mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-03 09:52:49 +02:00
CGB-C NR10 conflict improvements
This commit is contained in:
94
Core/apu.c
94
Core/apu.c
@@ -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++;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user