IRQ/NMI timing fixed (Dragon Quest 3 was still broken) + code cleanup
This commit is contained in:
parent
ac0d84171a
commit
95c0ab9047
6 changed files with 19 additions and 51 deletions
|
@ -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 {
|
||||
|
|
41
Core/CPU.cpp
41
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<int32_t>(_cycleCount);
|
||||
Stream<bool>(_state.NMIFlag);
|
||||
Stream<uint32_t>(_state.IRQFlag);
|
||||
|
||||
Stream<bool>(_runNMI);
|
||||
Stream<bool>(_runIRQ);
|
||||
|
||||
Stream<int32_t>(_relativeCycleCount);
|
||||
}
|
20
Core/CPU.h
20
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; }
|
||||
};
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue