From 0f98ac5ff9740f5652adc640cc5124502d4c1a65 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 6 Aug 2016 13:56:29 +0300 Subject: [PATCH] Emulate TIMA reloading --- Core/gb.h | 7 +++++++ Core/memory.c | 21 ++++++++++++++++++--- Core/timing.c | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Core/gb.h b/Core/gb.h index 52890cf6..aa8a62d0 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -193,6 +193,12 @@ struct GB_watchpoint_s; /* Todo: We might want to typedef our own bool if this prevents SameBoy from working on specific platforms. */ _Static_assert(sizeof(bool) == 1, "sizeof(bool) != 1"); +enum { + GB_TIMA_RUNNING = 0, + GB_TIMA_RELOADING = 1, + GB_TIMA_RELOADED = 2 +}; + typedef struct GB_gameboy_s { GB_SECTION(header, /* The magic makes sure a state file is: @@ -287,6 +293,7 @@ typedef struct GB_gameboy_s { GB_PADDING(uint32_t, tima_cycles); GB_PADDING(uint32_t, dma_cycles); GB_aligned_double apu_cycles; + uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ ); /* APU */ diff --git a/Core/memory.c b/Core/memory.c index e4fb9a88..1038f38a 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -147,7 +147,6 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) /* Fall through */ case GB_IO_JOYP: case GB_IO_DIV: - case GB_IO_TIMA: case GB_IO_TMA: case GB_IO_LCDC: case GB_IO_SCY: @@ -161,6 +160,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) case GB_IO_WX: case GB_IO_SB: return gb->io_registers[addr & 0xFF]; + case GB_IO_TIMA: + if (gb->tima_reload_state == GB_TIMA_RELOADING) { + return 0; + } + return gb->io_registers[GB_IO_TIMA]; case GB_IO_HDMA5: if (!gb->is_cgb) { return 0xFF; @@ -356,8 +360,6 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) case GB_IO_SCX: case GB_IO_IF: - case GB_IO_TIMA: - case GB_IO_TMA: case GB_IO_SCY: case GB_IO_LYC: case GB_IO_BGP: @@ -373,6 +375,19 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) case GB_IO_DMG_EMULATION_INDICATION: gb->io_registers[addr & 0xFF] = value; return; + + case GB_IO_TIMA: + if (gb->tima_reload_state != GB_TIMA_RELOADED) { + gb->io_registers[GB_IO_TIMA] = value; + } + return; + + case GB_IO_TMA: + gb->io_registers[GB_IO_TMA] = value; + if (gb->tima_reload_state == GB_TIMA_RELOADED) { + gb->io_registers[GB_IO_TIMA] = value; + } + return; case GB_IO_TAC: GB_emulate_timer_glitch(gb, gb->io_registers[GB_IO_TAC], value); diff --git a/Core/timing.c b/Core/timing.c index 4b15da1c..48f28dcf 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -14,15 +14,33 @@ static void GB_ir_run(GB_gameboy_t *gb) } } +static void advance_tima_state_machine(GB_gameboy_t *gb) +{ + if (gb->tima_reload_state == GB_TIMA_RELOADED) { + gb->tima_reload_state = GB_TIMA_RUNNING; + } + else if (gb->tima_reload_state == GB_TIMA_RELOADING) { + gb->tima_reload_state = GB_TIMA_RELOADED; + } +} + void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) { // Affected by speed boost gb->dma_cycles += cycles; + advance_tima_state_machine(gb); for (int i = 0; i < cycles; i += 4) { GB_set_internal_div_counter(gb, gb->div_cycles + 4); } + if (cycles > 4) { + advance_tima_state_machine(gb); + if (cycles > 8) { + advance_tima_state_machine(gb); + } + } + if (gb->cgb_double_speed) { cycles >>=1; } @@ -49,6 +67,7 @@ static void increase_tima(GB_gameboy_t *gb) if (gb->io_registers[GB_IO_TIMA] == 0) { gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA]; gb->io_registers[GB_IO_IF] |= 4; + gb->tima_reload_state = GB_TIMA_RELOADING; } }