Further accuracy improvements to sweep; passes Blargg's APU tests again, this time for real

This commit is contained in:
Lior Halphon 2020-12-01 14:17:35 +02:00
parent 0485124076
commit 74cf452a48
4 changed files with 47 additions and 45 deletions

View File

@ -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) void GB_apu_div_event(GB_gameboy_t *gb)
{ {
if (!gb->apu.global_enable) return; 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.div_divider & 3) == 3) {
if (gb->apu.square_sweep_countdown) { gb->apu.square_sweep_countdown++;
if (!--gb->apu.square_sweep_countdown && gb->apu.sweep_enabled) { gb->apu.square_sweep_countdown &= 7;
if ((gb->io_registers[GB_IO_NR10] & 0x70) && (gb->io_registers[GB_IO_NR10] & 0x07)) { trigger_sweep_calculation(gb);
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;
}
}
} }
} }
@ -433,7 +433,8 @@ void GB_apu_run(GB_gameboy_t *gb)
gb->apu.lf_div ^= cycles & 1; gb->apu.lf_div ^= cycles & 1;
gb->apu.noise_channel.alignment += cycles; 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) { if (gb->apu.square_sweep_calculate_countdown > cycles) {
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; break;
/* Square channels */ /* Square channels */
case GB_IO_NR10: case GB_IO_NR10:{
if (gb->apu.shadow_sweep_sample_length + gb->apu.sweep_length_addend > 0x7FF && !(gb->io_registers[GB_IO_NR10] & 8)) { 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; gb->apu.is_active[GB_SQUARE_1] = false;
update_sample(gb, GB_SQUARE_1, 0, 0); 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; break;
}
case GB_IO_NR11: case GB_IO_NR11:
case GB_IO_NR21: { 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 &= 0xFF;
gb->apu.square_channels[index].sample_length |= (value & 7) << 8; gb->apu.square_channels[index].sample_length |= (value & 7) << 8;
if (value & 0x80) { 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 /* Current sample index remains unchanged when restarting channels 1 or 2. It is only reset by
turning the APU off. */ turning the APU off. */
if (!gb->apu.is_active[index]) { 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 (index == GB_SQUARE_1) {
if (gb->io_registers[GB_IO_NR10] & 7) { if (gb->io_registers[GB_IO_NR10] & 7) {
/* APU bug: if shift is nonzero, overflow check also occurs on trigger */ /* 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.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); gb->apu.sweep_length_addend >>= (gb->io_registers[GB_IO_NR10] & 7);
} }
else { 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); gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7) ^ 7;
if (!gb->apu.square_sweep_countdown) gb->apu.square_sweep_countdown = 8;
} }
} }
/* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */ /* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */

View File

@ -66,7 +66,7 @@ typedef struct
uint8_t square_sweep_calculate_countdown; // In 2 MHz uint8_t square_sweep_calculate_countdown; // In 2 MHz
uint16_t sweep_length_addend; uint16_t sweep_length_addend;
uint16_t shadow_sweep_sample_length; uint16_t shadow_sweep_sample_length;
bool sweep_enabled; GB_PADDING(bool, sweep_enabled);
GB_PADDING(bool, sweep_decreasing); GB_PADDING(bool, sweep_decreasing);
struct { struct {

View File

@ -1778,11 +1778,18 @@ static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
gb->apu.square_channels[channel].current_sample_index >> 7 ? " (suppressed)" : ""); gb->apu.square_channels[channel].current_sample_index >> 7 ? " (suppressed)" : "");
if (channel == GB_SQUARE_1) { if (channel == GB_SQUARE_1) {
GB_log(gb, " Frequency sweep %s and %s (next in %u APU ticks)\n", GB_log(gb, " Frequency sweep %s and %s\n",
gb->apu.sweep_enabled? "active" : "inactive", ((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", (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); 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) { if (gb->apu.square_channels[channel].length_enabled) {
GB_log(gb, " Channel will end in %u 256 Hz ticks\n", GB_log(gb, " Channel will end in %u 256 Hz ticks\n",

View File

@ -32,7 +32,7 @@ void GB_handle_rumble(GB_gameboy_t *gb)
ch4_rumble = MAX(ch4_rumble, 0.0); ch4_rumble = MAX(ch4_rumble, 0.0);
double ch1_rumble = 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); 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 = 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); ch1_rumble = MIN(ch1_rumble, 1.0);