git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

commit 048da6e6d16fed2fecdf7e94142a78320e630134
parent 4ab256d896755cb101f3721d7231a5d98f3ee8f5
Author: Lior Halphon <LIJI32@gmail.com>
Date:   Sat, 29 Jul 2023 22:27:50 +0300

Fixed a bug where accurate RTC emulation halted while SameBoy wasn't running

Diffstat:
MCore/gb.c4++++
MCore/timing.c136+++++++++++++++++++++++++++++++++++++++++--------------------------------------
MCore/timing.h2+-
3 files changed, 76 insertions(+), 66 deletions(-)

diff --git a/Core/gb.c b/Core/gb.c @@ -1040,7 +1040,9 @@ void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t really RTC data. */ goto reset_rtc; } + GB_rtc_set_time(gb, time(NULL)); goto exit; + reset_rtc: gb->last_rtc_second = time(NULL); gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */ @@ -1150,7 +1152,9 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path) really RTC data. */ goto reset_rtc; } + GB_rtc_set_time(gb, time(NULL)); goto exit; + reset_rtc: gb->last_rtc_second = time(NULL); gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */ diff --git a/Core/timing.c b/Core/timing.c @@ -282,31 +282,8 @@ void GB_set_rtc_multiplier(GB_gameboy_t *gb, double multiplier) gb->rtc_second_length = GB_get_unmultiplied_clock_rate(gb) * 2 * multiplier; } -static void rtc_run(GB_gameboy_t *gb, uint8_t cycles) +void GB_rtc_set_time(GB_gameboy_t *gb, uint64_t current_time) { - if (likely(gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc)) return; - gb->rtc_cycles += cycles; - time_t current_time = 0; - uint32_t rtc_second_length = unlikely(gb->rtc_second_length)? gb->rtc_second_length : GB_get_unmultiplied_clock_rate(gb) * 2; - - switch (gb->rtc_mode) { - case GB_RTC_MODE_SYNC_TO_HOST: - // Sync in a 1/32s resolution - if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) / 16) return; - gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) / 16; - current_time = time(NULL); - break; - case GB_RTC_MODE_ACCURATE: - if (gb->cartridge_type->mbc_type != GB_HUC3 && (gb->rtc_real.high & 0x40)) { - gb->rtc_cycles -= cycles; - return; - } - if (gb->rtc_cycles < rtc_second_length) return; - gb->rtc_cycles -= rtc_second_length; - current_time = gb->last_rtc_second + 1; - break; - } - if (gb->cartridge_type->mbc_type == GB_HUC3) { while (gb->last_rtc_second / 60 < current_time / 60) { gb->last_rtc_second += 60; @@ -318,6 +295,7 @@ static void rtc_run(GB_gameboy_t *gb, uint8_t cycles) } return; } + bool running = false; if (gb->cartridge_type->mbc_type == GB_TPP1) { running = gb->tpp1_mr4 & 0x4; @@ -326,59 +304,87 @@ static void rtc_run(GB_gameboy_t *gb, uint8_t cycles) running = (gb->rtc_real.high & 0x40) == 0; } - if (running) { /* is timer running? */ - while (gb->last_rtc_second + 60 * 60 * 24 < current_time) { - gb->last_rtc_second += 60 * 60 * 24; - if (gb->cartridge_type->mbc_type == GB_TPP1) { - if (++gb->rtc_real.tpp1.weekday == 7) { - gb->rtc_real.tpp1.weekday = 0; - if (++gb->rtc_real.tpp1.weeks == 0) { - gb->tpp1_mr4 |= 8; /* Overflow bit */ - } + if (!running) return; + + while (gb->last_rtc_second + 60 * 60 * 24 < current_time) { + gb->last_rtc_second += 60 * 60 * 24; + if (gb->cartridge_type->mbc_type == GB_TPP1) { + if (++gb->rtc_real.tpp1.weekday == 7) { + gb->rtc_real.tpp1.weekday = 0; + if (++gb->rtc_real.tpp1.weeks == 0) { + gb->tpp1_mr4 |= 8; /* Overflow bit */ } } - else if (++gb->rtc_real.days == 0) { - if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ - gb->rtc_real.high |= 0x80; /* Overflow bit */ - } - - gb->rtc_real.high ^= 1; + } + else if (++gb->rtc_real.days == 0) { + if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ + gb->rtc_real.high |= 0x80; /* Overflow bit */ } + + gb->rtc_real.high ^= 1; } + } + + while (gb->last_rtc_second < current_time) { + gb->last_rtc_second++; + if (++gb->rtc_real.seconds != 60) continue; + gb->rtc_real.seconds = 0; + + if (++gb->rtc_real.minutes != 60) continue; + gb->rtc_real.minutes = 0; - while (gb->last_rtc_second < current_time) { - gb->last_rtc_second++; - if (++gb->rtc_real.seconds != 60) continue; - gb->rtc_real.seconds = 0; + if (gb->cartridge_type->mbc_type == GB_TPP1) { + if (++gb->rtc_real.tpp1.hours != 24) continue; + gb->rtc_real.tpp1.hours = 0; + if (++gb->rtc_real.tpp1.weekday != 7) continue; + gb->rtc_real.tpp1.weekday = 0; + if (++gb->rtc_real.tpp1.weeks == 0) { + gb->tpp1_mr4 |= 8; /* Overflow bit */ + } + } + else { + if (++gb->rtc_real.hours != 24) continue; + gb->rtc_real.hours = 0; - if (++gb->rtc_real.minutes != 60) continue; - gb->rtc_real.minutes = 0; + if (++gb->rtc_real.days != 0) continue; - if (gb->cartridge_type->mbc_type == GB_TPP1) { - if (++gb->rtc_real.tpp1.hours != 24) continue; - gb->rtc_real.tpp1.hours = 0; - if (++gb->rtc_real.tpp1.weekday != 7) continue; - gb->rtc_real.tpp1.weekday = 0; - if (++gb->rtc_real.tpp1.weeks == 0) { - gb->tpp1_mr4 |= 8; /* Overflow bit */ - } - } - else { - if (++gb->rtc_real.hours != 24) continue; - gb->rtc_real.hours = 0; - - if (++gb->rtc_real.days != 0) continue; - - if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ - gb->rtc_real.high |= 0x80; /* Overflow bit */ - } - - gb->rtc_real.high ^= 1; + if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ + gb->rtc_real.high |= 0x80; /* Overflow bit */ } + + gb->rtc_real.high ^= 1; } } } +static void rtc_run(GB_gameboy_t *gb, uint8_t cycles) +{ + if (likely(gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc)) return; + gb->rtc_cycles += cycles; + time_t current_time = 0; + uint32_t rtc_second_length = unlikely(gb->rtc_second_length)? gb->rtc_second_length : GB_get_unmultiplied_clock_rate(gb) * 2; + + switch (gb->rtc_mode) { + case GB_RTC_MODE_SYNC_TO_HOST: + // Sync in a 1/32s resolution + if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) / 16) return; + gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) / 16; + current_time = time(NULL); + break; + case GB_RTC_MODE_ACCURATE: + if (gb->cartridge_type->mbc_type != GB_HUC3 && (gb->rtc_real.high & 0x40)) { + gb->rtc_cycles -= cycles; + return; + } + if (gb->rtc_cycles < rtc_second_length) return; + gb->rtc_cycles -= rtc_second_length; + current_time = gb->last_rtc_second + 1; + break; + } + + GB_rtc_set_time(gb, current_time); +} + static void camera_run(GB_gameboy_t *gb, uint8_t cycles) { /* Do we have a camera? */ diff --git a/Core/timing.h b/Core/timing.h @@ -20,7 +20,7 @@ internal bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should internal void GB_timing_sync(GB_gameboy_t *gb); internal void GB_set_internal_div_counter(GB_gameboy_t *gb, uint16_t value); internal void GB_serial_master_edge(GB_gameboy_t *gb); - +internal void GB_rtc_set_time(GB_gameboy_t *gb, uint64_t time); #define GB_SLEEP(gb, unit, state, cycles) do {\ (gb)->unit##_cycles -= (cycles) * __state_machine_divisor; \

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.