From 95c0ab90474860fc9ca41cc94f34032e4c5d362b Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 19 Jul 2015 22:09:24 -0400 Subject: [PATCH] IRQ/NMI timing fixed (Dragon Quest 3 was still broken) + code cleanup --- Core/ApuFrameCounter.h | 2 +- Core/CPU.cpp | 41 ++++++++++------------------------------- Core/CPU.h | 20 +++++--------------- Core/Console.cpp | 1 - Core/Debugger.cpp | 4 ++-- Core/MMC1.h | 2 +- 6 files changed, 19 insertions(+), 51 deletions(-) diff --git a/Core/ApuFrameCounter.h b/Core/ApuFrameCounter.h index 84f147df..0c04a781 100644 --- a/Core/ApuFrameCounter.h +++ b/Core/ApuFrameCounter.h @@ -130,7 +130,7 @@ public: } //Reset sequence after $4017 is written to - if(CPU::GetRelativeCycleCount() & 0x01) { + if(CPU::GetCycleCount() & 0x01) { //"If the write occurs during an APU cycle, the effects occur 3 CPU cycles after the $4017 write cycle" _previousCycle = -3; } else { diff --git a/Core/CPU.cpp b/Core/CPU.cpp index 6dee9a7b..684124d4 100644 --- a/Core/CPU.cpp +++ b/Core/CPU.cpp @@ -58,7 +58,6 @@ void CPU::Reset(bool softReset) _state.NMIFlag = false; _state.IRQFlag = 0; _cycleCount = 0; - _relativeCycleCount = 0; //Use _memoryManager->Read() directly to prevent clocking the PPU/APU when setting PC at reset _state.PC = _memoryManager->Read(CPU::ResetVector) | _memoryManager->Read(CPU::ResetVector+1) << 8; @@ -73,44 +72,29 @@ void CPU::Reset(bool softReset) _state.Y = 0; _state.PS = PSFlags::Reserved | PSFlags::Interrupt; - _runIRQ = false; - _runNMI = false; + _runIrq = false; } } -uint32_t CPU::Exec() +void CPU::Exec() { uint8_t opCode = GetOPCode(); _instAddrMode = _addrMode[opCode]; _operand = FetchOperand(); + (this->*_opTable[opCode])(); - if(_opTable[opCode] != nullptr) { - (this->*_opTable[opCode])(); - } else { - std::cout << "Invalid opcode: " << std::hex << (short)opCode; - } - - _runNMI = _state.NMIFlag; - _runIRQ = _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt); - - if(_runNMI) { - NMI(); - _state.NMIFlag = false; - } else if(_runIRQ) { + if(_prevRunIrq) { IRQ(); } - - return _cycleCount; -} - -void CPU::EndFrame() -{ - _relativeCycleCount += _cycleCount; - _cycleCount = 0; } void CPU::IncCycleCount() { + //"it's really the status of the interrupt lines at the end of the second-to-last cycle that matters." + //Keep the irq lines values from the previous cycle. The before-to-last cycle's values will be used + _prevRunIrq = _runIrq; + _runIrq = _state.NMIFlag || (_state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)); + PPU::ExecStatic(); APU::ExecStatic(); _cycleCount++; @@ -119,7 +103,7 @@ void CPU::IncCycleCount() 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) { + if(Instance->_cycleCount % 2 != 0) { Instance->IncCycleCount(); } Instance->IncCycleCount(); @@ -148,9 +132,4 @@ void CPU::StreamState(bool saving) Stream(_cycleCount); Stream(_state.NMIFlag); Stream(_state.IRQFlag); - - Stream(_runNMI); - Stream(_runIRQ); - - Stream(_relativeCycleCount); } \ No newline at end of file diff --git a/Core/CPU.h b/Core/CPU.h index ae6b2a27..ea83c984 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -59,7 +59,6 @@ private: typedef void(CPU::*Func)(); int32_t _cycleCount; - int32_t _relativeCycleCount; uint16_t _operand; Func _opTable[256]; @@ -72,8 +71,8 @@ private: State _state; MemoryManager *_memoryManager = nullptr; - bool _runNMI = false; - bool _runIRQ = false; + bool _prevRunIrq = false; + bool _runIrq = false; void IncCycleCount(); @@ -619,15 +618,6 @@ private: } } - 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((uint8_t)PS()); - SetFlags(PSFlags::Interrupt); - SetPC(MemoryReadWord(CPU::NMIVector)); - } - 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.) @@ -638,6 +628,7 @@ private: SetFlags(PSFlags::Interrupt); SetPC(MemoryReadWord(CPU::NMIVector)); + _state.NMIFlag = false; } else { Push((uint8_t)PS()); SetFlags(PSFlags::Interrupt); @@ -842,7 +833,7 @@ public: static const uint32_t ClockRate = 1789773; CPU(MemoryManager *memoryManager); - static int32_t GetRelativeCycleCount() { return CPU::Instance->_relativeCycleCount + CPU::Instance->_cycleCount; } + static int32_t GetCycleCount() { return CPU::Instance->_cycleCount; } static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; } static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; } static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; } @@ -851,8 +842,7 @@ public: static void RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue); void Reset(bool softReset); - uint32_t Exec(); - void EndFrame(); + void Exec(); State GetState() { return _state; } }; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index 03265d68..de8bb6a8 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -160,7 +160,6 @@ void Console::Run() uint32_t currentFrameNumber = PPU::GetFrameCount(); if(currentFrameNumber != lastFrameNumber) { lastFrameNumber = currentFrameNumber; - _cpu->EndFrame(); if(EmulationSettings::CheckFlag(EmulationFlags::LimitFPS)) { elapsedTime = clockTimer.GetElapsedMS(); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 93ea9182..e0b93ecd 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -142,7 +142,7 @@ void Debugger::PrivateCheckBreakpoint(BreakpointType type, uint32_t addr) Step(2); } else if(_stepOverAddr != -1 && addr == _stepOverAddr) { Step(1); - } else if(_stepCycleCount != -1 && abs(_cpu->GetRelativeCycleCount() - _stepCycleCount) < 100 && _cpu->GetRelativeCycleCount() >= _stepCycleCount) { + } else if(_stepCycleCount != -1 && abs(_cpu->GetCycleCount() - _stepCycleCount) < 100 && _cpu->GetCycleCount() >= _stepCycleCount) { Step(1); } _disassembler->BuildCache(_mapper->ToAbsoluteAddress(addr), addr); @@ -198,7 +198,7 @@ void Debugger::Step(uint32_t count) void Debugger::StepCycles(uint32_t count) { //Run CPU for [count] CYCLES and before breaking again - _stepCycleCount = _cpu->GetRelativeCycleCount() + count; + _stepCycleCount = _cpu->GetCycleCount() + count; Run(); } diff --git a/Core/MMC1.h b/Core/MMC1.h index a851b462..40aab08b 100644 --- a/Core/MMC1.h +++ b/Core/MMC1.h @@ -160,7 +160,7 @@ class MMC1 : public BaseMapper void WriteRegister(uint16_t addr, uint8_t value) { - int32_t currentCycle = CPU::GetRelativeCycleCount(); + int32_t currentCycle = CPU::GetCycleCount(); //Ignore write if within 2 cycles of another write (i.e the real write after a dummy write) if(abs(currentCycle - _lastWriteCycle) >= 2) {