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)
{
@ -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;
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;
}
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 (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;
}
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;
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;
}
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;

View File

@ -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 {

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, " 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,

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 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 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 = MAX(ch4_rumble, 0.0);