diff --git a/Core/debugger.c b/Core/debugger.c index 371a8652..6d4deb4d 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1606,8 +1606,12 @@ static bool ticks(GB_gameboy_t *gb, char *arguments, char *modifiers, const debu return true; } - GB_log(gb, "Ticks: %llu. (Resetting)\n", (unsigned long long)gb->debugger_ticks); + GB_log(gb, "T-cycles: %llu\n", (unsigned long long)gb->debugger_ticks); + GB_log(gb, "M-cycles: %llu\n", (unsigned long long)gb->debugger_ticks / 4); + GB_log(gb, "Absolute 8MHz ticks: %llu\n", (unsigned long long)gb->absolute_debugger_ticks); + GB_log(gb, "Tick count reset.\n"); gb->debugger_ticks = 0; + gb->absolute_debugger_ticks = 0; return true; } diff --git a/Core/gb.h b/Core/gb.h index f29f914a..80465dfb 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -532,6 +532,7 @@ struct GB_gameboy_internal_s { uint8_t double_speed_alignment; uint8_t serial_count; int32_t speed_switch_halt_countdown; + uint8_t speed_switch_countdown; // To compensate for the lack of pipeline emulation uint8_t speed_switch_freeze; // Solely for realigning the PPU, should be removed when the odd modes are implemented ); @@ -718,6 +719,7 @@ struct GB_gameboy_internal_s { /* Ticks command */ uint64_t debugger_ticks; + uint64_t absolute_debugger_ticks; /* Undo */ uint8_t *undo_state; diff --git a/Core/sm83_cpu.c b/Core/sm83_cpu.c index 0388e4f3..20e7691d 100644 --- a/Core/sm83_cpu.c +++ b/Core/sm83_cpu.c @@ -374,6 +374,7 @@ static void leave_stop_mode(GB_gameboy_t *gb) gb->cgb_palettes_ppu_blocked = false; } +/* TODO: Speed switch timing needs far more tests. Double to single is wrong to avoid odd mode. */ static void stop(GB_gameboy_t *gb, uint8_t opcode) { flush_pending_cycles(gb); @@ -387,29 +388,39 @@ static void stop(GB_gameboy_t *gb, uint8_t opcode) } if (!interrupt_pending) { - /* Todo: is PC being actually read? */ cycle_read_inc_oam_bug(gb, gb->pc++); } - /* Todo: speed switching takes a fractional number of M-cycles. It make - every active component (APU, PPU) unaligned with the CPU. */ + /* Todo: speed switching takes 2 extra T-cycles (so 2 PPU ticks in single->double and 1 PPU tick in double->single) */ if (speed_switch) { flush_pending_cycles(gb); - if (gb->io_registers[GB_IO_LCDC] & 0x80) { - GB_log(gb, "ROM triggered PPU odd mode, which is currently not supported. Reverting to even-mode.\n"); + if (gb->io_registers[GB_IO_LCDC] & 0x80 && gb->cgb_double_speed) { + GB_log(gb, "ROM triggered a PPU odd mode, which is currently not supported. Reverting to even-mode.\n"); if (gb->double_speed_alignment & 7) { - gb->speed_switch_freeze = 6; - } - else { - gb->speed_switch_freeze = 4; + gb->speed_switch_freeze = 2; } } + if (gb->apu.global_enable && gb->cgb_double_speed) { + GB_log(gb, "ROM triggered an APU odd mode, which is currently not tested.\n"); + } + + if (gb->cgb_double_speed) { + gb->cgb_double_speed = false; + } + else { + gb->speed_switch_countdown = 6; + gb->speed_switch_freeze = 1; + } + + if (interrupt_pending) { + } + else { + gb->speed_switch_halt_countdown = 0x20008; + gb->speed_switch_freeze = 5; + } - gb->cgb_double_speed ^= true; gb->io_registers[GB_IO_KEY1] = 0; - - gb->speed_switch_halt_countdown = 0x20008; } if (immediate_exit) { diff --git a/Core/timing.c b/Core/timing.c index 69b301a1..a755ac52 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -346,6 +346,22 @@ static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles) void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) { + if (gb->speed_switch_countdown) { + if (gb->speed_switch_countdown == cycles) { + gb->cgb_double_speed ^= true; + gb->speed_switch_countdown = 0; + } + else if (gb->speed_switch_countdown > cycles) { + gb->speed_switch_countdown -= cycles; + } + else { + uint8_t old_cycles = gb->speed_switch_countdown; + cycles -= old_cycles; + gb->speed_switch_countdown = 0; + GB_advance_cycles(gb, old_cycles); + gb->cgb_double_speed ^= true; + } + } gb->apu.pcm_mask[0] = gb->apu.pcm_mask[1] = 0xFF; // Sort of hacky, but too many cross-component interactions to do it right // Affected by speed boost gb->dma_cycles += cycles; @@ -378,6 +394,8 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) cycles <<= 1; } + gb->absolute_debugger_ticks += cycles; + // Not affected by speed boost if (gb->io_registers[GB_IO_LCDC] & 0x80) { gb->double_speed_alignment += cycles;