From c4ccbd5ccec2a5b30118e995fc6d2da5b9c9b907 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 23 Jun 2017 17:58:04 +0300 Subject: [PATCH] Improved serial interrupt timing, fixes boot_sclk_align. --- Core/gb.c | 2 ++ Core/gb.h | 4 +++- Core/memory.c | 6 ++++-- Core/timing.c | 11 +++++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Core/gb.c b/Core/gb.c index ec12b395..56697a1e 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -479,6 +479,8 @@ void GB_reset(GB_gameboy_t *gb) } gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF; } + /* The serial interrupt always occur on the 0xF8th cycle of every 0x100 cycle since boot. */ + gb->serial_cycles = 0x100 - 0xF8; gb->io_registers[GB_IO_SC] = 0x7E; gb->magic = (uintptr_t)'SAME'; } diff --git a/Core/gb.h b/Core/gb.h index 18df88f0..82608821 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -329,7 +329,9 @@ struct GB_gameboy_internal_s { uint32_t display_cycles; uint32_t div_cycles; uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ - uint16_t serial_cycles; + GB_PADDING(uint16_t, serial_cycles); + uint16_t serial_cycles; /* This field changed its meaning in v0.10 */ + uint16_t serial_length; ); /* APU */ diff --git a/Core/memory.c b/Core/memory.c index b913ba5a..c914e559 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -617,13 +617,15 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) } gb->io_registers[GB_IO_SC] = value | (~0x83); if ((value & 0x80) && (value & 0x1) ) { - gb->serial_cycles = gb->cgb_mode && (value & 2)? 128 : 4096; + gb->serial_length = gb->cgb_mode && (value & 2)? 128 : 4096; + /* Todo: This is probably incorrect for CGB's faster clock mode. */ + gb->serial_cycles &= 0xFF; if (gb->serial_transfer_start_callback) { gb->serial_transfer_start_callback(gb, gb->io_registers[GB_IO_SB]); } } else { - gb->serial_cycles = 0; + gb->serial_length = 0; } return; diff --git a/Core/timing.c b/Core/timing.c index 713f9b7c..77348fe2 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -107,9 +107,11 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) } } - if (gb->serial_cycles) { - if (gb->serial_cycles <= cycles) { - gb->serial_cycles = 0; + uint16_t previous_serial_cycles = gb->serial_cycles; + gb->serial_cycles += cycles; + if (gb->serial_length) { + if ((gb->serial_cycles & gb->serial_length) != (previous_serial_cycles & gb->serial_length)) { + gb->serial_length = 0; gb->io_registers[GB_IO_SC] &= ~0x80; /* TODO: Does SB "update" bit by bit? */ if (gb->serial_transfer_end_callback) { @@ -121,9 +123,6 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) gb->io_registers[GB_IO_IF] |= 8; } - else { - gb->serial_cycles -= cycles; - } } gb->debugger_ticks += cycles;