Redo channel 4's timing accurately, emulate NR43 write quirks

This commit is contained in:
Lior Halphon 2020-12-12 16:02:25 +02:00
parent 1baa0446a9
commit 7de6194e28
4 changed files with 93 additions and 55 deletions

View File

@ -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) void GB_apu_run(GB_gameboy_t *gb)
{ {
@ -507,38 +529,37 @@ void GB_apu_run(GB_gameboy_t *gb)
} }
} }
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; uint8_t cycles_left = cycles;
while (unlikely(cycles_left > gb->apu.noise_channel.sample_countdown)) { unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
cycles_left -= gb->apu.noise_channel.sample_countdown + 1; if (!divisor) divisor = 2;
gb->apu.noise_channel.sample_countdown = gb->apu.noise_channel.sample_length * 4 + 3; 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 */ /* Step LFSR */
unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000; if (new_bit && !old_bit) {
bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1; step_lfsr(gb, cycles - cycles_left);
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 (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) { if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) {
gb->apu.pcm_mask[1] &= 0x0F; 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) { 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: { case GB_IO_NR43: {
gb->apu.noise_channel.narrow = value & 8; gb->apu.noise_channel.narrow = value & 8;
unsigned divisor = (value & 0x07) << 1; bool old_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1;
if (!divisor) divisor = 1; gb->io_registers[GB_IO_NR43] = value;
gb->apu.noise_channel.sample_length = (divisor << (value >> 4)) - 1; bool new_bit = (gb->apu.noise_channel.counter >> (gb->io_registers[GB_IO_NR43] >> 4)) & 1;
if (gb->apu.channel_4_countdown_reloaded) {
/* Todo: changing the frequency sometimes delays the next sample. This is probably unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
due to how the frequency is actually calculated in the noise channel, which is probably if (!divisor) divisor = 2;
not by calculating the effective sample length and counting simiarly to the other channels. gb->apu.noise_channel.counter_countdown =
This is not emulated correctly. */ 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; break;
} }
case GB_IO_NR44: { case GB_IO_NR44: {
if (value & 0x80) { if (value & 0x80) {
gb->apu.noise_channel.sample_countdown = (gb->apu.noise_channel.sample_length) * 2 + 6 - gb->apu.lf_div; unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
if (!divisor) divisor = 2;
/* I'm COMPLETELY unsure about this logic, but it passes all relevant tests. gb->apu.channel_4_delta = 0;
See comment in NR43. */ gb->apu.noise_channel.counter_countdown = divisor + 4;
if ((gb->io_registers[GB_IO_NR43] & 7) && (gb->apu.noise_channel.alignment & 2) == 0) { if (divisor == 2) {
if ((gb->io_registers[GB_IO_NR43] & 7) == 1) { gb->apu.noise_channel.counter_countdown += 1 - gb->apu.lf_div;
gb->apu.noise_channel.sample_countdown += 2;
} }
else { else {
gb->apu.noise_channel.sample_countdown -= 2; 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;
} }
} }
if (gb->apu.is_active[GB_NOISE]) {
gb->apu.noise_channel.sample_countdown += 2;
} }
gb->apu.noise_channel.current_volume = gb->io_registers[GB_IO_NR42] >> 4; gb->apu.noise_channel.current_volume = gb->io_registers[GB_IO_NR42] >> 4;

View File

@ -105,8 +105,9 @@ typedef struct
uint16_t lfsr; uint16_t lfsr;
bool narrow; bool narrow;
uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length) uint8_t counter_countdown; // Counts from 0-7 to 0 to tick counter (Scaled from 512KHz to 2MHz)
uint16_t sample_length; // From NR43, in APU ticks uint8_t __padding;
uint16_t counter; // A bit from this 14-bit register ticks LFSR
bool length_enabled; // NR44 bool length_enabled; // NR44
uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of 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; bool current_lfsr_sample;
uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch
uint8_t channel_1_restart_hold; uint8_t channel_1_restart_hold;
int8_t channel_4_delta;
bool channel_4_countdown_reloaded;
} GB_apu_t; } GB_apu_t;
typedef enum { typedef enum {

View File

@ -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, "\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.current_volume,
gb->apu.noise_channel.sample_length * 4 + 3, gb->apu.noise_channel.counter,
gb->apu.noise_channel.sample_countdown); gb->apu.noise_channel.counter_countdown);
GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n", GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n",
gb->apu.noise_channel.volume_countdown, gb->apu.noise_channel.volume_countdown,

View File

@ -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 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 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)); unsigned ch1_volume = volume * (!!(gb->io_registers[GB_IO_NR51] & 1) + !!(gb->io_registers[GB_IO_NR51] & 0x10));
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(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; 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 = MIN(ch4_rumble, 1.0);
ch4_rumble = MAX(ch4_rumble, 0.0); ch4_rumble = MAX(ch4_rumble, 0.0);