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.

This commit is contained in:
Lior Halphon 2018-06-09 15:11:20 +03:00
parent 593cb7c107
commit f64da1864f
4 changed files with 14 additions and 1 deletions

View File

@ -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) void GB_apu_div_event(GB_gameboy_t *gb)
{ {
if (!gb->apu.global_enable) return; if (!gb->apu.global_enable) return;
if (gb->apu.skip_div_event) {
gb->apu.skip_div_event = false;
return;
}
gb->apu.div_divider++; gb->apu.div_divider++;
if ((gb->apu.div_divider & 7) == 0) { 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)); memset(&gb->apu, 0, sizeof(gb->apu));
gb->apu.lf_div = 1; 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) uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)

View File

@ -108,6 +108,8 @@ typedef struct
} noise_channel; } noise_channel;
bool skip_div_event;
} GB_apu_t; } GB_apu_t;
typedef enum { typedef enum {

View File

@ -350,7 +350,7 @@ struct GB_gameboy_internal_s {
GB_SECTION(timing, GB_SECTION(timing,
GB_UNIT(display); GB_UNIT(display);
GB_UNIT(div); 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. */ uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */
uint16_t serial_cycles; uint16_t serial_cycles;
uint16_t serial_length; uint16_t serial_length;

View File

@ -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])) { counter_overflow_check(gb->div_counter, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) {
increase_tima(gb); 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)) { if (counter_overflow_check(gb->div_counter, value, gb->cgb_double_speed? 0x4000 : 0x2000)) {
GB_apu_run(gb); GB_apu_run(gb);
GB_apu_div_event(gb); GB_apu_div_event(gb);