IRQ/NMI timing fixed (Dragon Quest 3 was still broken) + code cleanup

This commit is contained in:
Souryo 2015-07-19 22:09:24 -04:00
parent ac0d84171a
commit 95c0ab9047
6 changed files with 19 additions and 51 deletions

View file

@ -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 {

View file

@ -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<int32_t>(_cycleCount);
Stream<bool>(_state.NMIFlag);
Stream<uint32_t>(_state.IRQFlag);
Stream<bool>(_runNMI);
Stream<bool>(_runIRQ);
Stream<int32_t>(_relativeCycleCount);
}

View file

@ -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; }
};

View file

@ -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();

View file

@ -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();
}

View file

@ -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) {