From 94776fcf8c2a99aebdbd654dfbf06bb73e11c38a Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 19 Oct 2021 01:53:24 +0300 Subject: [PATCH] Better (But imperfect) emulation of the wave RAM address bug glitch --- Core/apu.c | 37 ++++++++++++++++++++++++++++++++++++- Core/apu.h | 3 +++ Core/gb.h | 1 + Core/sm83_cpu.c | 41 ++++++++++++++++++----------------------- 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/Core/apu.c b/Core/apu.c index dc13e201..537ae016 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -529,6 +529,16 @@ void GB_apu_div_event(GB_gameboy_t *gb) if (gb->apu.wave_channel.length_enabled) { if (gb->apu.wave_channel.pulse_length) { if (!--gb->apu.wave_channel.pulse_length) { + if (gb->apu.is_active[GB_WAVE] && gb->model == GB_MODEL_AGB) { + if (gb->apu.wave_channel.sample_countdown == 0) { + gb->apu.wave_channel.current_sample_byte = + gb->io_registers[GB_IO_WAV_START + (((gb->apu.wave_channel.current_sample_index + 1) & 0xF) >> 1)]; + } + else if (gb->apu.wave_channel.sample_countdown == 9) { + // TODO: wtf? + gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START]; + } + } gb->apu.is_active[GB_WAVE] = false; update_sample(gb, GB_WAVE, 0, 0); } @@ -596,6 +606,12 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.apu_cycles = 0; if (!cycles) return; + if (unlikely(gb->apu.channel_3_delayed_bugged_read)) { + gb->apu.channel_3_delayed_bugged_read = false; + gb->apu.wave_channel.current_sample_byte = + gb->io_registers[GB_IO_WAV_START + (gb->address_bus & 0xF)]; + } + bool start_ch4 = false; if (likely(!gb->stopped || GB_is_cgb(gb))) { if (gb->apu.channel_4_dmg_delayed_start) { @@ -688,6 +704,23 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.wave_channel.wave_form_just_read = false; } } + else if (gb->apu.wave_channel.enable && gb->apu.channel_3_pulsed && gb->model < GB_MODEL_AGB) { + uint8_t cycles_left = cycles; + while (unlikely(cycles_left > gb->apu.wave_channel.sample_countdown)) { + cycles_left -= gb->apu.wave_channel.sample_countdown + 1; + gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length ^ 0x7FF; + if (cycles_left) { + gb->apu.wave_channel.current_sample_byte = + gb->io_registers[GB_IO_WAV_START + (gb->address_bus & 0xF)]; + } + else { + gb->apu.channel_3_delayed_bugged_read = true; + } + } + if (cycles_left) { + gb->apu.wave_channel.sample_countdown -= cycles_left; + } + } // The noise channel can step even if inactive on the DMG if (gb->apu.is_active[GB_NOISE] || !GB_is_cgb(gb)) { @@ -1156,13 +1189,14 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) case GB_IO_NR30: gb->apu.wave_channel.enable = value & 0x80; if (!gb->apu.wave_channel.enable) { + gb->apu.channel_3_pulsed = false; if (gb->apu.is_active[GB_WAVE]) { // Todo: I assume this happens on pre-CGB models; test this with an audible test if (gb->apu.wave_channel.sample_countdown == 0 && gb->model < GB_MODEL_AGB) { gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + (gb->pc & 0xF)]; } else if (gb->apu.wave_channel.wave_form_just_read && gb->model <= GB_MODEL_CGB_C) { - gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + (GB_IO_NR30 & 0xF) ]; + gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + (GB_IO_NR30 & 0xF)]; } } gb->apu.is_active[GB_WAVE] = false; @@ -1186,6 +1220,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) gb->apu.wave_channel.sample_length &= 0xFF; gb->apu.wave_channel.sample_length |= (value & 7) << 8; if (value & 0x80) { + gb->apu.channel_3_pulsed = true; /* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU reads from it. */ if (!GB_is_cgb(gb) && diff --git a/Core/apu.h b/Core/apu.h index 9c9afc87..ead4088a 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -122,6 +122,7 @@ typedef struct } noise_channel; + /* Todo: merge these into their structs when breaking save state compatibility */ #define GB_SKIP_DIV_EVENT_INACTIVE 0 #define GB_SKIP_DIV_EVENT_SKIPPED 1 #define GB_SKIP_DIV_EVENT_SKIP 2 @@ -136,6 +137,8 @@ typedef struct GB_envelope_clock_t square_envelope_clock[2]; GB_envelope_clock_t noise_envelope_clock; + bool channel_3_pulsed; + bool channel_3_delayed_bugged_read; } GB_apu_t; typedef enum { diff --git a/Core/gb.h b/Core/gb.h index 4ac977eb..ea4fe7d7 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -434,6 +434,7 @@ struct GB_gameboy_internal_s { int32_t ir_sensor; bool effective_ir_input; + uint16_t address_bus; ); /* DMA and HDMA */ diff --git a/Core/sm83_cpu.c b/Core/sm83_cpu.c index d709213b..a9180810 100644 --- a/Core/sm83_cpu.c +++ b/Core/sm83_cpu.c @@ -83,6 +83,7 @@ static uint8_t cycle_read(GB_gameboy_t *gb, uint16_t addr) if (gb->pending_cycles) { GB_advance_cycles(gb, gb->pending_cycles); } + gb->address_bus = addr; uint8_t ret = GB_read_memory(gb, addr); gb->pending_cycles = 4; return ret; @@ -93,10 +94,12 @@ static uint8_t cycle_read(GB_gameboy_t *gb, uint16_t addr) 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. */ +/* TODO: Does this affect the address bus? Verify. */ static uint8_t cycle_write_if(GB_gameboy_t *gb, uint8_t value) { assert(gb->pending_cycles); GB_advance_cycles(gb, gb->pending_cycles); + gb->address_bus = 0xFF00 + GB_IO_IF; uint8_t old = (gb->io_registers[GB_IO_IF]) & 0x1F; GB_write_memory(gb, 0xFF00 + GB_IO_IF, value); gb->pending_cycles = 4; @@ -125,19 +128,19 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, gb->pending_cycles); GB_write_memory(gb, addr, value); gb->pending_cycles = 4; - return; + break; case GB_CONFLICT_READ_NEW: GB_advance_cycles(gb, gb->pending_cycles - 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 5; - return; + break; case GB_CONFLICT_WRITE_CPU: GB_advance_cycles(gb, gb->pending_cycles + 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 3; - return; + break; /* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */ case GB_CONFLICT_STAT_DMG: @@ -155,7 +158,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 3; - return; + break; case GB_CONFLICT_STAT_CGB: { /* Todo: Verify this with SCX adjustments */ @@ -166,7 +169,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 3; - return; + break; } /* There is some "time travel" going on with these two values, as it appears @@ -181,14 +184,14 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 5; - return; + break; } case GB_CONFLICT_PALETTE_CGB: { GB_advance_cycles(gb, gb->pending_cycles - 2); GB_write_memory(gb, addr, value); gb->pending_cycles = 6; - return; + break; } case GB_CONFLICT_DMG_LCDC: { @@ -212,7 +215,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 5; - return; + break; } case GB_CONFLICT_SGB_LCDC: { @@ -226,7 +229,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); GB_write_memory(gb, addr, value); gb->pending_cycles = 5; - return; + break; } case GB_CONFLICT_WX: @@ -236,7 +239,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_advance_cycles(gb, 1); gb->wx_just_changed = false; gb->pending_cycles = 3; - return; + break; case GB_CONFLICT_CGB_LCDC: if ((value ^ gb->io_registers[GB_IO_LCDC]) & 0x10) { @@ -265,7 +268,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_write_memory(gb, addr, value); gb->pending_cycles = 4; } - return; + break; case GB_CONFLICT_NR10: /* Hack: Due to the coupling between DIV and the APU, GB_apu_run only runs at M-cycle @@ -285,9 +288,9 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) } GB_write_memory(gb, addr, value); gb->pending_cycles = 4; - return; - + break; } + gb->address_bus = addr; } static void cycle_no_access(GB_gameboy_t *gb) @@ -297,28 +300,20 @@ static void cycle_no_access(GB_gameboy_t *gb) static void cycle_oam_bug(GB_gameboy_t *gb, uint8_t register_id) { - if (GB_is_cgb(gb)) { - /* Slight optimization */ - gb->pending_cycles += 4; - return; - } if (gb->pending_cycles) { GB_advance_cycles(gb, gb->pending_cycles); } + gb->address_bus = gb->registers[register_id]; GB_trigger_oam_bug(gb, gb->registers[register_id]); /* Todo: test T-cycle timing */ gb->pending_cycles = 4; } static void cycle_oam_bug_pc(GB_gameboy_t *gb) { - if (GB_is_cgb(gb)) { - /* Slight optimization */ - gb->pending_cycles += 4; - return; - } if (gb->pending_cycles) { GB_advance_cycles(gb, gb->pending_cycles); } + gb->address_bus = gb->pc; GB_trigger_oam_bug(gb, gb->pc); /* Todo: test T-cycle timing */ gb->pending_cycles = 4; }