Further accuracy improvements to sweep; passes Blargg's APU tests again, this time for real
This commit is contained in:
parent
0485124076
commit
74cf452a48
73
Core/apu.c
73
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)
|
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. */
|
||||||
|
@ -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 {
|
||||||
|
@ -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",
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user