diff --git a/cpu/cpu.cpp b/cpu/cpu.cpp index 12a9136..8021826 100644 --- a/cpu/cpu.cpp +++ b/cpu/cpu.cpp @@ -84,20 +84,35 @@ void Cpu::reset() state.IF = 0; state.halted = false; + state.haltbug = false; state.stopped = false; } u8 Cpu::readPC8() { u8 data = bus->read8(state.PC); - state.PC++; + if(!state.haltbug) + state.PC++; + else + state.haltbug = false; return data; } u16 Cpu::readPC16() { - u16 data = bus->read16(state.PC); - state.PC+=2; + u16 data; + if(state.haltbug) + { + data = bus->read8(state.PC); + data |= data << 8; // Same byte twice + state.PC++; + state.haltbug = false; + } + else + { + data = bus->read16(state.PC); + state.PC+=2; + } return data; } @@ -230,11 +245,8 @@ void Cpu::aluop8(AluOp op, u8 lhs, u8 rhs, u8& out, bool update_carry) bool Cpu::handleInterrupts() { - // servicable interrupts (assuming IME is on) - u8 si = state.IE & state.IF & INT_MASK; - // Once there's an interrupt we exit halt mode - if (si) + if (state.SI()) state.halted = false; if (state.IME == IME_SCHEDULED) diff --git a/cpu/cpu.h b/cpu/cpu.h index 15f0b52..a44017d 100644 --- a/cpu/cpu.h +++ b/cpu/cpu.h @@ -116,7 +116,12 @@ struct Cpu_state { u8 IE; u8 IF; + // servicable interrupts + inline u8 SI() const + { return INT_MASK & IE & IF; } + bool halted; + bool haltbug; bool stopped; void setAF(u16 v); diff --git a/cpu/decoder.cpp b/cpu/decoder.cpp index cbc9b6b..6c21e1d 100644 --- a/cpu/decoder.cpp +++ b/cpu/decoder.cpp @@ -443,6 +443,8 @@ void Cpu::executeInstruction() break; case 0x76: // HALT state.halted = true; + if(state.IME != IME_ON && state.SI()) + state.haltbug = true; break; case 0x10: // STOP n8 (void)readPC8();