From 4bbd27735fb6d12ba95deb10437214b2172aeec3 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 25 Dec 2020 20:40:39 +0200 Subject: [PATCH] Fix a regression in speed switch timing, reset DIV on speed switch, better odd-mode detection and avoidance --- Core/memory.c | 1 + Core/sm83_cpu.c | 16 ++++++++-------- Core/timing.c | 8 ++++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Core/memory.c b/Core/memory.c index 40af0e5..cff31b6 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -895,6 +895,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) { gb->display_cycles = 0; gb->display_state = 0; + gb->double_speed_alignment = 0; if (GB_is_sgb(gb)) { gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; } diff --git a/Core/sm83_cpu.c b/Core/sm83_cpu.c index e423fba..e56040b 100644 --- a/Core/sm83_cpu.c +++ b/Core/sm83_cpu.c @@ -332,6 +332,7 @@ static void nop(GB_gameboy_t *gb, uint8_t opcode) static void enter_stop_mode(GB_gameboy_t *gb) { + GB_write_memory(gb, 0xFF00 + GB_IO_DIV, 0); gb->stopped = true; gb->oam_ppu_blocked = !gb->oam_read_blocked; gb->vram_ppu_blocked = !gb->vram_read_blocked; @@ -340,30 +341,30 @@ static void enter_stop_mode(GB_gameboy_t *gb) static void leave_stop_mode(GB_gameboy_t *gb) { - /* The CPU takes more time to wake up then the other components */ - for (unsigned i = 0x200; i--;) { - GB_advance_cycles(gb, 0x10); - } gb->stopped = false; gb->oam_ppu_blocked = false; gb->vram_ppu_blocked = false; gb->cgb_palettes_ppu_blocked = false; + /* The CPU takes more time to wake up then the other components */ + for (unsigned i = 0x2000; i--;) { + GB_advance_cycles(gb, 0x10); + } + GB_write_memory(gb, 0xFF00 + GB_IO_DIV, 0); } static void stop(GB_gameboy_t *gb, uint8_t opcode) { if (gb->io_registers[GB_IO_KEY1] & 0x1) { - if (gb->cgb_double_speed && gb->io_registers[GB_IO_LCDC] & 0x80) { - GB_log(gb, "Returning from double speed mode while the PPU is on may trigger odd-mode\n"); - } flush_pending_cycles(gb); bool needs_alignment = false; GB_advance_cycles(gb, 0x4); /* Make sure we keep the CPU ticks aligned correctly when returning from double speed mode */ + if (gb->double_speed_alignment & 7) { GB_advance_cycles(gb, 0x4); needs_alignment = true; + GB_log(gb, "ROM triggered PPU odd mode, which is currently not supported. Reverting to even-mode.\n"); } gb->cgb_double_speed ^= true; @@ -388,7 +389,6 @@ static void stop(GB_gameboy_t *gb, uint8_t opcode) enter_stop_mode(gb); } } - /* Todo: is PC being actually read? */ gb->pc++; } diff --git a/Core/timing.c b/Core/timing.c index 44ff8f7..7009d7b 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -157,7 +157,9 @@ static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value) static void GB_timers_run(GB_gameboy_t *gb, uint8_t cycles) { if (gb->stopped) { - gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; + if (GB_is_cgb(gb)) { + gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; + } return; } @@ -248,7 +250,9 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) } // Not affected by speed boost - gb->double_speed_alignment += cycles; + if (gb->io_registers[GB_IO_LCDC] & 0x80) { + gb->double_speed_alignment += cycles; + } gb->hdma_cycles += cycles; gb->apu_output.sample_cycles += cycles; gb->cycles_since_last_sync += cycles;