From 74cf452a48d7ad6676b2e5f5580bf8e47b2178de Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 1 Dec 2020 14:17:35 +0200 Subject: [PATCH] Further accuracy improvements to sweep; passes Blargg's APU tests again, this time for real --- Core/apu.c | 73 +++++++++++++++++++++++-------------------------- Core/apu.h | 2 +- Core/debugger.c | 15 +++++++--- Core/rumble.c | 2 +- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/Core/apu.c b/Core/apu.c index 9275f81..c568d08 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -329,6 +329,24 @@ static void tick_noise_envelope(GB_gameboy_t *gb) } } +static void trigger_sweep_calculation(GB_gameboy_t *gb) +{ + if ((gb->io_registers[GB_IO_NR10] & 0x70) && gb->apu.square_sweep_countdown == 7) { + if (gb->io_registers[GB_IO_NR10] & 0x07) { + gb->apu.square_channels[GB_SQUARE_1].sample_length = + gb->apu.sweep_length_addend + gb->apu.shadow_sweep_sample_length + !!(gb->io_registers[GB_IO_NR10] & 0x8); + gb->apu.square_channels[GB_SQUARE_1].sample_length &= 0x7FF; + } + gb->apu.sweep_length_addend = gb->apu.square_channels[GB_SQUARE_1].sample_length; + gb->apu.sweep_length_addend >>= (gb->io_registers[GB_IO_NR10] & 7); + + /* Recalculation and overflow check only occurs after a delay */ + gb->apu.square_sweep_calculate_countdown = (gb->io_registers[GB_IO_NR10] & 0x7) * 2 + 7 - gb->apu.lf_div; + + gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7) ^ 7; + } +} + void GB_apu_div_event(GB_gameboy_t *gb) { if (!gb->apu.global_enable) return; @@ -396,27 +414,9 @@ void GB_apu_div_event(GB_gameboy_t *gb) } if ((gb->apu.div_divider & 3) == 3) { - if (gb->apu.square_sweep_countdown) { - if (!--gb->apu.square_sweep_countdown && gb->apu.sweep_enabled) { - if ((gb->io_registers[GB_IO_NR10] & 0x70) && (gb->io_registers[GB_IO_NR10] & 0x07)) { - gb->apu.square_channels[GB_SQUARE_1].sample_length = - gb->apu.sweep_length_addend + gb->apu.shadow_sweep_sample_length + !!(gb->io_registers[GB_IO_NR10] & 0x8); - gb->apu.square_channels[GB_SQUARE_1].sample_length &= 0x7FF; - } - gb->apu.sweep_length_addend = gb->apu.square_channels[GB_SQUARE_1].sample_length; - gb->apu.sweep_length_addend >>= (gb->io_registers[GB_IO_NR10] & 7); - - if (gb->io_registers[GB_IO_NR10] & 0x70) { - /* Recalculation and overflow check only occurs after a delay */ - gb->apu.square_sweep_calculate_countdown = (gb->io_registers[GB_IO_NR10] & 0x7) * 2 + 7 - gb->apu.lf_div; - } - - gb->apu.sweep_enabled = gb->io_registers[GB_IO_NR10] & 0x70; - - gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7); - if (!gb->apu.square_sweep_countdown) gb->apu.square_sweep_countdown = 8; - } - } + gb->apu.square_sweep_countdown++; + gb->apu.square_sweep_countdown &= 7; + trigger_sweep_calculation(gb); } } @@ -433,7 +433,8 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.lf_div ^= cycles & 1; gb->apu.noise_channel.alignment += cycles; - if (gb->apu.square_sweep_calculate_countdown) { + if (gb->apu.square_sweep_calculate_countdown && + ((gb->io_registers[GB_IO_NR10] & 7) || gb->apu.square_sweep_calculate_countdown <= 7)) { // Calculation is paused if the lower bits if (gb->apu.square_sweep_calculate_countdown > cycles) { gb->apu.square_sweep_calculate_countdown -= cycles; } @@ -664,18 +665,16 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) break; /* Square channels */ - case GB_IO_NR10: - if (gb->apu.shadow_sweep_sample_length + gb->apu.sweep_length_addend > 0x7FF && !(gb->io_registers[GB_IO_NR10] & 8)) { + case GB_IO_NR10:{ + bool old_negate = gb->io_registers[GB_IO_NR10] & 8; + gb->io_registers[GB_IO_NR10] = value; + if (gb->apu.shadow_sweep_sample_length + gb->apu.sweep_length_addend + old_negate > 0x7FF && !(value & 8)) { gb->apu.is_active[GB_SQUARE_1] = false; update_sample(gb, GB_SQUARE_1, 0, 0); - gb->apu.square_sweep_calculate_countdown = 0; - } - if ((value & 0x70) == 0) { - /* Todo: what happens if we set period to 0 while a calculate event is scheduled, and then - re-set it to non-zero? */ - gb->apu.square_sweep_calculate_countdown = 0; } + trigger_sweep_calculation(gb); break; + } case GB_IO_NR11: case GB_IO_NR21: { @@ -737,11 +736,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) gb->apu.square_channels[index].sample_length &= 0xFF; gb->apu.square_channels[index].sample_length |= (value & 7) << 8; if (value & 0x80) { - if (index == GB_SQUARE_1) { - gb->apu.sweep_length_addend = gb->apu.square_channels[GB_SQUARE_1].sample_length; - gb->apu.shadow_sweep_sample_length = 0; - gb->apu.sweep_enabled = gb->io_registers[GB_IO_NR10] & 0x70; - } /* Current sample index remains unchanged when restarting channels 1 or 2. It is only reset by turning the APU off. */ if (!gb->apu.is_active[index]) { @@ -776,16 +770,17 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) if (index == GB_SQUARE_1) { if (gb->io_registers[GB_IO_NR10] & 7) { /* APU bug: if shift is nonzero, overflow check also occurs on trigger */ + gb->apu.shadow_sweep_sample_length = gb->apu.square_channels[GB_SQUARE_1].sample_length; gb->apu.square_sweep_calculate_countdown = (gb->io_registers[GB_IO_NR10] & 0x7) * 2 + 7 - gb->apu.lf_div; + gb->apu.sweep_length_addend = gb->apu.square_channels[GB_SQUARE_1].sample_length; gb->apu.sweep_length_addend >>= (gb->io_registers[GB_IO_NR10] & 7); } else { - gb->apu.square_sweep_calculate_countdown = 0; + gb->apu.shadow_sweep_sample_length = 0; + gb->apu.sweep_length_addend = 0; } - gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7); - if (!gb->apu.square_sweep_countdown) gb->apu.square_sweep_countdown = 8; + gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7) ^ 7; } - } /* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */ diff --git a/Core/apu.h b/Core/apu.h index 0512723..a8b5697 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -66,7 +66,7 @@ typedef struct uint8_t square_sweep_calculate_countdown; // In 2 MHz uint16_t sweep_length_addend; uint16_t shadow_sweep_sample_length; - bool sweep_enabled; + GB_PADDING(bool, sweep_enabled); GB_PADDING(bool, sweep_decreasing); struct { diff --git a/Core/debugger.c b/Core/debugger.c index 28db01c..9825d95 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1778,10 +1778,17 @@ static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg gb->apu.square_channels[channel].current_sample_index >> 7 ? " (suppressed)" : ""); if (channel == GB_SQUARE_1) { - GB_log(gb, " Frequency sweep %s and %s (next in %u APU ticks)\n", - gb->apu.sweep_enabled? "active" : "inactive", - (gb->io_registers[GB_IO_NR10] & 0x8) ? "decreasing" : "increasing", - gb->apu.square_sweep_calculate_countdown); + GB_log(gb, " Frequency sweep %s and %s\n", + ((gb->io_registers[GB_IO_NR10] & 0x7) && (gb->io_registers[GB_IO_NR10] & 0x70))? "active" : "inactive", + (gb->io_registers[GB_IO_NR10] & 0x8) ? "decreasing" : "increasing"); + if (gb->apu.square_sweep_calculate_countdown) { + GB_log(gb, " On going frequency calculation will be ready in %u APU ticks\n", + gb->apu.square_sweep_calculate_countdown); + } + else { + GB_log(gb, " Shadow frequency register: 0x%03x\n", gb->apu.shadow_sweep_sample_length); + GB_log(gb, " Sweep addend register: 0x%03x\n", gb->apu.sweep_length_addend); + } } if (gb->apu.square_channels[channel].length_enabled) { diff --git a/Core/rumble.c b/Core/rumble.c index 8cbe20d..22321fb 100644 --- a/Core/rumble.c +++ b/Core/rumble.c @@ -32,7 +32,7 @@ void GB_handle_rumble(GB_gameboy_t *gb) ch4_rumble = MAX(ch4_rumble, 0.0); double ch1_rumble = 0; - if (gb->apu.sweep_enabled && ((gb->io_registers[GB_IO_NR10] >> 4) & 7)) { + if ((gb->io_registers[GB_IO_NR10] & 0x7) && (gb->io_registers[GB_IO_NR10] & 0x70)) { double sweep_speed = (gb->io_registers[GB_IO_NR10] & 7) / (double)((gb->io_registers[GB_IO_NR10] >> 4) & 7); ch1_rumble = gb->apu.square_channels[GB_SQUARE_1].current_volume * ch1_volume / 32.0 * sweep_speed / 8.0 - 0.5; ch1_rumble = MIN(ch1_rumble, 1.0);