Fixed a very rare edge case where an interrupt occurs when SP=FF11

This commit is contained in:
Lior Halphon 2019-01-12 00:39:24 +02:00
parent 4e2b5bb336
commit 21d2a59a5f

View File

@ -72,6 +72,21 @@ static uint8_t cycle_read_inc_oam_bug(GB_gameboy_t *gb, uint16_t addr)
return ret;
}
/* A special case for IF during ISR, returns the old value of IF. */
/* TODO: Verify the timing, it might be wrong in cases where, in the same M cycle, IF
is both read be the CPU, modified by the ISR, and modified by an actual interrupt.
If this timing proves incorrect, the ISR emulation must be updated so IF reads are
timed correctly. */
static uint8_t cycle_write_if(GB_gameboy_t *gb, uint8_t value)
{
assert(gb->pending_cycles);
GB_advance_cycles(gb, gb->pending_cycles);
uint8_t old = (gb->io_registers[GB_IO_IF]) & 0x1F;
GB_write_memory(gb, 0xFF00 + GB_IO_IF, value);
gb->pending_cycles = 4;
return old;
}
static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
{
assert(gb->pending_cycles);
@ -1399,8 +1414,15 @@ void GB_cpu_run(GB_gameboy_t *gb)
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8);
interrupt_queue = gb->interrupt_enable;
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
interrupt_queue &= (gb->io_registers[GB_IO_IF]) & 0x1F;
if (gb->registers[GB_REGISTER_SP] == GB_IO_IF + 0xFF00 + 1) {
gb->registers[GB_REGISTER_SP]--;
interrupt_queue &= cycle_write_if(gb, (gb->pc) & 0xFF);
}
else {
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
interrupt_queue &= (gb->io_registers[GB_IO_IF]) & 0x1F;
}
if (interrupt_queue) {
uint8_t interrupt_bit = 0;