diff --git a/Core/gb.c b/Core/gb.c index ec12b39..56697a1 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 18df88f..8260882 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 b913ba5..c914e55 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 713f9b7..77348fe 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;