More accurate channel 3 restarts

This commit is contained in:
Lior Halphon 2021-10-17 02:06:33 +03:00
parent f1b8164613
commit 7ef198ec50
4 changed files with 45 additions and 39 deletions

View File

@ -289,6 +289,19 @@ static void update_square_sample(GB_gameboy_t *gb, unsigned index)
0); 0);
} }
static inline void update_wave_sample(GB_gameboy_t *gb, unsigned cycles)
{
if (gb->apu.wave_channel.current_sample_index & 1) {
update_sample(gb, GB_WAVE,
(gb->apu.wave_channel.current_sample_byte & 0xF) >> gb->apu.wave_channel.shift,
cycles);
}
else {
update_sample(gb, GB_WAVE,
(gb->apu.wave_channel.current_sample_byte >> 4) >> gb->apu.wave_channel.shift,
cycles);
}
}
/* the effects of NRX2 writes on current volume are not well documented and differ /* the effects of NRX2 writes on current volume are not well documented and differ
between models and variants. The exact behavior can only be verified on CGB as it between models and variants. The exact behavior can only be verified on CGB as it
@ -665,11 +678,9 @@ void GB_apu_run(GB_gameboy_t *gb)
gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length ^ 0x7FF; gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length ^ 0x7FF;
gb->apu.wave_channel.current_sample_index++; gb->apu.wave_channel.current_sample_index++;
gb->apu.wave_channel.current_sample_index &= 0x1F; gb->apu.wave_channel.current_sample_index &= 0x1F;
gb->apu.wave_channel.current_sample = gb->apu.wave_channel.current_sample_byte =
gb->apu.wave_channel.wave_form[gb->apu.wave_channel.current_sample_index]; gb->io_registers[GB_IO_WAV_START + (gb->apu.wave_channel.current_sample_index >> 1)];
update_sample(gb, GB_WAVE, update_wave_sample(gb, cycles - cycles_left);
gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift,
cycles - cycles_left);
gb->apu.wave_channel.wave_form_just_read = true; gb->apu.wave_channel.wave_form_just_read = true;
} }
if (cycles_left) { if (cycles_left) {
@ -729,11 +740,6 @@ void GB_apu_run(GB_gameboy_t *gb)
void GB_apu_init(GB_gameboy_t *gb) void GB_apu_init(GB_gameboy_t *gb)
{ {
memset(&gb->apu, 0, sizeof(gb->apu)); memset(&gb->apu, 0, sizeof(gb->apu));
/* Restore the wave form */
for (unsigned reg = GB_IO_WAV_START; reg <= GB_IO_WAV_END; reg++) {
gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = gb->io_registers[reg] >> 4;
gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = gb->io_registers[reg] & 0xF;
}
gb->apu.lf_div = 1; gb->apu.lf_div = 1;
gb->apu.wave_channel.shift = 4; gb->apu.wave_channel.shift = 4;
/* APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode) is on, /* APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode) is on,
@ -1150,6 +1156,15 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
case GB_IO_NR30: case GB_IO_NR30:
gb->apu.wave_channel.enable = value & 0x80; gb->apu.wave_channel.enable = value & 0x80;
if (!gb->apu.wave_channel.enable) { if (!gb->apu.wave_channel.enable) {
if (gb->apu.is_active[GB_WAVE]) {
// Todo: I assume this happens on pre-CGB models; test this with an audible test
if (gb->apu.wave_channel.sample_countdown == 0 && gb->model < GB_MODEL_AGB) {
gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + 5]; // what the actual fuck? Why specifically this wave address ?
}
else if (gb->apu.wave_channel.wave_form_just_read && gb->model <= GB_MODEL_CGB_C) {
gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + 0xA]; // what the actual fuck? Why specifically this wave address?
}
}
gb->apu.is_active[GB_WAVE] = false; gb->apu.is_active[GB_WAVE] = false;
update_sample(gb, GB_WAVE, 0, 0); update_sample(gb, GB_WAVE, 0, 0);
} }
@ -1160,7 +1175,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
case GB_IO_NR32: case GB_IO_NR32:
gb->apu.wave_channel.shift = (uint8_t[]){4, 0, 1, 2}[(value >> 5) & 3]; gb->apu.wave_channel.shift = (uint8_t[]){4, 0, 1, 2}[(value >> 5) & 3];
if (gb->apu.is_active[GB_WAVE]) { if (gb->apu.is_active[GB_WAVE]) {
update_sample(gb, GB_WAVE, gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, 0); update_wave_sample(gb, 0);
} }
break; break;
case GB_IO_NR33: case GB_IO_NR33:
@ -1187,26 +1202,24 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
are all deterministic. */ are all deterministic. */
if (offset < 4) { if (offset < 4) {
gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset]; gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset];
gb->apu.wave_channel.wave_form[0] = gb->apu.wave_channel.wave_form[offset / 2];
gb->apu.wave_channel.wave_form[1] = gb->apu.wave_channel.wave_form[offset / 2 + 1];
} }
else { else {
memcpy(gb->io_registers + GB_IO_WAV_START, memcpy(gb->io_registers + GB_IO_WAV_START,
gb->io_registers + GB_IO_WAV_START + (offset & ~3), gb->io_registers + GB_IO_WAV_START + (offset & ~3),
4); 4);
memcpy(gb->apu.wave_channel.wave_form,
gb->apu.wave_channel.wave_form + (offset & ~3) * 2,
8);
} }
} }
if (!gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.enable) { gb->apu.wave_channel.current_sample_index = 0;
if (gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.sample_countdown == 0) {
gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START];
}
if (gb->apu.wave_channel.enable) {
gb->apu.is_active[GB_WAVE] = true; gb->apu.is_active[GB_WAVE] = true;
update_sample(gb, GB_WAVE, update_sample(gb, GB_WAVE,
gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, (gb->apu.wave_channel.current_sample_byte >> 4) >> gb->apu.wave_channel.shift,
0); 0);
} }
gb->apu.wave_channel.sample_countdown = (gb->apu.wave_channel.sample_length ^ 0x7FF) + 3; gb->apu.wave_channel.sample_countdown = (gb->apu.wave_channel.sample_length ^ 0x7FF) + 3;
gb->apu.wave_channel.current_sample_index = 0;
if (gb->apu.wave_channel.pulse_length == 0) { if (gb->apu.wave_channel.pulse_length == 0) {
gb->apu.wave_channel.pulse_length = 0x100; gb->apu.wave_channel.pulse_length = 0x100;
gb->apu.wave_channel.length_enabled = false; gb->apu.wave_channel.length_enabled = false;
@ -1396,12 +1409,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
gb->apu.noise_channel.length_enabled = value & 0x40; gb->apu.noise_channel.length_enabled = value & 0x40;
break; break;
} }
default:
if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END) {
gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = value >> 4;
gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = value & 0xF;
}
} }
gb->io_registers[reg] = value; gb->io_registers[reg] = value;
} }

