diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 7c2e877b..80b9f8a3 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -27,6 +27,7 @@ class BaseMapper : public IMemoryHandler class DefaultMapper : public BaseMapper { vector _mappedRomBanks; + MemoryBank *_mappedVromBank; private: void InitMapper() { @@ -35,23 +36,40 @@ class DefaultMapper : public BaseMapper } else { _mappedRomBanks = { &_romBanks[0], &_romBanks[1] }; } + + _mappedVromBank = &_vromBanks[0]; } public: - std::array GetIOAddresses() + vector> GetRAMAddresses() { - return std::array {{ 0x8000, 0xFFFF }}; + return { { { 0x8000, 0xFFFF } } }; + } + + vector> GetVRAMAddresses() + { + return { { { 0x0000, 0x1FFF } } }; } - uint8_t MemoryRead(uint16_t addr) + uint8_t ReadRAM(uint16_t addr) { return (*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF]; } - void MemoryWrite(uint16_t addr, uint8_t value) + void WriteRAM(uint16_t addr, uint8_t value) { (*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF] = value; } + + uint8_t ReadVRAM(uint16_t addr) + { + return (*_mappedVromBank)[addr & 0x1FFF]; + } + + void WriteVRAM(uint16_t addr, uint8_t value) + { + (*_mappedVromBank)[addr & 0x1FFF] = value; + } }; class MapperFactory diff --git a/Core/CPU.h b/Core/CPU.h index 3394b37f..c62f47f5 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -144,7 +144,7 @@ private: uint8_t SP() { return _state.SP; } void SetSP(uint8_t value) { _state.SP = value; } uint8_t PS() { return _state.PS; } - void SetPS(uint8_t value) { _state.PS = value | PSFlags::Reserved; } + void SetPS(uint8_t value) { _state.PS = (value & 0xDF) | PSFlags::Reserved; } uint16_t PC() { return _state.PC; } void SetPC(uint16_t value) { _state.PC = value; } @@ -182,8 +182,7 @@ private: uint16_t GetInd() { uint16_t addr = ReadWord(); - if(addr & 0xFF == 0xFF) { - //Emulate a CPU bug when crossing page boundary + if((addr & 0xFF) == 0xFF) { auto lo = MemoryRead(addr); auto hi = MemoryRead(addr - 0xFF); return (lo | hi << 8); @@ -250,7 +249,7 @@ private: if(reg == value) { SetFlags(PSFlags::Zero); } - if(result & 0x80 == 0x80) { + if((result & 0x80) == 0x80) { SetFlags(PSFlags::Negative); } } @@ -437,8 +436,8 @@ private: void PHA() { Push(A()); } void PHP() { - SetFlags(PSFlags::Break); - Push((uint8_t)PS()); + uint8_t flags = PS() | PSFlags::Break; + Push((uint8_t)flags); } void PLA() { SetA(Pop()); } void PLP() { SetPS(Pop()); } @@ -607,11 +606,11 @@ private: void SEI() { SetFlags(PSFlags::Interrupt); } void BRK() { - SetFlags(PSFlags::Break); Push((uint16_t)(PC() + 1)); - Push((uint8_t)PS()); + + uint8_t flags = PS() | PSFlags::Break; + Push((uint8_t)flags); SetFlags(PSFlags::Interrupt); - ClearFlags(PSFlags::Break); SetPC(MemoryReadWord(0xFFFE)); } diff --git a/Core/Console.cpp b/Core/Console.cpp index 8f56bbf1..237a74fe 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -6,13 +6,13 @@ Console::Console(string filename) { _mapper = MapperFactory::InitializeFromFile(filename); _memoryManager.RegisterIODevice(_mapper.get()); - _memoryManager.RegisterIODevice(&_ppu); _cpu.reset(new CPU(&_memoryManager)); + _ppu.reset(new PPU(&_memoryManager)); + _memoryManager.RegisterIODevice(_ppu.get()); } Console::~Console() { - _cpu.release(); } void Console::Reset() @@ -24,65 +24,72 @@ void Console::Run() { while(true) { _cpu->Exec(); - _ppu.Exec(); + _ppu->Exec(); } } void Console::RunTest(bool callback(Console*)) { while(true) { - _cpu->Exec(); - _ppu.Exec(); - if(callback(this)) { break; } + + _cpu->Exec(); + _ppu->Exec(); } } void Console::RunTests() { - /*Console *console = new Console("mario.nes"); - console->Run(); - delete console;*/ - - vector testROMs = { { + vector testROMs { + //"mario" "01-basics", "02-implied", - //"03-immediate", - //"04-zero_page", - //"05-zp_xy", - //"06-absolute", - //"07-abs_xy", + "03-immediate", + "04-zero_page", + "05-zp_xy", + "06-absolute", + "07-abs_xy", "08-ind_x", "09-ind_y", "10-branches", "11-stack", "12-jmp_jsr", "13-rts", - "14-rti", - //"15-brk", + "14-rti", + "15-brk", "16-special" - } }; + }; for(string testROM : testROMs) { Console *console = new Console(string("TestSuite/") + testROM + ".nes"); if(testROM == "nestest") { console->RunTest([] (Console *console) { - auto state = console->_cpu->GetState(); - std::stringstream ss; - ss << std::hex << (short)state.PC << " A:" << (short)state.A << " X:" << (short)state.X << " Y:" << (short)state.Y << std::endl; - OutputDebugStringA(ss.str().c_str()); + State state = console->_cpu->GetState(); + std::cout << std::hex << std::uppercase << + "A:" << std::setfill('0') << std::setw(2) << (short)state.A << + " X:" << std::setfill('0') << std::setw(2) << (short)state.X << + " Y:" << std::setfill('0') << std::setw(2) << (short)state.Y << + " S:" << std::setfill('0') << std::setw(2) << (short)state.SP << + " P:........ $" << + std::setfill('0') << std::setw(4) << (short)state.PC <RunTest([] (Console *console) { - //static std::ofstream output("test.log", ios::out | ios::binary); + static std::ofstream output("test.log", ios::out | ios::binary); static bool testStarted = false; uint8_t testStatus = console->_memoryManager.Read(0x6000); State state = console->_cpu->GetState(); - //output << std::hex << (short)state.PC << " A:" << (short)state.A << " X:" << (short)state.X << " Y:" << (short)state.Y << std::endl; + /*output << std::hex << std::uppercase << + "A:" << std::setfill('0') << std::setw(2) << (short)state.A << + " X:" << std::setfill('0') << std::setw(2) << (short)state.X << + " Y:" << std::setfill('0') << std::setw(2) << (short)state.Y << + " S:" << std::setfill('0') << std::setw(2) << (short)state.SP << + " P:........ $" << + std::setfill('0') << std::setw(4) << (short)state.PC < _cpu; - PPU _ppu; + unique_ptr _ppu; shared_ptr _mapper; MemoryManager _memoryManager; diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h index 468ac3fe..a863b95d 100644 --- a/Core/IMemoryHandler.h +++ b/Core/IMemoryHandler.h @@ -4,8 +4,11 @@ class IMemoryHandler { - public: - virtual std::array GetIOAddresses() = 0; - virtual uint8_t MemoryRead(uint16_t addr) = 0; - virtual void MemoryWrite(uint16_t addr, uint8_t value) = 0; +public: + virtual vector> GetRAMAddresses() = 0; + virtual vector> GetVRAMAddresses() { return{}; } + virtual uint8_t ReadRAM(uint16_t addr) = 0; + virtual void WriteRAM(uint16_t addr, uint8_t value) = 0; + virtual uint8_t ReadVRAM(uint16_t addr) { return 0; } + virtual void WriteVRAM(uint16_t addr, uint8_t value) { } }; \ No newline at end of file diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 79faf06b..0d756ab5 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -3,8 +3,8 @@ uint8_t MemoryManager::ReadRegister(uint16_t addr) { - if(_registerHandlers[addr]) { - return _registerHandlers[addr]->MemoryRead(addr); + if(_ramHandlers[addr]) { + return _ramHandlers[addr]->ReadRAM(addr); } else { return 0; } @@ -12,8 +12,24 @@ uint8_t MemoryManager::ReadRegister(uint16_t addr) void MemoryManager::WriteRegister(uint16_t addr, uint8_t value) { - if(_registerHandlers[addr]) { - _registerHandlers[addr]->MemoryWrite(addr, value); + if(_ramHandlers[addr]) { + _ramHandlers[addr]->WriteRAM(addr, value); + } +} + +uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr) +{ + if(_vramHandlers[addr]) { + return _vramHandlers[addr]->ReadVRAM(addr); + } else { + return 0; + } +} + +void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value) +{ + if(_vramHandlers[addr]) { + _vramHandlers[addr]->WriteVRAM(addr, value); } } @@ -21,13 +37,19 @@ MemoryManager::MemoryManager() { _internalRAM = new uint8_t[InternalRAMSize]; _SRAM = new uint8_t[SRAMSize]; + _videoRAM = new uint8_t[VRAMSize]; _expansionRAM = new uint8_t[0x2000]; ZeroMemory(_internalRAM, InternalRAMSize); ZeroMemory(_SRAM, SRAMSize); + ZeroMemory(_videoRAM, VRAMSize); ZeroMemory(_expansionRAM, 0x2000); for(int i = 0; i <= 0xFFFF; i++) { - _registerHandlers.push_back(nullptr); + _ramHandlers.push_back(nullptr); + } + + for(int i = 0; i <= 0x3FFF; i++) { + _vramHandlers.push_back(nullptr); } } @@ -40,9 +62,18 @@ MemoryManager::~MemoryManager() void MemoryManager::RegisterIODevice(IMemoryHandler *handler) { - std::array addresses = handler->GetIOAddresses(); - for(int i = addresses[0]; i < addresses[1]; i++) { - _registerHandlers[i] = handler; + vector> addresses = handler->GetRAMAddresses(); + for(std::array startEndAddr : addresses) { + for(int i = startEndAddr[0]; i <= startEndAddr[1]; i++) { + _ramHandlers[i] = handler; + } + } + + addresses = handler->GetVRAMAddresses(); + for(std::array startEndAddr : addresses) { + for(int i = startEndAddr[0]; i <= startEndAddr[1]; i++) { + _vramHandlers[i] = handler; + } } } @@ -82,4 +113,21 @@ uint16_t MemoryManager::ReadWord(uint16_t addr) uint8_t hi = Read(addr+1); return lo | hi << 8; } - \ No newline at end of file + +uint8_t MemoryManager::ReadVRAM(uint16_t addr) +{ + if(addr <= 0x1FFF) { + return ReadMappedVRAM(addr & 0x1FFF); + } else { + return _videoRAM[addr & 0x3FFF]; + } +} + +void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value) +{ + if(addr <= 0x1FFF) { + WriteMappedVRAM(addr, value); + } else { + _videoRAM[addr & 0x3FFF] = value; + } +} \ No newline at end of file diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 83cc88c5..b02acb16 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -8,15 +8,21 @@ class MemoryManager private: const int InternalRAMSize = 0x800; const int SRAMSize = 0x2000; + const int VRAMSize = 0x4000; uint8_t *_internalRAM; uint8_t *_expansionRAM; uint8_t *_SRAM; + uint8_t *_videoRAM; - vector _registerHandlers; + vector _ramHandlers; + vector _vramHandlers; - inline uint8_t ReadRegister(uint16_t addr); - inline void WriteRegister(uint16_t addr, uint8_t value); + uint8_t ReadRegister(uint16_t addr); + void WriteRegister(uint16_t addr, uint8_t value); + + uint8_t ReadMappedVRAM(uint16_t addr); + void WriteMappedVRAM(uint16_t addr, uint8_t value); public: MemoryManager(); @@ -25,8 +31,12 @@ class MemoryManager void RegisterIODevice(IMemoryHandler *handler); uint8_t Read(uint16_t addr); - void Write(uint16_t addr, uint8_t value); uint16_t ReadWord(uint16_t addr); + void Write(uint16_t addr, uint8_t value); + + uint8_t ReadVRAM(uint16_t addr); + void WriteVRAM(uint16_t addr, uint8_t value); + char* GetTestResult() { diff --git a/Core/PPU.cpp b/Core/PPU.cpp index 407a96bb..63cadb35 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -2,8 +2,9 @@ #include "PPU.h" #include "CPU.h" -PPU::PPU() +PPU::PPU(MemoryManager *memoryManager) { + _memoryManager = memoryManager; _state = {}; _flags = {}; _statusFlags = {}; @@ -21,7 +22,7 @@ bool PPU::CheckFlag(PPUControlFlags flag) return false; } -uint8_t PPU::MemoryRead(uint16_t addr) +uint8_t PPU::ReadRAM(uint16_t addr) { switch(GetRegisterID(addr)) { case PPURegisters::Control: @@ -36,13 +37,14 @@ uint8_t PPU::MemoryRead(uint16_t addr) return _spriteRAM[_state.SpriteRamAddr]; case PPURegisters::VideoMemoryData: uint8_t returnValue = _memoryReadBuffer; - _memoryReadBuffer = _videoRAM[_state.VideoRamAddr]; + _memoryReadBuffer = _memoryManager->ReadVRAM(_state.VideoRamAddr); + _state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1; return returnValue; } return 0; } -void PPU::MemoryWrite(uint16_t addr, uint8_t value) +void PPU::WriteRAM(uint16_t addr, uint8_t value) { switch(GetRegisterID(addr)) { case PPURegisters::Control: @@ -72,7 +74,8 @@ void PPU::MemoryWrite(uint16_t addr, uint8_t value) _writeLow = !_writeLow; break; case PPURegisters::VideoMemoryData: - _videoRAM[_state.VideoRamAddr&0x3FFF] = value; + _memoryManager->WriteVRAM(_state.VideoRamAddr, value); + _state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1; break; } } @@ -125,8 +128,8 @@ void PPU::Exec() /*if(_flags.BackgroundEnabled || _flags.SpritesEnabled) { //p->registers.vramAddress = p->registers.vramLatch; }*/ - } else if(_cycle == 339 && (_frameCount % 2 == 1)) { - //Skip a cycle for odd frames + } else if(_cycle == 339 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) { + //Skip a cycle for odd frames, if background drawing is enabled _cycle++; } } else if(_scanline < 240) { diff --git a/Core/PPU.h b/Core/PPU.h index eba052f3..f454ad68 100644 --- a/Core/PPU.h +++ b/Core/PPU.h @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -#include "IMemoryHandler.h" +#include "MemoryManager.h" enum PPURegisters { @@ -53,12 +53,13 @@ struct PPUState class PPU : public IMemoryHandler { private: + MemoryManager *_memoryManager; + PPUState _state; uint64_t _cycleCount; uint8_t _memoryReadBuffer; uint8_t _spriteRAM[0x100]; - uint8_t _videoRAM[0x4000]; uint8_t *_outputBuffer; @@ -82,16 +83,16 @@ class PPU : public IMemoryHandler } public: - PPU(); + PPU(MemoryManager *memoryManager); ~PPU(); - std::array GetIOAddresses() - { - return std::array {{ 0x2000, 0x3FFF }}; + vector> GetRAMAddresses() + { + return{ { { 0x2000, 0x3FFF } }, { {0x4014, 0x4014 } } }; } - uint8_t MemoryRead(uint16_t addr); - void MemoryWrite(uint16_t addr, uint8_t value); + uint8_t ReadRAM(uint16_t addr); + void WriteRAM(uint16_t addr, uint8_t value); void Exec(); }; \ No newline at end of file