From f64da1864f5e3d710c0f9d1c531d1f59bf80b3d2 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 9 Jun 2018 15:11:20 +0300 Subject: [PATCH] APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode), the first DIV/APU event is skipped. --- Core/apu.c | 9 +++++++++ Core/apu.h | 2 ++ Core/gb.h | 2 +- Core/timing.c | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Core/apu.c b/Core/apu.c index 703355a..cb462d7 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -181,6 +181,10 @@ static void nrx2_glitch(uint8_t *volume, uint8_t value, uint8_t old_value) void GB_apu_div_event(GB_gameboy_t *gb) { if (!gb->apu.global_enable) return; + if (gb->apu.skip_div_event) { + gb->apu.skip_div_event = false; + return; + } gb->apu.div_divider++; if ((gb->apu.div_divider & 7) == 0) { @@ -426,6 +430,11 @@ void GB_apu_init(GB_gameboy_t *gb) { memset(&gb->apu, 0, sizeof(gb->apu)); gb->apu.lf_div = 1; + /* APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode), the + first DIV/APU event is skipped. */ + if (gb->div_counter & (gb->cgb_double_speed? 0x2000 : 0x1000)) { + gb->apu.skip_div_event = true; + } } uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) diff --git a/Core/apu.h b/Core/apu.h index f75d25e..59d0e36 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -108,6 +108,8 @@ typedef struct } noise_channel; + bool skip_div_event; + } GB_apu_t; typedef enum { diff --git a/Core/gb.h b/Core/gb.h index aa16ede..afd5c27 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -350,7 +350,7 @@ struct GB_gameboy_internal_s { GB_SECTION(timing, GB_UNIT(display); GB_UNIT(div); - uint32_t div_counter; + uint16_t div_counter; uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ uint16_t serial_cycles; uint16_t serial_length; diff --git a/Core/timing.c b/Core/timing.c index 6132f40..58177d5 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -130,6 +130,8 @@ static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value) counter_overflow_check(gb->div_counter, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) { increase_tima(gb); } + + /* TODO: Can switching to double speed mode trigger an event? */ if (counter_overflow_check(gb->div_counter, value, gb->cgb_double_speed? 0x4000 : 0x2000)) { GB_apu_run(gb); GB_apu_div_event(gb);