View File

@ -99,9 +99,9 @@ typedef struct
uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF) uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF)
uint8_t current_sample_index; uint8_t current_sample_index;
uint8_t current_sample; // Current sample before shifting. uint8_t current_sample_byte; // Current sample byte.
int8_t wave_form[32]; GB_PADDING(int8_t, wave_form)[32];
bool wave_form_just_read; bool wave_form_just_read;
} wave_channel; } wave_channel;

View File

@ -1797,8 +1797,9 @@ static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
GB_log(gb, "\nCH3:\n"); GB_log(gb, "\nCH3:\n");
GB_log(gb, " Wave:"); GB_log(gb, " Wave:");
for (uint8_t i = 0; i < 32; i++) { for (uint8_t i = 0; i < 16; i++) {
GB_log(gb, "%s%X", i%4?"":" ", gb->apu.wave_channel.wave_form[i]); GB_log(gb, "%s%X", i % 2? "" : " ", gb->io_registers[GB_IO_WAV_START + i] >> 4);
GB_log(gb, "%s%X", i % 2? "" : " ", gb->io_registers[GB_IO_WAV_START + i] & 0xF);
} }
GB_log(gb, "\n"); GB_log(gb, "\n");
GB_log(gb, " Current position: %u\n", gb->apu.wave_channel.current_sample_index); GB_log(gb, " Current position: %u\n", gb->apu.wave_channel.current_sample_index);
@ -1880,11 +1881,14 @@ static bool wave(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug
for (int8_t cur_val = 0xf & mask; cur_val >= 0; cur_val -= shift_amount) { for (int8_t cur_val = 0xf & mask; cur_val >= 0; cur_val -= shift_amount) {
for (uint8_t i = 0; i < 32; i++) { for (uint8_t i = 0; i < 32; i++) {
if ((gb->apu.wave_channel.wave_form[i] & mask) == cur_val) { uint8_t sample = i & 1?
GB_log(gb, "%X", gb->apu.wave_channel.wave_form[i]); (gb->io_registers[GB_IO_WAV_START + i / 2] & 0xF) :
(gb->io_registers[GB_IO_WAV_START + i / 2] >> 4);
if ((sample & mask) == cur_val) {
GB_log(gb, "%X", sample);
} }
else { else {
GB_log(gb, "%c", i%4 == 2 ? '-' : ' '); GB_log(gb, "%c", i % 4 == 2 ? '-' : ' ');
} }
} }
GB_log(gb, "\n"); GB_log(gb, "\n");

View File

@ -1536,18 +1536,13 @@ static void reset_ram(GB_gameboy_t *gb)
case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */
case GB_MODEL_SGB2: case GB_MODEL_SGB2:
case GB_MODEL_SGB2_NO_SFC: { case GB_MODEL_SGB2_NO_SFC: {
uint8_t temp;
for (unsigned i = 0; i < GB_IO_WAV_END - GB_IO_WAV_START; i++) { for (unsigned i = 0; i < GB_IO_WAV_END - GB_IO_WAV_START; i++) {
if (i & 1) { if (i & 1) {
temp = GB_random() & GB_random() & GB_random(); gb->io_registers[GB_IO_WAV_START + i] = GB_random() & GB_random() & GB_random();
} }
else { else {
temp = GB_random() | GB_random() | GB_random(); gb->io_registers[GB_IO_WAV_START + i] = GB_random() | GB_random() | GB_random();
} }
gb->apu.wave_channel.wave_form[i * 2] = temp >> 4;
gb->apu.wave_channel.wave_form[i * 2 + 1] = temp & 0xF;
gb->io_registers[GB_IO_WAV_START + i] = temp;
} }
break; break;
} }