Emulate the delayed NR44 write on the DMG
@@ -451,6 +451,22 @@ void GB_apu_run(GB_gameboy_t *gb)
uint8_t cycles = gb->apu.apu_cycles >> 2;
gb->apu.apu_cycles = 0;
if (!cycles) return;
+ bool start_ch4 = false;
+ if (gb->apu.channel_4_dmg_delayed_start) {
+ if (gb->apu.channel_4_dmg_delayed_start == cycles) {
+ gb->apu.channel_4_dmg_delayed_start = 0;
+ start_ch4 = true;
+ }
+ else if (gb->apu.channel_4_dmg_delayed_start > cycles) {
+ gb->apu.channel_4_dmg_delayed_start -= cycles;
+ }
+ else {
+ /* Split it into two */
+ cycles -= gb->apu.channel_4_dmg_delayed_start;
+ gb->apu.apu_cycles = gb->apu.channel_4_dmg_delayed_start * 2;
+ GB_apu_run(gb);
+ }
+ }
if (likely(!gb->stopped || GB_is_cgb(gb))) {
/* To align the square signal to 1MHz */
@@ -572,6 +588,9 @@ void GB_apu_run(GB_gameboy_t *gb)
render(gb);
}
}
+ if (start_ch4) {
+ GB_apu_write(gb, GB_IO_NR44, gb->io_registers[GB_IO_NR44] | 0x80);
+ }
}
void GB_apu_init(GB_gameboy_t *gb)
{
@@ -978,6 +997,10 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
case GB_IO_NR44: {
if (value & 0x80) {
+ if (!GB_is_cgb(gb) && (gb->apu.noise_channel.alignment & 3) != 0) {
+ gb->apu.channel_4_dmg_delayed_start = 6;
+ }
+ else {
unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
if (!divisor) divisor = 2;
gb->apu.channel_4_delta = 0;
@@ -1023,6 +1046,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
gb->apu.noise_channel.length_enabled = false;
}
}
+ }
/* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */
if ((value & 0x40) &&
