-CPU code changes to implement all dummy reads/writes. Each memory access runs the PPU for 3 cycles (PPU is now controlled by the CPU)
-Optimizations + PGO (profile guided optimization) build support
This commit is contained in:
parent
b01e94d64d
commit
f3df2ecf17
13 changed files with 367 additions and 254 deletions
|
@ -59,9 +59,9 @@ void APU::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool APU::Exec(uint32_t executedCycles)
|
bool APU::Exec(uint32_t currentCPUCycle)
|
||||||
{
|
{
|
||||||
_currentClock += executedCycles;
|
_currentClock = currentCPUCycle;
|
||||||
|
|
||||||
if(_currentClock >= 29780) {
|
if(_currentClock >= 29780) {
|
||||||
_apu.end_frame(_currentClock);
|
_apu.end_frame(_currentClock);
|
||||||
|
|
|
@ -35,8 +35,13 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
uint32_t* _chrSlotPages;
|
uint32_t* _chrSlotPages;
|
||||||
|
|
||||||
uint32_t _chrShift = -1;
|
uint32_t _chrShift = -1;
|
||||||
|
uint32_t _chrSlotMaxIndex = -1;
|
||||||
uint32_t _prgShift = -1;
|
uint32_t _prgShift = -1;
|
||||||
|
uint32_t _prgSlotMaxIndex = -1;
|
||||||
|
|
||||||
|
uint32_t _chrPageMask = -1;
|
||||||
|
uint32_t _prgPageMask = -1;
|
||||||
|
|
||||||
virtual void InitMapper() = 0;
|
virtual void InitMapper() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -93,20 +98,12 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
|
|
||||||
uint32_t AddrToPRGSlot(uint16_t addr)
|
uint32_t AddrToPRGSlot(uint16_t addr)
|
||||||
{
|
{
|
||||||
if(_prgShift == -1) {
|
return (addr >> _prgShift) & _prgSlotMaxIndex;
|
||||||
_prgShift = this->log2(GetPRGSlotCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (addr >> (15 - _prgShift)) & (GetPRGSlotCount() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AddrToCHRSlot(uint16_t addr)
|
uint32_t AddrToCHRSlot(uint16_t addr)
|
||||||
{
|
{
|
||||||
if(_chrShift == -1) {
|
return (addr >> _chrShift) & _chrSlotMaxIndex;
|
||||||
_chrShift = this->log2(GetCHRSlotCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (addr >> (13 - _chrShift)) & (GetCHRSlotCount() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring GetBatteryFilename()
|
wstring GetBatteryFilename()
|
||||||
|
@ -184,6 +181,14 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
_prgSlotPages = new uint32_t[GetPRGSlotCount()];
|
_prgSlotPages = new uint32_t[GetPRGSlotCount()];
|
||||||
_chrSlotPages = new uint32_t[GetCHRSlotCount()];
|
_chrSlotPages = new uint32_t[GetCHRSlotCount()];
|
||||||
|
|
||||||
|
_prgShift = 15 - this->log2(GetPRGSlotCount());
|
||||||
|
_prgSlotMaxIndex = GetPRGSlotCount() - 1;
|
||||||
|
_chrShift = 13 - this->log2(GetCHRSlotCount());
|
||||||
|
_chrSlotMaxIndex = GetCHRSlotCount() - 1;
|
||||||
|
|
||||||
|
_chrPageMask = GetCHRPageSize() - 1;
|
||||||
|
_prgPageMask = GetPRGPageSize() - 1;
|
||||||
|
|
||||||
InitMapper();
|
InitMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +250,7 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
virtual uint8_t ReadRAM(uint16_t addr)
|
virtual uint8_t ReadRAM(uint16_t addr)
|
||||||
{
|
{
|
||||||
if(addr >= 0x8000) {
|
if(addr >= 0x8000) {
|
||||||
return _prgPages[AddrToPRGSlot(addr)][addr & (GetPRGPageSize() - 1)];
|
return _prgPages[AddrToPRGSlot(addr)][addr & _prgPageMask];
|
||||||
} else if(addr >= 0x6000) {
|
} else if(addr >= 0x6000) {
|
||||||
return _SRAM[addr & 0x1FFF];
|
return _SRAM[addr & 0x1FFF];
|
||||||
} else if(addr >= 0x4000) {
|
} else if(addr >= 0x4000) {
|
||||||
|
@ -268,7 +273,7 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
|
|
||||||
uint32_t ToAbsoluteAddress(uint16_t addr)
|
uint32_t ToAbsoluteAddress(uint16_t addr)
|
||||||
{
|
{
|
||||||
return GetPRGPageSize() * (_prgSlotPages[AddrToPRGSlot(addr)] % GetPRGPageCount()) + (addr & (GetPRGPageSize() - 1));
|
return GetPRGPageSize() * (_prgSlotPages[AddrToPRGSlot(addr)] % GetPRGPageCount()) + (addr & _prgPageMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t FromAbsoluteAddress(uint32_t addr)
|
int32_t FromAbsoluteAddress(uint32_t addr)
|
||||||
|
@ -319,13 +324,13 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
|
||||||
|
|
||||||
virtual uint8_t ReadVRAM(uint16_t addr)
|
virtual uint8_t ReadVRAM(uint16_t addr)
|
||||||
{
|
{
|
||||||
return _chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)];
|
return _chrPages[AddrToCHRSlot(addr)][addr & _chrPageMask];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void WriteVRAM(uint16_t addr, uint8_t value)
|
virtual void WriteVRAM(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
if(_hasCHRRAM) {
|
if(_hasCHRRAM) {
|
||||||
_chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)] = value;
|
_chrPages[AddrToCHRSlot(addr)][addr & _chrPageMask] = value;
|
||||||
} else {
|
} else {
|
||||||
//assert(false);
|
//assert(false);
|
||||||
}
|
}
|
||||||
|
|
115
Core/CPU.cpp
115
Core/CPU.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
|
#include "PPU.h"
|
||||||
|
|
||||||
CPU* CPU::Instance = nullptr;
|
CPU* CPU::Instance = nullptr;
|
||||||
|
|
||||||
|
@ -28,66 +29,27 @@ CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
|
||||||
};
|
};
|
||||||
|
|
||||||
AddrMode addrMode[] = {
|
AddrMode addrMode[] = {
|
||||||
Imm, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //0
|
||||||
Abs, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //1
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Abs, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //2
|
||||||
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //3
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //4
|
||||||
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //5
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //6
|
||||||
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //7
|
||||||
Rel, IndYW, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsYW, Imp, AbsY, AbsXW, AbsXW, AbsYW, AbsY,
|
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //8
|
||||||
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndYW, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsYW, Imp, AbsY, AbsXW, AbsXW, AbsYW, AbsY, //9
|
||||||
Rel, IndY, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsY, Imp, AbsY, AbsX, AbsX, AbsY, AbsY,
|
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //A
|
||||||
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsY, Imp, AbsY, AbsX, AbsX, AbsY, AbsY, //B
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //C
|
||||||
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //D
|
||||||
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
|
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //E
|
||||||
|
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //F
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t cycles[] {
|
|
||||||
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
|
||||||
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
|
||||||
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
|
||||||
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
|
|
||||||
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t cyclesPageCrossed[] {
|
|
||||||
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
|
||||||
3, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
|
||||||
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
|
||||||
3, 6, 2, 5, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
|
||||||
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
|
||||||
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
memcpy(_opTable, opTable, sizeof(opTable));
|
memcpy(_opTable, opTable, sizeof(opTable));
|
||||||
memcpy(_cycles, cycles, sizeof(cycles));
|
|
||||||
memcpy(_addrMode, addrMode, sizeof(addrMode));
|
memcpy(_addrMode, addrMode, sizeof(addrMode));
|
||||||
memcpy(_cyclesPageCrossed, cyclesPageCrossed, sizeof(cyclesPageCrossed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Reset(bool softReset)
|
void CPU::Reset(bool softReset)
|
||||||
|
@ -96,7 +58,6 @@ void CPU::Reset(bool softReset)
|
||||||
_state.IRQFlag = 0;
|
_state.IRQFlag = 0;
|
||||||
_cycleCount = 0;
|
_cycleCount = 0;
|
||||||
_relativeCycleCount = 0;
|
_relativeCycleCount = 0;
|
||||||
_cyclePenalty = 0;
|
|
||||||
|
|
||||||
_state.PC = MemoryReadWord(CPU::ResetVector);
|
_state.PC = MemoryReadWord(CPU::ResetVector);
|
||||||
if(softReset) {
|
if(softReset) {
|
||||||
|
@ -116,11 +77,8 @@ void CPU::Reset(bool softReset)
|
||||||
|
|
||||||
uint32_t CPU::Exec()
|
uint32_t CPU::Exec()
|
||||||
{
|
{
|
||||||
//static ofstream log("log.txt", ios::out | ios::binary);
|
|
||||||
uint32_t executedCycles = 0;
|
|
||||||
if(!_runNMI && !_runIRQ) {
|
if(!_runNMI && !_runIRQ) {
|
||||||
uint8_t opCode = GetOPCode();
|
uint8_t opCode = GetOPCode();
|
||||||
|
|
||||||
if(_state.NMIFlag) {
|
if(_state.NMIFlag) {
|
||||||
_runNMI = true;
|
_runNMI = true;
|
||||||
} else if(opCode != 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
|
} else if(opCode != 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
|
||||||
|
@ -128,14 +86,12 @@ uint32_t CPU::Exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
_instAddrMode = _addrMode[opCode];
|
_instAddrMode = _addrMode[opCode];
|
||||||
|
_operand = FetchOperand();
|
||||||
|
|
||||||
if(_opTable[opCode] != nullptr) {
|
if(_opTable[opCode] != nullptr) {
|
||||||
//std::cout << std::hex << (_state.PC - 1) << ": " << (short)opCode << std::endl;
|
|
||||||
(this->*_opTable[opCode])();
|
(this->*_opTable[opCode])();
|
||||||
executedCycles = (IsPageCrossed() ? _cyclesPageCrossed[opCode] : _cycles[opCode]);
|
|
||||||
} else {
|
} else {
|
||||||
GetOperandAddr();
|
|
||||||
std::cout << "Invalid opcode: " << std::hex << (short)opCode;
|
std::cout << "Invalid opcode: " << std::hex << (short)opCode;
|
||||||
//throw exception("Invalid opcode");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_runIRQ && opCode == 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
|
if(!_runIRQ && opCode == 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
|
||||||
|
@ -151,12 +107,9 @@ uint32_t CPU::Exec()
|
||||||
IRQ();
|
IRQ();
|
||||||
}
|
}
|
||||||
_runIRQ = false;
|
_runIRQ = false;
|
||||||
|
|
||||||
executedCycles = 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cycleCount += executedCycles;
|
return _cycleCount;
|
||||||
return executedCycles + GetCyclePenalty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::EndFrame()
|
void CPU::EndFrame()
|
||||||
|
@ -165,6 +118,28 @@ void CPU::EndFrame()
|
||||||
_cycleCount = 0;
|
_cycleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPU::RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue)
|
||||||
|
{
|
||||||
|
//"the DMA procedure takes 513 CPU cycles (+1 on odd CPU cycles)"
|
||||||
|
if((CPU::GetRelativeCycleCount() + Instance->_cycleCount) % 2 != 0) {
|
||||||
|
Instance->_cycleCount++;
|
||||||
|
}
|
||||||
|
Instance->_cycleCount++;
|
||||||
|
|
||||||
|
//DMA transfer starts at SpriteRamAddr and wraps around
|
||||||
|
for(int i = 0; i < 0x100; i++) {
|
||||||
|
//Read value
|
||||||
|
uint8_t readValue = Instance->_memoryManager->Read(offsetValue*0x100 + i);
|
||||||
|
Instance->_cycleCount++;
|
||||||
|
|
||||||
|
//Write to ram
|
||||||
|
spriteRAM[(spriteRamAddr+i) & 0xFF] = readValue;
|
||||||
|
PPU::ExecStatic();
|
||||||
|
Instance->_cycleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CPU::StreamState(bool saving)
|
void CPU::StreamState(bool saving)
|
||||||
{
|
{
|
||||||
Stream<uint16_t>(_state.PC);
|
Stream<uint16_t>(_state.PC);
|
||||||
|
|
154
Core/CPU.h
154
Core/CPU.h
|
@ -59,7 +59,7 @@ private:
|
||||||
|
|
||||||
int32_t _cycleCount;
|
int32_t _cycleCount;
|
||||||
int32_t _relativeCycleCount;
|
int32_t _relativeCycleCount;
|
||||||
uint32_t _cyclePenalty;
|
uint16_t _operand;
|
||||||
|
|
||||||
Func _opTable[256];
|
Func _opTable[256];
|
||||||
uint8_t _cycles[256];
|
uint8_t _cycles[256];
|
||||||
|
@ -77,10 +77,17 @@ private:
|
||||||
uint8_t GetOPCode()
|
uint8_t GetOPCode()
|
||||||
{
|
{
|
||||||
uint8_t value = _memoryManager->Read(_state.PC, true);
|
uint8_t value = _memoryManager->Read(_state.PC, true);
|
||||||
|
_cycleCount++;
|
||||||
_state.PC++;
|
_state.PC++;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DummyRead()
|
||||||
|
{
|
||||||
|
_memoryManager->Read(_state.PC, false);
|
||||||
|
_cycleCount++;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ReadByte()
|
uint8_t ReadByte()
|
||||||
{
|
{
|
||||||
return MemoryRead(_state.PC++);
|
return MemoryRead(_state.PC++);
|
||||||
|
@ -132,14 +139,19 @@ private:
|
||||||
void MemoryWrite(uint16_t addr, uint8_t value)
|
void MemoryWrite(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
_memoryManager->Write(addr, value);
|
_memoryManager->Write(addr, value);
|
||||||
|
_cycleCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MemoryRead(uint16_t addr) {
|
uint8_t MemoryRead(uint16_t addr) {
|
||||||
return _memoryManager->Read(addr);
|
uint8_t value = _memoryManager->Read(addr);
|
||||||
|
_cycleCount++;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MemoryReadWord(uint16_t addr) {
|
uint16_t MemoryReadWord(uint16_t addr) {
|
||||||
return _memoryManager->ReadWord(addr);
|
uint16_t value = _memoryManager->ReadWord(addr);
|
||||||
|
_cycleCount+=2;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRegister(uint8_t ®, uint8_t value) {
|
void SetRegister(uint8_t ®, uint8_t value) {
|
||||||
|
@ -183,40 +195,56 @@ private:
|
||||||
uint16_t PC() { return _state.PC; }
|
uint16_t PC() { return _state.PC; }
|
||||||
void SetPC(uint16_t value) { _state.PC = value; }
|
void SetPC(uint16_t value) { _state.PC = value; }
|
||||||
|
|
||||||
uint16_t GetOperandAddr()
|
uint16_t FetchOperand()
|
||||||
{
|
{
|
||||||
switch(_instAddrMode) {
|
switch(_instAddrMode) {
|
||||||
|
case AddrMode::Acc:
|
||||||
|
case AddrMode::Imp: DummyRead(); return 0;
|
||||||
|
case AddrMode::Imm:
|
||||||
|
case AddrMode::Rel: return GetImmediate();
|
||||||
|
case AddrMode::Zero: return GetZeroAddr();
|
||||||
|
case AddrMode::ZeroX: return GetZeroXAddr();
|
||||||
|
case AddrMode::ZeroY: return GetZeroYAddr();
|
||||||
|
case AddrMode::Ind: return GetIndAddr();
|
||||||
|
case AddrMode::IndX: return GetIndXAddr();
|
||||||
|
case AddrMode::IndY: return GetIndYAddr(false);
|
||||||
|
case AddrMode::IndYW: return GetIndYAddr(true);
|
||||||
case AddrMode::Abs: return GetAbsAddr();
|
case AddrMode::Abs: return GetAbsAddr();
|
||||||
case AddrMode::AbsX: return GetAbsXAddr(false);
|
case AddrMode::AbsX: return GetAbsXAddr(false);
|
||||||
case AddrMode::AbsXW: return GetAbsXAddr(true);
|
case AddrMode::AbsXW: return GetAbsXAddr(true);
|
||||||
case AddrMode::AbsY: return GetAbsYAddr(false);
|
case AddrMode::AbsY: return GetAbsYAddr(false);
|
||||||
case AddrMode::AbsYW: return GetAbsYAddr(true);
|
case AddrMode::AbsYW: return GetAbsYAddr(true);
|
||||||
case AddrMode::Imm: return GetImmediate();
|
|
||||||
case AddrMode::IndX: return GetIndXAddr();
|
|
||||||
case AddrMode::IndY: return GetIndYAddr(false);
|
|
||||||
case AddrMode::IndYW: return GetIndYAddr(true);
|
|
||||||
case AddrMode::Zero: return GetZeroAddr();
|
|
||||||
case AddrMode::ZeroX: return GetZeroXAddr();
|
|
||||||
case AddrMode::ZeroY: return GetZeroYAddr();
|
|
||||||
}
|
}
|
||||||
return 0;
|
throw new exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GetOperand()
|
uint16_t GetOperand()
|
||||||
{
|
{
|
||||||
uint16_t addr = GetOperandAddr();
|
return _operand;
|
||||||
|
}
|
||||||
|
|
||||||
if(_instAddrMode != AddrMode::Imm) {
|
uint8_t GetOperandValue()
|
||||||
return MemoryRead(addr);
|
{
|
||||||
|
if(_instAddrMode >= AddrMode::Zero) {
|
||||||
|
return MemoryRead(GetOperand());
|
||||||
} else {
|
} else {
|
||||||
return (uint8_t)addr;
|
return (uint8_t)GetOperand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t GetIndAddr() { return ReadWord(); }
|
||||||
uint8_t GetImmediate() { return ReadByte(); }
|
uint8_t GetImmediate() { return ReadByte(); }
|
||||||
uint8_t GetZeroAddr() { return ReadByte(); }
|
uint8_t GetZeroAddr() { return ReadByte(); }
|
||||||
uint8_t GetZeroXAddr() { return ReadByte() + X(); }
|
uint8_t GetZeroXAddr() {
|
||||||
uint8_t GetZeroYAddr() { return ReadByte() + Y(); }
|
uint8_t value = ReadByte();
|
||||||
|
MemoryRead(value); //Dummy read
|
||||||
|
return value + X();
|
||||||
|
}
|
||||||
|
uint8_t GetZeroYAddr() {
|
||||||
|
uint8_t value = ReadByte();
|
||||||
|
MemoryRead(value); //Dummy read
|
||||||
|
return value + Y();
|
||||||
|
}
|
||||||
uint16_t GetAbsAddr() { return ReadWord(); }
|
uint16_t GetAbsAddr() { return ReadWord(); }
|
||||||
|
|
||||||
uint16_t GetAbsXAddr(bool dummyRead = true) {
|
uint16_t GetAbsXAddr(bool dummyRead = true) {
|
||||||
|
@ -243,7 +271,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GetInd() {
|
uint16_t GetInd() {
|
||||||
uint16_t addr = ReadWord();
|
uint16_t addr = GetOperand();
|
||||||
if((addr & 0xFF) == 0xFF) {
|
if((addr & 0xFF) == 0xFF) {
|
||||||
auto lo = MemoryRead(addr);
|
auto lo = MemoryRead(addr);
|
||||||
auto hi = MemoryRead(addr - 0xFF);
|
auto hi = MemoryRead(addr - 0xFF);
|
||||||
|
@ -288,9 +316,9 @@ private:
|
||||||
return addr + Y();
|
return addr + Y();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AND() { SetA(A() & GetOperand()); }
|
void AND() { SetA(A() & GetOperandValue()); }
|
||||||
void EOR() { SetA(A() ^ GetOperand()); }
|
void EOR() { SetA(A() ^ GetOperandValue()); }
|
||||||
void ORA() { SetA(A() | GetOperand()); }
|
void ORA() { SetA(A() | GetOperandValue()); }
|
||||||
|
|
||||||
void ADD(uint8_t value)
|
void ADD(uint8_t value)
|
||||||
{
|
{
|
||||||
|
@ -307,8 +335,8 @@ private:
|
||||||
SetA((uint8_t)result);
|
SetA((uint8_t)result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADC() { ADD(GetOperand()); }
|
void ADC() { ADD(GetOperandValue()); }
|
||||||
void SBC() { ADD(GetOperand() ^ 0xFF); }
|
void SBC() { ADD(GetOperandValue() ^ 0xFF); }
|
||||||
|
|
||||||
void CMP(uint8_t reg, uint8_t value)
|
void CMP(uint8_t reg, uint8_t value)
|
||||||
{
|
{
|
||||||
|
@ -327,13 +355,13 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPA() { CMP(A(), GetOperand()); }
|
void CPA() { CMP(A(), GetOperandValue()); }
|
||||||
void CPX() { CMP(X(), GetOperand()); }
|
void CPX() { CMP(X(), GetOperandValue()); }
|
||||||
void CPY() { CMP(Y(), GetOperand()); }
|
void CPY() { CMP(Y(), GetOperandValue()); }
|
||||||
|
|
||||||
void INC()
|
void INC()
|
||||||
{
|
{
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
ClearFlags(PSFlags::Negative | PSFlags::Zero);
|
ClearFlags(PSFlags::Negative | PSFlags::Zero);
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
|
|
||||||
|
@ -346,7 +374,7 @@ private:
|
||||||
|
|
||||||
void DEC()
|
void DEC()
|
||||||
{
|
{
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
ClearFlags(PSFlags::Negative | PSFlags::Zero);
|
ClearFlags(PSFlags::Negative | PSFlags::Zero);
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
MemoryWrite(addr, value); //Dummy write
|
MemoryWrite(addr, value); //Dummy write
|
||||||
|
@ -405,28 +433,28 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASLAddr() {
|
void ASLAddr() {
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
MemoryWrite(addr, value); //Dummy write
|
MemoryWrite(addr, value); //Dummy write
|
||||||
MemoryWrite(addr, ASL(value));
|
MemoryWrite(addr, ASL(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LSRAddr() {
|
void LSRAddr() {
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
MemoryWrite(addr, value); //Dummy write
|
MemoryWrite(addr, value); //Dummy write
|
||||||
MemoryWrite(addr, LSR(value));
|
MemoryWrite(addr, LSR(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ROLAddr() {
|
void ROLAddr() {
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
MemoryWrite(addr, value); //Dummy write
|
MemoryWrite(addr, value); //Dummy write
|
||||||
MemoryWrite(addr, ROL(value));
|
MemoryWrite(addr, ROL(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RORAddr() {
|
void RORAddr() {
|
||||||
uint16_t addr = GetOperandAddr();
|
uint16_t addr = GetOperand();
|
||||||
uint8_t value = MemoryRead(addr);
|
uint8_t value = MemoryRead(addr);
|
||||||
MemoryWrite(addr, value); //Dummy write
|
MemoryWrite(addr, value); //Dummy write
|
||||||
MemoryWrite(addr, ROR(value));
|
MemoryWrite(addr, ROR(value));
|
||||||
|
@ -437,17 +465,19 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void BranchRelative(bool branch) {
|
void BranchRelative(bool branch) {
|
||||||
int8_t offset = GetImmediate();
|
int8_t offset = (int8_t)GetOperand();
|
||||||
if(branch) {
|
if(branch) {
|
||||||
CheckPageCrossed(PC(), offset);
|
if(CheckPageCrossed(PC(), offset)) {
|
||||||
IncCycleCount(1);
|
DummyRead();
|
||||||
|
}
|
||||||
|
DummyRead();
|
||||||
|
|
||||||
SetPC(PC() + offset);
|
SetPC(PC() + offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BIT() {
|
void BIT() {
|
||||||
uint8_t value = GetOperand();
|
uint8_t value = GetOperandValue();
|
||||||
ClearFlags(PSFlags::Zero | PSFlags::Overflow | PSFlags::Negative);
|
ClearFlags(PSFlags::Zero | PSFlags::Overflow | PSFlags::Negative);
|
||||||
if((A() & value) == 0) {
|
if((A() & value) == 0) {
|
||||||
SetFlags(PSFlags::Zero);
|
SetFlags(PSFlags::Zero);
|
||||||
|
@ -466,20 +496,14 @@ private:
|
||||||
return pageCrossed;
|
return pageCrossed;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetCyclePenalty() {
|
|
||||||
uint32_t cyclePenalty = _cyclePenalty;
|
|
||||||
_cyclePenalty = 0;
|
|
||||||
return cyclePenalty;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma region OP Codes
|
#pragma region OP Codes
|
||||||
void LDA() { SetA(GetOperand()); }
|
void LDA() { SetA(GetOperandValue()); }
|
||||||
void LDX() { SetX(GetOperand()); }
|
void LDX() { SetX(GetOperandValue()); }
|
||||||
void LDY() { SetY(GetOperand()); }
|
void LDY() { SetY(GetOperandValue()); }
|
||||||
|
|
||||||
void STA() { MemoryWrite(GetOperandAddr(), A()); }
|
void STA() { MemoryWrite(GetOperand(), A()); }
|
||||||
void STX() { MemoryWrite(GetOperandAddr(), X()); }
|
void STX() { MemoryWrite(GetOperand(), X()); }
|
||||||
void STY() { MemoryWrite(GetOperandAddr(), Y()); }
|
void STY() { MemoryWrite(GetOperand(), Y()); }
|
||||||
|
|
||||||
void TAX() { SetX(A()); }
|
void TAX() { SetX(A()); }
|
||||||
void TAY() { SetY(A()); }
|
void TAY() { SetY(A()); }
|
||||||
|
@ -493,8 +517,14 @@ private:
|
||||||
uint8_t flags = PS() | PSFlags::Break;
|
uint8_t flags = PS() | PSFlags::Break;
|
||||||
Push((uint8_t)flags);
|
Push((uint8_t)flags);
|
||||||
}
|
}
|
||||||
void PLA() { SetA(Pop()); }
|
void PLA() {
|
||||||
void PLP() { SetPS(Pop()); }
|
DummyRead();
|
||||||
|
SetA(Pop());
|
||||||
|
}
|
||||||
|
void PLP() {
|
||||||
|
DummyRead();
|
||||||
|
SetPS(Pop());
|
||||||
|
}
|
||||||
|
|
||||||
void INX() { SetX(X() + 1); }
|
void INX() { SetX(X() + 1); }
|
||||||
void INY() { SetY(Y() + 1); }
|
void INY() { SetY(Y() + 1); }
|
||||||
|
@ -515,16 +545,19 @@ private:
|
||||||
void ROR_Memory() { RORAddr(); }
|
void ROR_Memory() { RORAddr(); }
|
||||||
|
|
||||||
void JMP_Abs() {
|
void JMP_Abs() {
|
||||||
JMP(GetAbsAddr());
|
JMP(GetOperand());
|
||||||
}
|
}
|
||||||
void JMP_Ind() { JMP(GetInd()); }
|
void JMP_Ind() { JMP(GetInd()); }
|
||||||
void JSR() {
|
void JSR() {
|
||||||
uint16_t addr = GetAbsAddr();
|
uint16_t addr = GetOperand();
|
||||||
|
DummyRead();
|
||||||
Push((uint16_t)(PC() - 1));
|
Push((uint16_t)(PC() - 1));
|
||||||
JMP(addr);
|
JMP(addr);
|
||||||
}
|
}
|
||||||
void RTS() {
|
void RTS() {
|
||||||
uint16_t addr = PopWord();
|
uint16_t addr = PopWord();
|
||||||
|
DummyRead();
|
||||||
|
DummyRead();
|
||||||
SetPC(addr + 1);
|
SetPC(addr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +620,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMI() {
|
void NMI() {
|
||||||
|
DummyRead(); //fetch opcode (and discard it - $00 (BRK) is forced into the opcode register instead)
|
||||||
|
DummyRead(); //read next instruction byte (actually the same as above, since PC increment is suppressed. Also discarded.)
|
||||||
Push((uint16_t)(PC()));
|
Push((uint16_t)(PC()));
|
||||||
Push((uint8_t)PS());
|
Push((uint8_t)PS());
|
||||||
SetFlags(PSFlags::Interrupt);
|
SetFlags(PSFlags::Interrupt);
|
||||||
|
@ -594,6 +629,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRQ() {
|
void IRQ() {
|
||||||
|
DummyRead(); //fetch opcode (and discard it - $00 (BRK) is forced into the opcode register instead)
|
||||||
|
DummyRead(); //read next instruction byte (actually the same as above, since PC increment is suppressed. Also discarded.)
|
||||||
Push((uint16_t)(PC()));
|
Push((uint16_t)(PC()));
|
||||||
|
|
||||||
if(_state.NMIFlag) {
|
if(_state.NMIFlag) {
|
||||||
|
@ -609,14 +646,14 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTI() {
|
void RTI() {
|
||||||
|
DummyRead();
|
||||||
SetPS(Pop());
|
SetPS(Pop());
|
||||||
SetPC(PopWord());
|
SetPC(PopWord());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NOP() {
|
void NOP() {
|
||||||
GetOperand();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -628,14 +665,11 @@ public:
|
||||||
CPU(MemoryManager *memoryManager);
|
CPU(MemoryManager *memoryManager);
|
||||||
static int32_t GetCycleCount() { return CPU::Instance->_cycleCount; }
|
static int32_t GetCycleCount() { return CPU::Instance->_cycleCount; }
|
||||||
static int32_t GetRelativeCycleCount() { return CPU::Instance->_relativeCycleCount + CPU::Instance->_cycleCount; }
|
static int32_t GetRelativeCycleCount() { return CPU::Instance->_relativeCycleCount + CPU::Instance->_cycleCount; }
|
||||||
static void IncCycleCount(uint32_t cycles) {
|
|
||||||
CPU::Instance->_cyclePenalty += cycles;
|
|
||||||
CPU::Instance->_cycleCount += cycles;
|
|
||||||
}
|
|
||||||
static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; }
|
static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; }
|
||||||
static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; }
|
static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; }
|
||||||
static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; }
|
static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; }
|
||||||
static void ClearIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag &= ~(int)source; }
|
static void ClearIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag &= ~(int)source; }
|
||||||
|
static void RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue);
|
||||||
|
|
||||||
void Reset(bool softReset);
|
void Reset(bool softReset);
|
||||||
uint32_t Exec();
|
uint32_t Exec();
|
||||||
|
|
|
@ -159,13 +159,10 @@ void Console::Run()
|
||||||
Console::RunningLock.Acquire();
|
Console::RunningLock.Acquire();
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
uint32_t executedCycles = _cpu->Exec();
|
bool frameDone = _apu->Exec(_cpu->Exec());
|
||||||
_ppu->Exec();
|
|
||||||
bool frameDone = _apu->Exec(executedCycles);
|
|
||||||
|
|
||||||
if(frameDone) {
|
if(frameDone) {
|
||||||
_cpu->EndFrame();
|
_cpu->EndFrame();
|
||||||
_ppu->EndFrame();
|
|
||||||
|
|
||||||
if(CheckFlag(EmulationFlags::LimitFPS) && frameDone) {
|
if(CheckFlag(EmulationFlags::LimitFPS) && frameDone) {
|
||||||
elapsedTime = clockTimer.GetElapsedMS();
|
elapsedTime = clockTimer.GetElapsedMS();
|
||||||
|
@ -273,12 +270,8 @@ bool Console::RunTest(uint8_t *expectedResult)
|
||||||
Console::RunningLock.Acquire();
|
Console::RunningLock.Acquire();
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
uint32_t executedCycles = _cpu->Exec();
|
if(_apu->Exec(_cpu->Exec())) {
|
||||||
_ppu->Exec();
|
|
||||||
|
|
||||||
if(_apu->Exec(executedCycles)) {
|
|
||||||
_cpu->EndFrame();
|
_cpu->EndFrame();
|
||||||
_ppu->EndFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(timer.GetElapsedMS() > 100) {
|
if(timer.GetElapsedMS() > 100) {
|
||||||
|
|
|
@ -59,18 +59,12 @@ void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
||||||
|
|
||||||
uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr)
|
uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr)
|
||||||
{
|
{
|
||||||
if(_vramReadHandlers[addr]) {
|
return _mapper->ReadVRAM(addr);
|
||||||
return _vramReadHandlers[addr]->ReadVRAM(addr);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value)
|
void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
if(_vramWriteHandlers[addr]) {
|
return _mapper->WriteVRAM(addr, value);
|
||||||
_vramWriteHandlers[addr]->WriteVRAM(addr, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses)
|
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses)
|
||||||
|
@ -115,7 +109,7 @@ uint8_t MemoryManager::Read(uint16_t addr, bool forExecution)
|
||||||
Debugger::CheckBreakpoint(forExecution ? BreakpointType::Execute : BreakpointType::Read, addr);
|
Debugger::CheckBreakpoint(forExecution ? BreakpointType::Execute : BreakpointType::Read, addr);
|
||||||
|
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
PPU::ExecStatic(3);
|
PPU::ExecStatic();
|
||||||
if(addr <= 0x1FFF) {
|
if(addr <= 0x1FFF) {
|
||||||
value = _internalRAM[addr & 0x07FF];
|
value = _internalRAM[addr & 0x07FF];
|
||||||
} else {
|
} else {
|
||||||
|
@ -128,7 +122,7 @@ void MemoryManager::Write(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
Debugger::CheckBreakpoint(BreakpointType::Write, addr);
|
Debugger::CheckBreakpoint(BreakpointType::Write, addr);
|
||||||
|
|
||||||
PPU::ExecStatic(3);
|
PPU::ExecStatic();
|
||||||
if(addr <= 0x1FFF) {
|
if(addr <= 0x1FFF) {
|
||||||
_internalRAM[addr & 0x07FF] = value;
|
_internalRAM[addr & 0x07FF] = value;
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,24 +137,20 @@ uint16_t MemoryManager::ReadWord(uint16_t addr)
|
||||||
return lo | hi << 8;
|
return lo | hi << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::ProcessVRAMAccess(uint16_t &addr)
|
|
||||||
{
|
|
||||||
addr &= 0x3FFF;
|
|
||||||
if(addr >= 0x3000) {
|
|
||||||
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
|
|
||||||
//Required for proper MMC3 IRQ timing in Burai Fighter
|
|
||||||
addr -= 0x1000;
|
|
||||||
}
|
|
||||||
_mapper->NotifyVRAMAddressChange(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t MemoryManager::ReadVRAM(uint16_t addr)
|
uint8_t MemoryManager::ReadVRAM(uint16_t addr)
|
||||||
{
|
{
|
||||||
ProcessVRAMAccess(addr);
|
addr &= 0x3FFF;
|
||||||
|
|
||||||
if(addr <= 0x1FFF) {
|
if(addr <= 0x1FFF) {
|
||||||
return ReadMappedVRAM(addr & 0x1FFF);
|
_mapper->NotifyVRAMAddressChange(addr);
|
||||||
|
return ReadMappedVRAM(addr);
|
||||||
} else {
|
} else {
|
||||||
|
if(addr >= 0x3000) {
|
||||||
|
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
|
||||||
|
//Required for proper MMC3 IRQ timing in Burai Fighter
|
||||||
|
addr -= 0x1000;
|
||||||
|
}
|
||||||
|
_mapper->NotifyVRAMAddressChange(addr);
|
||||||
switch(_mapper->GetMirroringType()) {
|
switch(_mapper->GetMirroringType()) {
|
||||||
case MirroringType::Vertical:
|
case MirroringType::Vertical:
|
||||||
return _nametableRAM[(addr&0x400)>>10][addr & 0x3FF];
|
return _nametableRAM[(addr&0x400)>>10][addr & 0x3FF];
|
||||||
|
@ -178,17 +168,23 @@ uint8_t MemoryManager::ReadVRAM(uint16_t addr)
|
||||||
case MirroringType::ScreenBOnly:
|
case MirroringType::ScreenBOnly:
|
||||||
return _nametableRAM[1][addr & 0x3FF];
|
return _nametableRAM[1][addr & 0x3FF];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
ProcessVRAMAccess(addr);
|
addr &= 0x3FFF;
|
||||||
|
|
||||||
if(addr <= 0x1FFF) {
|
if(addr <= 0x1FFF) {
|
||||||
|
_mapper->NotifyVRAMAddressChange(addr);
|
||||||
WriteMappedVRAM(addr, value);
|
WriteMappedVRAM(addr, value);
|
||||||
} else {
|
} else {
|
||||||
|
if(addr >= 0x3000) {
|
||||||
|
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
|
||||||
|
//Required for proper MMC3 IRQ timing in Burai Fighter
|
||||||
|
addr -= 0x1000;
|
||||||
|
}
|
||||||
|
_mapper->NotifyVRAMAddressChange(addr);
|
||||||
switch(_mapper->GetMirroringType()) {
|
switch(_mapper->GetMirroringType()) {
|
||||||
case MirroringType::Vertical:
|
case MirroringType::Vertical:
|
||||||
_nametableRAM[(addr&0x400)>>10][addr & 0x3FF] = value;
|
_nametableRAM[(addr&0x400)>>10][addr & 0x3FF] = value;
|
||||||
|
|
|
@ -34,8 +34,6 @@ class MemoryManager: public Snapshotable
|
||||||
uint8_t ReadMappedVRAM(uint16_t addr);
|
uint8_t ReadMappedVRAM(uint16_t addr);
|
||||||
void WriteMappedVRAM(uint16_t addr, uint8_t value);
|
void WriteMappedVRAM(uint16_t addr, uint8_t value);
|
||||||
|
|
||||||
void ProcessVRAMAccess(uint16_t &addr);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void StreamState(bool saving);
|
void StreamState(bool saving);
|
||||||
|
|
||||||
|
|
102
Core/PPU.cpp
102
Core/PPU.cpp
|
@ -46,7 +46,6 @@ void PPU::Reset()
|
||||||
_scanline = 0;
|
_scanline = 0;
|
||||||
_cycle = 0;
|
_cycle = 0;
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
_cycleCount = 0;
|
|
||||||
_memoryReadBuffer = 0;
|
_memoryReadBuffer = 0;
|
||||||
|
|
||||||
memset(_spriteRAM, 0xFF, 0x100);
|
memset(_spriteRAM, 0xFF, 0x100);
|
||||||
|
@ -154,13 +153,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
UpdateVideoRamAddr();
|
UpdateVideoRamAddr();
|
||||||
break;
|
break;
|
||||||
case PPURegisters::SpriteDMA:
|
case PPURegisters::SpriteDMA:
|
||||||
//DMA transfer starts at SpriteRamAddr and wraps around
|
CPU::RunDMATransfer(_spriteRAM, _state.SpriteRamAddr, value);
|
||||||
for(int i = 0; i < 0x100; i++) {
|
|
||||||
_spriteRAM[(_state.SpriteRamAddr+i)&0xFF] = _memoryManager->Read(value*0x100 + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
//"the DMA procedure takes 513 CPU cycles (+1 on odd CPU cycles)"
|
|
||||||
CPU::IncCycleCount((CPU::GetCycleCount() % 2 == 0) ? 513 : 514);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,21 +392,20 @@ void PPU::DrawPixel()
|
||||||
//This is called 3.7 million times per second - needs to be as fast as possible.
|
//This is called 3.7 million times per second - needs to be as fast as possible.
|
||||||
uint8_t offset = _state.XScroll;
|
uint8_t offset = _state.XScroll;
|
||||||
|
|
||||||
bool useBackground = true;
|
|
||||||
uint32_t backgroundColor = 0;
|
uint32_t backgroundColor = 0;
|
||||||
uint32_t spriteColor = 0;
|
uint32_t &pixel = (((uint32_t*)_outputBuffer)[(_scanline << 8) + _cycle - 1]);
|
||||||
|
|
||||||
if((_cycle > 8 || _flags.BackgroundMask) && _flags.BackgroundEnabled) {
|
if((_cycle > 8 || _flags.BackgroundMask) && _flags.BackgroundEnabled) {
|
||||||
//BackgroundMask = false: Hide background in leftmost 8 pixels of screen
|
//BackgroundMask = false: Hide background in leftmost 8 pixels of screen
|
||||||
backgroundColor = (((_state.LowBitShift << offset) & 0x8000) >> 15) | (((_state.HighBitShift << offset) & 0x8000) >> 14);
|
backgroundColor = (((_state.LowBitShift << offset) & 0x8000) >> 15) | (((_state.HighBitShift << offset) & 0x8000) >> 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t i;
|
|
||||||
if((_cycle > 8 || _flags.SpriteMask) && _flags.SpritesEnabled) {
|
if((_cycle > 8 || _flags.SpriteMask) && _flags.SpritesEnabled) {
|
||||||
//SpriteMask = true: Hide sprites in leftmost 8 pixels of screen
|
//SpriteMask = true: Hide sprites in leftmost 8 pixels of screen
|
||||||
for(i = 0; i < _spriteCount; i++) {
|
for(uint8_t i = 0; i < _spriteCount; i++) {
|
||||||
int32_t shift = -((int32_t)_spriteX[i] - (int32_t)_cycle + 1);
|
int32_t shift = -((int32_t)_spriteX[i] - (int32_t)_cycle + 1);
|
||||||
if(shift >= 0 && shift < 8) {
|
if(shift >= 0 && shift < 8) {
|
||||||
|
uint32_t spriteColor;
|
||||||
if(_spriteTiles[i].HorizontalMirror) {
|
if(_spriteTiles[i].HorizontalMirror) {
|
||||||
spriteColor = ((_spriteTiles[i].LowByte >> shift) & 0x01) | ((_spriteTiles[i].HighByte >> shift) & 0x01) << 1;
|
spriteColor = ((_spriteTiles[i].LowByte >> shift) & 0x01) | ((_spriteTiles[i].HighByte >> shift) & 0x01) << 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -424,7 +416,7 @@ void PPU::DrawPixel()
|
||||||
//First sprite without a 00 color, use it.
|
//First sprite without a 00 color, use it.
|
||||||
if(backgroundColor == 0 || !_spriteTiles[i].BackgroundPriority) {
|
if(backgroundColor == 0 || !_spriteTiles[i].BackgroundPriority) {
|
||||||
//Check sprite priority
|
//Check sprite priority
|
||||||
useBackground = false;
|
pixel = PPU_PALETTE_RGB[GetSpritePaletteEntry(_spriteTiles[i].PaletteOffset, spriteColor)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i == 0 && backgroundColor != 0 && _sprite0Visible && _cycle != 256 && _flags.BackgroundEnabled) {
|
if(i == 0 && backgroundColor != 0 && _sprite0Visible && _cycle != 256 && _flags.BackgroundEnabled) {
|
||||||
|
@ -434,22 +426,12 @@ void PPU::DrawPixel()
|
||||||
//"Should always miss when Y >= 239"
|
//"Should always miss when Y >= 239"
|
||||||
_statusFlags.Sprite0Hit = true;
|
_statusFlags.Sprite0Hit = true;
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pixel = PPU_PALETTE_RGB[GetBGPaletteEntry(offset + ((_cycle - 1) % 8) < 8 ? _previousTile.PaletteOffset : _currentTile.PaletteOffset, backgroundColor)];
|
||||||
uint32_t bufferPosition = _scanline * 256 + (_cycle - 1);
|
|
||||||
if(useBackground) {
|
|
||||||
// If we're grabbing the pixel from the high part of the shift register, use the previous tile's palette, not the current one
|
|
||||||
((uint32_t*)_outputBuffer)[bufferPosition] = PPU_PALETTE_RGB[GetBGPaletteEntry(offset + ((_cycle - 1) % 8) < 8 ? _previousTile.PaletteOffset : _currentTile.PaletteOffset, backgroundColor)];
|
|
||||||
} else {
|
|
||||||
((uint32_t*)_outputBuffer)[bufferPosition] = PPU_PALETTE_RGB[GetSpritePaletteEntry(_spriteTiles[i].PaletteOffset, spriteColor)];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Shift the tile registers to prepare for the next cycle
|
|
||||||
ShiftTileRegisters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::ProcessPreVBlankScanline()
|
void PPU::ProcessPreVBlankScanline()
|
||||||
|
@ -457,13 +439,13 @@ void PPU::ProcessPreVBlankScanline()
|
||||||
//For pre-render scanline & all visible scanlines
|
//For pre-render scanline & all visible scanlines
|
||||||
if(IsRenderingEnabled()) {
|
if(IsRenderingEnabled()) {
|
||||||
//Update video ram address according to scrolling logic
|
//Update video ram address according to scrolling logic
|
||||||
if(_cycle == 256) {
|
if((_cycle > 0 && _cycle < 256 && _cycle % 8 == 0) || _cycle == 328 || _cycle == 336) {
|
||||||
|
IncHorizontalScrolling();
|
||||||
|
} else if(_cycle == 256) {
|
||||||
IncVerticalScrolling();
|
IncVerticalScrolling();
|
||||||
} else if(_cycle == 257) {
|
} else if(_cycle == 257) {
|
||||||
//copy horizontal scrolling value from t
|
//copy horizontal scrolling value from t
|
||||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
|
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
|
||||||
} else if((_cycle % 8 == 0 && _cycle > 0 && _cycle < 256) || _cycle == 328 || _cycle == 336) {
|
|
||||||
IncHorizontalScrolling();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +459,7 @@ void PPU::ProcessPrerenderScanline()
|
||||||
{
|
{
|
||||||
ProcessPreVBlankScanline();
|
ProcessPreVBlankScanline();
|
||||||
|
|
||||||
if(_cycle == 0) {
|
if(_cycle == 1) {
|
||||||
_statusFlags.SpriteOverflow = false;
|
_statusFlags.SpriteOverflow = false;
|
||||||
_statusFlags.Sprite0Hit = false;
|
_statusFlags.Sprite0Hit = false;
|
||||||
_statusFlags.VerticalBlank = false;
|
_statusFlags.VerticalBlank = false;
|
||||||
|
@ -520,6 +502,7 @@ void PPU::ProcessVisibleScanline()
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawPixel();
|
DrawPixel();
|
||||||
|
ShiftTileRegisters();
|
||||||
|
|
||||||
if(IsRenderingEnabled()) {
|
if(IsRenderingEnabled()) {
|
||||||
CopyOAMData();
|
CopyOAMData();
|
||||||
|
@ -527,9 +510,12 @@ void PPU::ProcessVisibleScanline()
|
||||||
|
|
||||||
if(_cycle == 256 && _scanline == 239) {
|
if(_cycle == 256 && _scanline == 239) {
|
||||||
//Send frame to GUI once the last pixel has been output
|
//Send frame to GUI once the last pixel has been output
|
||||||
PPU::VideoDevice->UpdateFrame(_outputBuffer);
|
if(PPU::VideoDevice) {
|
||||||
|
PPU::VideoDevice->UpdateFrame(_outputBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if((_cycle - 261) % 8 == 0 && _cycle <= 320) {
|
} else if((_cycle - 261) % 8 == 0 && _cycle <= 320) {
|
||||||
|
//Cycle 261, 269, etc.
|
||||||
uint32_t spriteIndex = (_cycle - 261) / 8;
|
uint32_t spriteIndex = (_cycle - 261) / 8;
|
||||||
LoadSpriteTileInfo(spriteIndex);
|
LoadSpriteTileInfo(spriteIndex);
|
||||||
} else if(_cycle == 321 || _cycle == 329) {
|
} else if(_cycle == 321 || _cycle == 329) {
|
||||||
|
@ -615,7 +601,7 @@ void PPU::CopyOAMData()
|
||||||
|
|
||||||
void PPU::BeginVBlank()
|
void PPU::BeginVBlank()
|
||||||
{
|
{
|
||||||
if(_cycle == 0) {
|
if(_cycle == 1) {
|
||||||
if(!_doNotSetVBFlag) {
|
if(!_doNotSetVBFlag) {
|
||||||
_statusFlags.VerticalBlank = true;
|
_statusFlags.VerticalBlank = true;
|
||||||
if(_flags.VBlank) {
|
if(_flags.VBlank) {
|
||||||
|
@ -633,39 +619,34 @@ void PPU::EndVBlank()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Exec(uint32_t extraCycles)
|
void PPU::Exec()
|
||||||
{
|
{
|
||||||
int32_t gap = CPU::GetCycleCount() * 3 - _cycleCount;
|
if(_scanline != -1 && _scanline < 240) {
|
||||||
if(gap < 0) {
|
ProcessVisibleScanline();
|
||||||
gap = 0;
|
} else if(_scanline == -1) {
|
||||||
|
ProcessPrerenderScanline();
|
||||||
|
} else if(_scanline == 241) {
|
||||||
|
BeginVBlank();
|
||||||
|
} else if(_scanline == 260) {
|
||||||
|
EndVBlank();
|
||||||
}
|
}
|
||||||
gap += extraCycles;
|
|
||||||
|
|
||||||
_cycleCount += gap;
|
if(_cycle == 340) {
|
||||||
while(gap > 0) {
|
_cycle = -1;
|
||||||
if(_scanline == -1) {
|
_scanline++;
|
||||||
ProcessPrerenderScanline();
|
|
||||||
} else if(_scanline < 240) {
|
if(_scanline == 261) {
|
||||||
ProcessVisibleScanline();
|
_scanline = -1;
|
||||||
} else if(_scanline == 241) {
|
|
||||||
BeginVBlank();
|
|
||||||
} else if(_scanline == 260) {
|
|
||||||
EndVBlank();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_cycle == 340) {
|
|
||||||
_cycle = 0;
|
|
||||||
_scanline++;
|
|
||||||
|
|
||||||
if(_scanline == 261) {
|
|
||||||
_scanline = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_cycle++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gap--;
|
|
||||||
}
|
}
|
||||||
|
_cycle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPU::ExecStatic()
|
||||||
|
{
|
||||||
|
PPU::Instance->Exec();
|
||||||
|
PPU::Instance->Exec();
|
||||||
|
PPU::Instance->Exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::StreamState(bool saving)
|
void PPU::StreamState(bool saving)
|
||||||
|
@ -703,7 +684,6 @@ void PPU::StreamState(bool saving)
|
||||||
Stream<int32_t>(_scanline);
|
Stream<int32_t>(_scanline);
|
||||||
Stream<uint32_t>(_cycle);
|
Stream<uint32_t>(_cycle);
|
||||||
Stream<uint32_t>(_frameCount);
|
Stream<uint32_t>(_frameCount);
|
||||||
Stream<int32_t>(_cycleCount);
|
|
||||||
Stream<uint8_t>(_memoryReadBuffer);
|
Stream<uint8_t>(_memoryReadBuffer);
|
||||||
|
|
||||||
StreamArray<uint8_t>(_paletteRAM, 0x100);
|
StreamArray<uint8_t>(_paletteRAM, 0x100);
|
||||||
|
|
14
Core/PPU.h
14
Core/PPU.h
|
@ -124,7 +124,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
bool _writeOAMData;
|
bool _writeOAMData;
|
||||||
uint32_t _overflowCounter;
|
uint32_t _overflowCounter;
|
||||||
bool _sprite0Added;
|
bool _sprite0Added;
|
||||||
|
|
||||||
void UpdateStatusFlag();
|
void UpdateStatusFlag();
|
||||||
|
|
||||||
void SetControlRegister(uint8_t value);
|
void SetControlRegister(uint8_t value);
|
||||||
|
@ -193,7 +193,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
uint8_t ReadRAM(uint16_t addr);
|
uint8_t ReadRAM(uint16_t addr);
|
||||||
void WriteRAM(uint16_t addr, uint8_t value);
|
void WriteRAM(uint16_t addr, uint8_t value);
|
||||||
|
|
||||||
void Exec(uint32_t extraCycles = 0);
|
void Exec();
|
||||||
|
|
||||||
static void RegisterVideoDevice(IVideoDevice *videoDevice)
|
static void RegisterVideoDevice(IVideoDevice *videoDevice)
|
||||||
{
|
{
|
||||||
|
@ -225,13 +225,5 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
return PPU::Instance->_scanline;
|
return PPU::Instance->_scanline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExecStatic(uint32_t cycles)
|
static void ExecStatic();
|
||||||
{
|
|
||||||
PPU::Instance->Exec(cycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndFrame()
|
|
||||||
{
|
|
||||||
_cycleCount = 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
18
NES.sln
18
NES.sln
|
@ -24,6 +24,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteropDLL", "InteropDLL\In
|
||||||
{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0} = {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}
|
{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0} = {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PGOHelper", "PGOHelper\PGOHelper.vcxproj", "{38D74EE1-5276-4D24-AABC-104B912A27D2}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{37749BB2-FA78-4EC9-8990-5628FC0BBA19} = {37749BB2-FA78-4EC9-8990-5628FC0BBA19}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -84,8 +89,21 @@ Global
|
||||||
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Mixed Platforms.Build.0 = Release|Win32
|
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||||
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.ActiveCfg = Release|Win32
|
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.Build.0 = Release|Win32
|
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Win32.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(Performance) = preSolution
|
||||||
|
HasPerformanceSessions = true
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
14
PGOHelper/PGOHelper.cpp
Normal file
14
PGOHelper/PGOHelper.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void __stdcall LoadROM(wchar_t* filename);
|
||||||
|
void __stdcall Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int _tmain(int argc, _TCHAR* argv[])
|
||||||
|
{
|
||||||
|
LoadROM(argv[1]);
|
||||||
|
Run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
94
PGOHelper/PGOHelper.vcxproj
Normal file
94
PGOHelper/PGOHelper.vcxproj
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{38D74EE1-5276-4D24-AABC-104B912A27D2}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>PGOHelper</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="PGOHelper.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\InteropDLL\InteropDLL.vcxproj">
|
||||||
|
<Project>{37749bb2-fa78-4ec9-8990-5628fc0bba19}</Project>
|
||||||
|
<Private>false</Private>
|
||||||
|
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||||
|
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||||
|
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||||
|
<UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
14
PGOHelper/PGOHelper.vcxproj.filters
Normal file
14
PGOHelper/PGOHelper.vcxproj.filters
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="PGOHelper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
Loading…
Add table
Reference in a new issue