From 608c9a03cf2e1c113f6539d2b2bd39b422eded00 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 15 Jun 2014 09:35:17 -0400 Subject: [PATCH] PPU, NMI --- Core/CPU.cpp | 17 +++++++++++----- Core/CPU.h | 20 ++++++++++++------- Core/Console.cpp | 6 +++--- Core/PPU.cpp | 50 ++++++++++++++++++++++++++++++------------------ Core/PPU.h | 5 +++-- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/Core/CPU.cpp b/Core/CPU.cpp index bf319065..556e50e6 100644 --- a/Core/CPU.cpp +++ b/Core/CPU.cpp @@ -3,6 +3,7 @@ #include "Timer.h" uint64_t CPU::CycleCount = 0; +bool CPU::NMIFlag = false; CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager) { @@ -63,11 +64,17 @@ void CPU::Reset() void CPU::Exec() { - uint8_t opCode = ReadByte(); - if(_opTable[opCode] != nullptr) { - (this->*_opTable[opCode])(); - CPU::CycleCount += this->_cycles[opCode]; + if(!CPU::NMIFlag) { + uint8_t opCode = ReadByte(); + if(_opTable[opCode] != nullptr) { + (this->*_opTable[opCode])(); + CPU::CycleCount += this->_cycles[opCode]; + } else { + //throw std::exception("Invalid opcode"); + } } else { - //throw std::exception("Invalid opcode"); + NMI(); + CPU::CycleCount += 7; + CPU::NMIFlag = false; } } diff --git a/Core/CPU.h b/Core/CPU.h index 1b5d7625..c2074d7a 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -41,6 +41,7 @@ private: MemoryManager *_memoryManager = nullptr; static uint64_t CycleCount; + static bool NMIFlag; uint16_t _currentPC = 0; uint8_t _cyclePenalty = 0; @@ -592,6 +593,14 @@ private: SetPC(MemoryReadWord(0xFFFE)); } + void NMI() { + Push((uint16_t)(PC() + 1)); + Push((uint8_t)PS()); + SetFlags(PSFlags::Interrupt); + SetPC(MemoryReadWord(0xFFFA)); + } + + void NOP() {} void RTI() { SetPS(Pop()); @@ -601,13 +610,10 @@ private: public: CPU(MemoryManager *memoryManager); - static uint64_t GetCycleCount() { - return CPU::CycleCount; - } + static uint64_t GetCycleCount() { return CPU::CycleCount; } + static void SetNMIFlag() { CPU::NMIFlag = true; } void Reset(); void Exec(); - State GetState() - { - return _state; - } + State GetState() { return _state; } + }; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index d69f68aa..6856ec75 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -12,7 +12,7 @@ Console::Console(string filename) Console::~Console() { - + _cpu.release(); } void Console::Reset() @@ -46,7 +46,7 @@ void Console::RunTests() console->Run(); delete console;*/ - vector testROMs = { { "nestest", "01-basics", "02-implied", "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", "16-special" } }; + vector testROMs = { { "01-basics", "02-implied", "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", "16-special" } }; for(string testROM : testROMs) { Console *console = new Console(string("TestSuite/") + testROM + ".nes"); @@ -64,7 +64,7 @@ void Console::RunTests() uint8_t testStatus = console->_memoryManager.Read(0x6000); if(testStatus == 0x81) { //need reset - throw std::exception("reset needed"); + OutputDebugStringA("reset needed"); } else if(testStatus == 0x80) { testStarted = true; } else if(testStatus < 0x80 && testStarted) { diff --git a/Core/PPU.cpp b/Core/PPU.cpp index 53868fe3..309a1d34 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -5,7 +5,9 @@ PPU::PPU() { _state = {}; - + _flags = {}; + _statusFlags = {}; + _outputBuffer = new uint8_t[256 * 240 * 4]; } @@ -105,7 +107,8 @@ void PPU::UpdateStatusFlag() { _state.Status = ((uint8_t)_statusFlags.SpriteOverflow << 5) | ((uint8_t)_statusFlags.Sprite0Hit << 6) | - ((uint8_t)_statusFlags.VerticalBlank << 7)); + ((uint8_t)_statusFlags.VerticalBlank << 7); + _statusFlags.VerticalBlank = false; } void PPU::Exec() @@ -113,14 +116,19 @@ void PPU::Exec() uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3; while(_cycleCount < equivalentCycleCount) { if(_scanline == -1) { + //Pre-render scanline if(_cycle == 1) { _statusFlags.SpriteOverflow = false; _statusFlags.Sprite0Hit = false; + _statusFlags.VerticalBlank = false; } else if(_cycle == 304) { // Copy scroll latch into VRAMADDR register - if(_flags.BackgroundEnabled || _flags.SpritesEnabled) { + /*if(_flags.BackgroundEnabled || _flags.SpritesEnabled) { //p->registers.vramAddress = p->registers.vramLatch; - } + }*/ + } else if(_cycle == 339 && (_frameCount % 2 == 1)) { + //Skip a cycle for odd frames + _cycle++; } } else if(_scanline < 240) { if(_cycle == 254) { @@ -136,38 +144,42 @@ void PPU::Exec() //Ppu_updateEndScanlineRegisters(p); } } - } else if(_scanline == 240) { + } else if(_scanline == 241) { + //Start of VBlank if(_cycle == 1) { - if(!_suppressVBlank) { + _statusFlags.VerticalBlank = true; + /*if(!_suppressVBlank) { // We're in VBlank Ppu_setStatus(p, STATUS_VBLANK_STARTED); p->cycleCount = 0; + }*/ + if(_flags.VBlank) { + CPU::SetNMIFlag(); } - if(_flags.VBlank && !_suppressNMI) { + /*if(_flags.VBlank && !_suppressNMI) { VBlankInterrupt(); - } + }*/ //Ppu_raster(p); } } else if(_scanline == 260) { - // End of vblank - if(_cycle == 1) { - // Clear VBlank flag - Ppu_clearStatus(p, STATUS_VBLANK_STARTED); - _cycleCount = 0; - } else if(_cycle == 341) { - _scanline = -1; - _cycle = 1; + //End of VBlank + if(_cycle == 340) { _frameCount++; - return; } } - if(_cycle == 341) { + if(_cycle == 340) { _cycle = 0; _scanline++; + + if(_scanline == 261) { + _scanline = -1; + _frameCount++; + } + } else { + _cycle++; } - _cycle++; _cycleCount++; } } \ No newline at end of file diff --git a/Core/PPU.h b/Core/PPU.h index 5357302c..f993a74f 100644 --- a/Core/PPU.h +++ b/Core/PPU.h @@ -64,9 +64,10 @@ class PPU : public IMemoryHandler int16_t _scanline = -1; uint16_t _cycle = 0; + uint32_t _frameCount = 0; - PPUControlFlags _flags = {}; - PPUStatusFlags _statusFlags = {}; + PPUControlFlags _flags; + PPUStatusFlags _statusFlags; void PPU::UpdateStatusFlag();