From bc90c489c1a040117e22021b1c4a2210aa0af0ec Mon Sep 17 00:00:00 2001 From: Sour Date: Sat, 23 May 2020 12:38:31 -0400 Subject: [PATCH] GB: Improved EI and IRQ behavior Passes ei_sequence, ei_timing, ie_push, rapid_di_ei, reti_intr_timing --- Core/GbCpu.cpp | 25 ++++++++++++++++++++++--- Core/GbTypes.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index 76ac7de..8b1f886 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -49,18 +49,32 @@ void GbCpu::Exec() if(irqVector) { if(_state.IME) { uint16_t oldPc = _state.PC; - _memoryManager->ClearIrqRequest(irqVector); IncCycleCount(); IncCycleCount(); - PushWord(_state.PC); + + PushByte(_state.PC >> 8); + irqVector = _memoryManager->ProcessIrqRequests(); //Check IRQ line again before jumping (ie_push) + PushByte((uint8_t)_state.PC); + IncCycleCount(); + switch(irqVector) { + case 0: + //IRQ request bit is no longer set, jump to $0000 (ie_push test) + _state.PC = 0; + break; + case GbIrqSource::VerticalBlank: _state.PC = 0x40; break; case GbIrqSource::LcdStat: _state.PC = 0x48; break; case GbIrqSource::Timer: _state.PC = 0x50; break; case GbIrqSource::Serial: _state.PC = 0x58; break; case GbIrqSource::Joypad: _state.PC = 0x60; break; } + if(irqVector) { + //Only clear IRQ bit if an IRQ was processed + _memoryManager->ClearIrqRequest(irqVector); + } + _state.IME = false; _console->ProcessInterrupt(oldPc, _state.PC, false); } @@ -72,6 +86,11 @@ void GbCpu::Exec() return; } + if(_state.EiPending) { + _state.EiPending = false; + _state.IME = true; + } + ExecOpCode(ReadOpCode()); } @@ -1083,7 +1102,7 @@ void GbCpu::CCF() void GbCpu::EI() { - _state.IME = true; + _state.EiPending = true; } void GbCpu::DI() diff --git a/Core/GbTypes.h b/Core/GbTypes.h index 21da166..8b18fce 100644 --- a/Core/GbTypes.h +++ b/Core/GbTypes.h @@ -19,6 +19,7 @@ struct GbCpuState uint8_t H; uint8_t L; + bool EiPending; bool IME; bool Halted; };