CGB-C NR10 conflict improvements

This commit is contained in:
Lior Halphon
2023-09-25 23:35:26 +03:00
parent 340d4e0630
commit e59bc436bd
3 changed files with 53 additions and 59 deletions

View File

@@ -477,8 +477,7 @@ static void trigger_sweep_calculation(GB_gameboy_t *gb)
/* Recalculation and overflow check only occurs after a delay */
gb->apu.square_sweep_calculate_countdown = gb->io_registers[GB_IO_NR10] & 0x7;
gb->apu.square_sweep_calculate_countdown_reload_timer = 2 + (gb->model <= GB_MODEL_CGB_C);
gb->apu.square_sweep_stop_calc_if_no_zombie_write = false;
gb->apu.square_sweep_calculate_countdown_reload_timer = 2;
gb->apu.unshifted_sweep = !(gb->io_registers[GB_IO_NR10] & 0x7);
gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7) ^ 7;
}
@@ -690,23 +689,26 @@ void GB_apu_run(GB_gameboy_t *gb, bool force)
if ((cycles & 1) && !gb->apu.lf_div) {
sweep_cycles++;
}
if (gb->apu.square_sweep_calculate_countdown_reload_timer == 0 && !gb->cgb_double_speed) {
gb->apu.square_sweep_calculate_countdown = 0;
}
gb->apu.square_sweep_countdown_just_reloaded = false;
if (gb->apu.square_sweep_calculate_countdown_reload_timer > sweep_cycles) {
gb->apu.square_sweep_calculate_countdown_reload_timer -= sweep_cycles;
sweep_cycles = 0;
}
else {
if (gb->apu.square_sweep_calculate_countdown_reload_timer && !gb->apu.square_sweep_calculate_countdown) {
if (gb->apu.square_sweep_calculate_countdown_reload_timer && !gb->apu.square_sweep_calculate_countdown && gb->model > GB_MODEL_CGB_C) {
sweep_calculation_done(gb, cycles);
}
gb->apu.square_sweep_countdown_just_reloaded = gb->apu.square_sweep_calculate_countdown_reload_timer == sweep_cycles && sweep_cycles;
sweep_cycles -= gb->apu.square_sweep_calculate_countdown_reload_timer;
gb->apu.square_sweep_calculate_countdown_reload_timer = 0;
if (gb->apu.square_sweep_stop_calc_if_no_zombie_write) {
gb->apu.square_sweep_stop_calc_if_no_zombie_write = 0;
gb->apu.square_sweep_calculate_countdown = 0;
}
}
if (gb->apu.square_sweep_calculate_countdown &&
!gb->apu_output.square_sweep_disable_stepping &&
(((gb->io_registers[GB_IO_NR10] & 7) || gb->apu.unshifted_sweep) ||
gb->apu.square_sweep_calculate_countdown <= 1)) { // Calculation is paused if the lower bits are 0
if (gb->apu.square_sweep_calculate_countdown > sweep_cycles) {
@@ -714,7 +716,6 @@ void GB_apu_run(GB_gameboy_t *gb, bool force)
}
else {
sweep_calculation_done(gb, cycles);
gb->apu.square_sweep_calculate_countdown = 0;
}
}
@@ -1103,50 +1104,38 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
case GB_IO_NR10: {
bool old_negate = gb->io_registers[GB_IO_NR10] & 8;
// TODO: Check all of these in APU odd mode
if (gb->apu.square_sweep_calculate_countdown_reload_timer || gb->apu.square_sweep_countdown_just_reloaded) {
GB_log(gb, "%04x: Glitch NR10 write at %d.%d (%d, %d)\n", gb->de, gb->apu.square_sweep_calculate_countdown, gb->apu.lf_div, gb->apu.square_sweep_calculate_countdown_reload_timer, gb->apu.square_sweep_countdown_just_reloaded);
}
if (gb->model <= GB_MODEL_CGB_C) {
bool zombie_tick = !(gb->io_registers[GB_IO_NR10] & 7) &&
(gb->apu.lf_div ^ gb->cgb_double_speed) &&
gb->apu.square_sweep_calculate_countdown &&
!gb->apu.square_sweep_calculate_countdown_reload_timer;
gb->apu.square_sweep_stop_calc_if_no_zombie_write = false;
if (zombie_tick) {
gb->apu.square_sweep_calculate_countdown--;
if (!gb->apu.square_sweep_calculate_countdown) {
sweep_calculation_done(gb, 0);
if (gb->apu.square_sweep_calculate_countdown_reload_timer) {
if (gb->cgb_double_speed) {
// TODO: How does this affect actual frequency calculation?
gb->apu.square_sweep_calculate_countdown = value & 7;
}
}
switch (gb->apu.square_sweep_calculate_countdown_reload_timer) {
case 1: {
if (!gb->apu.lf_div) {
/* This is some instance-specific data corruption. It might also be affect by revision.
At least for my CGB-0 (haven't tested any other CGB-0s), the '3' case is non-deterministic. */
static const uint8_t corruption[8] = {0, 7, 5, 7, 3, 3, 5, 7}; // Two of my CGB-Cs, CGB-A
// static const uint8_t corruption[8] = {0, 7, 1, 3, 3, 3, 5, 7}; // My other CGB-C
// static const uint8_t corruption[8] = {0, 1, 1, 3, 3, 5, 5, 7}; // My CGB-B
// static const uint8_t corruption[8] = {0, 7, 1, *, 3, 3, 5, 7}; // My CGB-0
// TODO: How does this affect actual frequency calculation?
gb->apu.square_sweep_calculate_countdown = corruption[gb->apu.square_sweep_calculate_countdown & 7];
gb->apu.square_sweep_calculate_countdown_reload_timer = 0;
else if (gb->apu.square_sweep_countdown_just_reloaded) {
GB_log(gb, "%04x: Glitch NR10 write at %d.%d (%d, %d)\n", gb->de, gb->apu.square_sweep_calculate_countdown, gb->apu.lf_div, gb->apu.square_sweep_calculate_countdown_reload_timer, gb->apu.square_sweep_countdown_just_reloaded);
/* This is some instance-specific data corruption. It might also be affect by revision.
At least for my CGB-0 (haven't tested any other CGB-0s), the '3' case is non-deterministic. */
static const uint8_t corruption[8] = {7, 7, 5, 7, 3, 3, 5, 7}; // Two of my CGB-Cs, CGB-A
// static const uint8_t corruption[8] = {7, 7, 1, 3, 3, 3, 5, 7}; // My other CGB-C
// static const uint8_t corruption[8] = {7, 1, 1, 3, 3, 5, 5, 7}; // My CGB-B
// static const uint8_t corruption[8] = {7, 7, 1, *, 3, 3, 5, 7}; // My CGB-0
// TODO: How does this affect actual frequency calculation?
gb->apu.square_sweep_calculate_countdown = corruption[gb->apu.square_sweep_calculate_countdown & 7];
}
else {
if (!(gb->io_registers[GB_IO_NR10] & 7) &&
(gb->apu.lf_div ^ gb->cgb_double_speed) &&
gb->apu.square_sweep_calculate_countdown) {
gb->apu.square_sweep_calculate_countdown--;
if (!gb->apu.square_sweep_calculate_countdown) {
sweep_calculation_done(gb, 0);
}
break;
}
case 2:
if (gb->apu.lf_div) {
// TODO: How does this affect actual frequency calculation?
gb->apu.square_sweep_calculate_countdown = value & 7; // TODO: Confirm for non-zero?
gb->apu.square_sweep_calculate_countdown_reload_timer = 0;
}
else {
case 3:
// Countdown just reloaded, re-reload it with glitch value (FF & 7)
gb->apu.square_sweep_calculate_countdown = 7;
gb->apu.square_sweep_stop_calc_if_no_zombie_write = true;
}
break;
default:;
}
}
else {
@@ -1255,10 +1244,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
}
gb->apu.square_channels[index].delay = 6 - gb->apu.lf_div;
gb->apu.square_channels[index].sample_countdown = (gb->apu.square_channels[index].sample_length ^ 0x7FF) * 2 + gb->apu.square_channels[index].delay;
if (gb->model <= GB_MODEL_CGB_C && gb->apu.lf_div) {
gb->apu.square_channels[index].sample_countdown += 2;
gb->apu.square_channels[index].delay += 2;
}
}
else {
unsigned extra_delay = 0;
@@ -1278,10 +1263,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
/* Timing quirk: if already active, sound starts 2 (2MHz) ticks earlier.*/
gb->apu.square_channels[index].delay = 4 - gb->apu.lf_div + extra_delay;
gb->apu.square_channels[index].sample_countdown = (gb->apu.square_channels[index].sample_length ^ 0x7FF) * 2 + gb->apu.square_channels[index].delay;
if (gb->model <= GB_MODEL_CGB_C && gb->apu.lf_div) {
gb->apu.square_channels[index].sample_countdown += 2;
gb->apu.square_channels[index].delay += 2;
}
}
gb->apu.square_channels[index].current_volume = gb->io_registers[index == GB_SQUARE_1 ? GB_IO_NR12 : GB_IO_NR22] >> 4;
/* The volume changes caused by NRX4 sound start take effect instantly (i.e. the effect the previously
@@ -1306,11 +1287,10 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
if (index == GB_SQUARE_1) {
gb->apu.shadow_sweep_sample_length = 0;
gb->apu.channel1_completed_addend = 0;
gb->apu.square_sweep_stop_calc_if_no_zombie_write = false;
if (gb->io_registers[GB_IO_NR10] & 7) {
/* APU bug: if shift is nonzero, overflow check also occurs on trigger */
gb->apu.square_sweep_calculate_countdown = gb->io_registers[GB_IO_NR10] & 0x7;
gb->apu.square_sweep_calculate_countdown_reload_timer = 2 + (gb->model <= GB_MODEL_CGB_C);
gb->apu.square_sweep_calculate_countdown_reload_timer = 2;
gb->apu.unshifted_sweep = false;
if (!was_active) {
gb->apu.square_sweep_calculate_countdown_reload_timer++;

View File

@@ -75,8 +75,8 @@ typedef struct
uint16_t sweep_length_addend;
uint16_t shadow_sweep_sample_length;
bool unshifted_sweep;
bool square_sweep_stop_calc_if_no_zombie_write;
bool square_sweep_countdown_just_reloaded;
uint8_t channel_1_restart_hold;
uint16_t channel1_completed_addend;
struct {
@@ -177,6 +177,8 @@ typedef struct {
GB_audio_format_t output_format;
int output_error;
/* Not output related, but it's temp state so I'll put it here */
bool square_sweep_disable_stepping;
} GB_apu_output_t;
void GB_set_channel_muted(GB_gameboy_t *gb, GB_channel_t channel, bool muted);

View File

@@ -25,6 +25,7 @@ typedef enum {
GB_CONFLICT_SCX_CGB,
GB_CONFLICT_LCDC_CGB_DOUBLE,
GB_CONFLICT_STAT_CGB_DOUBLE,
GB_CONFLICT_NR10_CGB_DOUBLE,
} conflict_t;
static const conflict_t cgb_conflict_map[0x80] = {
@@ -43,6 +44,7 @@ static const conflict_t cgb_double_conflict_map[0x80] = {
[GB_IO_IF] = GB_CONFLICT_WRITE_CPU,
[GB_IO_LYC] = GB_CONFLICT_READ_OLD,
[GB_IO_STAT] = GB_CONFLICT_STAT_CGB_DOUBLE,
[GB_IO_NR10] = GB_CONFLICT_NR10_CGB_DOUBLE,
// Unconfirmed yet
[GB_IO_SCX] = GB_CONFLICT_SCX_CGB,
};
@@ -327,6 +329,16 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->pending_cycles = 4;
}
break;
case GB_CONFLICT_NR10_CGB_DOUBLE: {
GB_advance_cycles(gb, gb->pending_cycles - 1);
gb->apu_output.square_sweep_disable_stepping = gb->model <= GB_MODEL_CGB_C && (value & 7) == 0;
GB_advance_cycles(gb, 1);
gb->apu_output.square_sweep_disable_stepping = false;
GB_write_memory(gb, addr, value);
gb->pending_cycles = 4;
break;
}
}
gb->address_bus = addr;
}