From 72d26c7046b4c322b0157377e85b068108ad3776 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Mon, 4 Sep 2017 18:40:43 +0300 Subject: [PATCH] Fixed obscure timer behavior, fixed regression in rapid_toggle.gb. --- Core/gb.h | 3 +++ Core/timing.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/gb.h b/Core/gb.h index 37562561..773dccc1 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -333,6 +333,9 @@ struct GB_gameboy_internal_s { uint16_t serial_cycles; /* This field changed its meaning in v0.10 */ uint16_t serial_length; uint8_t delayed_interrupts; /* When an interrupt occurs while not aligned to a T-cycle, it must be "delayed" */ + bool dont_delay_timer_interrupt; /* If the timer glitch causes a TIMA overflow, it causes the timer to overflow + with different timing, so the triggered interrupt is not delayed. + Todo: needs test ROM. */ ); /* APU */ diff --git a/Core/timing.c b/Core/timing.c index 72097c24..626cb455 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -88,7 +88,9 @@ static void advance_tima_state_machine(GB_gameboy_t *gb) } else if (gb->tima_reload_state == GB_TIMA_RELOADING) { gb->io_registers[GB_IO_IF] |= 4; - gb->delayed_interrupts |= 4; // Timer interrupt is not aligned to a T-cycle and therefore is effective only the next one. + if (!gb->dont_delay_timer_interrupt) { + gb->delayed_interrupts |= 4; // Timer interrupt is not aligned to a T-cycle and therefore is effective only the next one. + } gb->tima_reload_state = GB_TIMA_RELOADED; } } @@ -156,6 +158,7 @@ static void increase_tima(GB_gameboy_t *gb) { gb->io_registers[GB_IO_TIMA]++; if (gb->io_registers[GB_IO_TIMA] == 0) { + gb->dont_delay_timer_interrupt = false; gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA]; gb->tima_reload_state = GB_TIMA_RELOADING; } @@ -195,6 +198,7 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac) /* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */ if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) { increase_tima(gb); + gb->dont_delay_timer_interrupt = true; } } }