From 7de6194e28771d1231d4ca1618f82c5977ab1514 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 12 Dec 2020 16:02:25 +0200 Subject: [PATCH] Redo channel 4's timing accurately, emulate NR43 write quirks --- Core/apu.c | 127 ++++++++++++++++++++++++++++++------------------ Core/apu.h | 8 ++- Core/debugger.c | 6 +-- Core/rumble.c | 7 ++- 4 files changed, 93 insertions(+), 55 deletions(-) diff --git a/Core/apu.c b/Core/apu.c index 4366fb2a..d689515b 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -422,6 +422,28 @@ void GB_apu_div_event(GB_gameboy_t *gb) } } +static void step_lfsr(GB_gameboy_t *gb, unsigned cycles_offset) +{ + unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000; + bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1; + gb->apu.noise_channel.lfsr >>= 1; + + if (new_high_bit) { + gb->apu.noise_channel.lfsr |= high_bit_mask; + } + else { + /* This code is not redundent, it's relevant when switching LFSR widths */ + gb->apu.noise_channel.lfsr &= ~high_bit_mask; + } + + gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1; + if (gb->apu.is_active[GB_NOISE]) { + update_sample(gb, GB_NOISE, + gb->apu.current_lfsr_sample ? + gb->apu.noise_channel.current_volume : 0, + cycles_offset); + } +} void GB_apu_run(GB_gameboy_t *gb) { @@ -506,39 +528,38 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.wave_channel.wave_form_just_read = false; } } - - if (gb->apu.is_active[GB_NOISE]) { + + // The noise channel can step even if inactive on the DMG + if (gb->apu.is_active[GB_NOISE] || !GB_is_cgb(gb)) { uint8_t cycles_left = cycles; - while (unlikely(cycles_left > gb->apu.noise_channel.sample_countdown)) { - cycles_left -= gb->apu.noise_channel.sample_countdown + 1; - gb->apu.noise_channel.sample_countdown = gb->apu.noise_channel.sample_length * 4 + 3; + unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2; + if (!divisor) divisor = 2; + if (gb->apu.noise_channel.counter_countdown == 0) { + gb->apu.noise_channel.counter_countdown = divisor; + } + while (unlikely(cycles_left >= gb->apu.noise_channel.counter_countdown)) { + cycles_left -= gb->apu.noise_channel.counter_countdown; + gb->apu.noise_channel.counter_countdown = divisor + gb->apu.channel_4_delta; + gb->apu.channel_4_delta = 0; + bool old_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1; + gb->apu.noise_channel.counter++; + gb->apu.noise_channel.counter &= 0x3FFF; + bool new_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1; /* Step LFSR */ - unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000; - bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1; - gb->apu.noise_channel.lfsr >>= 1; - - if (new_high_bit) { - gb->apu.noise_channel.lfsr |= high_bit_mask; + if (new_bit && !old_bit) { + step_lfsr(gb, cycles - cycles_left); + if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) { + gb->apu.pcm_mask[1] &= 0x0F; + } } - else { - /* This code is not redundent, it's relevant when switching LFSR widths */ - gb->apu.noise_channel.lfsr &= ~high_bit_mask; - } - - gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1; - - if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) { - gb->apu.pcm_mask[1] &= 0x0F; - } - - update_sample(gb, GB_NOISE, - gb->apu.current_lfsr_sample ? - gb->apu.noise_channel.current_volume : 0, - 0); } if (cycles_left) { - gb->apu.noise_channel.sample_countdown -= cycles_left; + gb->apu.noise_channel.counter_countdown -= cycles_left; + gb->apu.channel_4_countdown_reloaded = false; + } + else { + gb->apu.channel_4_countdown_reloaded = true; } } } @@ -938,33 +959,43 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) case GB_IO_NR43: { gb->apu.noise_channel.narrow = value & 8; - unsigned divisor = (value & 0x07) << 1; - if (!divisor) divisor = 1; - gb->apu.noise_channel.sample_length = (divisor << (value >> 4)) - 1; - - /* Todo: changing the frequency sometimes delays the next sample. This is probably - due to how the frequency is actually calculated in the noise channel, which is probably - not by calculating the effective sample length and counting simiarly to the other channels. - This is not emulated correctly. */ + bool old_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1; + gb->io_registers[GB_IO_NR43] = value; + bool new_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1; + if (gb->apu.channel_4_countdown_reloaded) { + unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2; + if (!divisor) divisor = 2; + gb->apu.noise_channel.counter_countdown = + divisor + (divisor == 2? 0 : (uint8_t[]){2, 1, 0, 3}[(gb->apu.noise_channel.alignment) & 3]); + gb->apu.channel_4_delta = 0; + } + /* Step LFSR */ + if (new_bit && !old_bit) { + step_lfsr(gb, 0); + } break; } case GB_IO_NR44: { if (value & 0x80) { - gb->apu.noise_channel.sample_countdown = (gb->apu.noise_channel.sample_length) * 2 + 6 - gb->apu.lf_div; - - /* I'm COMPLETELY unsure about this logic, but it passes all relevant tests. - See comment in NR43. */ - if ((gb->io_registers[GB_IO_NR43] & 7) && (gb->apu.noise_channel.alignment & 2) == 0) { - if ((gb->io_registers[GB_IO_NR43] & 7) == 1) { - gb->apu.noise_channel.sample_countdown += 2; - } - else { - gb->apu.noise_channel.sample_countdown -= 2; - } + unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2; + if (!divisor) divisor = 2; + gb->apu.channel_4_delta = 0; + gb->apu.noise_channel.counter_countdown = divisor + 4; + if (divisor == 2) { + gb->apu.noise_channel.counter_countdown += 1 - gb->apu.lf_div; } - if (gb->apu.is_active[GB_NOISE]) { - gb->apu.noise_channel.sample_countdown += 2; + else { + gb->apu.noise_channel.counter_countdown += (uint8_t[]){2, 1, 0, 3}[gb->apu.noise_channel.alignment & 3]; + if (((gb->apu.noise_channel.alignment + 1) & 3) < 2) { + if ((gb->io_registers[GB_IO_NR43] & 0x07) == 1) { + gb->apu.noise_channel.counter_countdown -= 2; + gb->apu.channel_4_delta = 2; + } + else { + gb->apu.noise_channel.counter_countdown -= 4; + } + } } gb->apu.noise_channel.current_volume = gb->io_registers[GB_IO_NR42] >> 4; diff --git a/Core/apu.h b/Core/apu.h index 07182c96..df1be405 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -105,8 +105,9 @@ typedef struct uint16_t lfsr; bool narrow; - uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length) - uint16_t sample_length; // From NR43, in APU ticks + uint8_t counter_countdown; // Counts from 0-7 to 0 to tick counter (Scaled from 512KHz to 2MHz) + uint8_t __padding; + uint16_t counter; // A bit from this 14-bit register ticks LFSR bool length_enabled; // NR44 uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of @@ -121,6 +122,9 @@ typedef struct bool current_lfsr_sample; uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch uint8_t channel_1_restart_hold; + int8_t channel_4_delta; + bool channel_4_countdown_reloaded; + } GB_apu_t; typedef enum { diff --git a/Core/debugger.c b/Core/debugger.c index 9825d95d..e62fd51e 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1821,10 +1821,10 @@ static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg GB_log(gb, "\nCH4:\n"); - GB_log(gb, " Current volume: %u, current sample length: %u APU ticks (next in %u ticks)\n", + GB_log(gb, " Current volume: %u, current internal counter: 0x%x (next increase in %u ticks)\n", gb->apu.noise_channel.current_volume, - gb->apu.noise_channel.sample_length * 4 + 3, - gb->apu.noise_channel.sample_countdown); + gb->apu.noise_channel.counter, + gb->apu.noise_channel.counter_countdown); GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n", gb->apu.noise_channel.volume_countdown, diff --git a/Core/rumble.c b/Core/rumble.c index 22321fb8..87eb8703 100644 --- a/Core/rumble.c +++ b/Core/rumble.c @@ -25,8 +25,11 @@ void GB_handle_rumble(GB_gameboy_t *gb) unsigned volume = (gb->io_registers[GB_IO_NR50] & 7) + 1 + ((gb->io_registers[GB_IO_NR50] >> 4) & 7) + 1; unsigned ch4_volume = volume * (!!(gb->io_registers[GB_IO_NR51] & 8) + !!(gb->io_registers[GB_IO_NR51] & 0x80)); unsigned ch1_volume = volume * (!!(gb->io_registers[GB_IO_NR51] & 1) + !!(gb->io_registers[GB_IO_NR51] & 0x10)); - - double ch4_rumble = (MIN(gb->apu.noise_channel.sample_length * (gb->apu.noise_channel.narrow? 8 : 1) , 4096) * ((signed) gb->apu.noise_channel.current_volume * gb->apu.noise_channel.current_volume * ch4_volume / 32.0 - 50) - 2048) / 2048.0; + unsigned ch4_divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 1; + if (!ch4_divisor) ch4_divisor = 1; + unsigned ch4_sample_length = (ch4_divisor << (gb->io_registers[GB_IO_NR43] >> 4)) - 1; + + double ch4_rumble = (MIN(ch4_sample_length * (gb->apu.noise_channel.narrow? 8 : 1) , 4096) * ((signed) gb->apu.noise_channel.current_volume * gb->apu.noise_channel.current_volume * ch4_volume / 32.0 - 50) - 2048) / 2048.0; ch4_rumble = MIN(ch4_rumble, 1.0); ch4_rumble = MAX(ch4_rumble, 0.0);