RTC speed multiplier, for TAS syncing (#422)

This commit is contained in:
Lior Halphon 2021-12-11 02:51:21 +02:00
parent a30247cf16
commit 7e5e672988
4 changed files with 36 additions and 21 deletions

View File

@ -1854,15 +1854,6 @@ unsigned GB_time_to_alarm(GB_gameboy_t *gb)
return alarm_time - current_time; return alarm_time - current_time;
} }
void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode)
{
if (gb->rtc_mode != mode) {
gb->rtc_mode = mode;
gb->rtc_cycles = 0;
gb->last_rtc_second = time(NULL);
}
}
bool GB_has_accelerometer(GB_gameboy_t *gb) bool GB_has_accelerometer(GB_gameboy_t *gb)
{ {
return gb->cartridge_type->mbc_type == GB_MBC7; return gb->cartridge_type->mbc_type == GB_MBC7;

View File

@ -247,11 +247,6 @@ typedef enum {
GB_BOOT_ROM_AGB, GB_BOOT_ROM_AGB,
} GB_boot_rom_t; } GB_boot_rom_t;
typedef enum {
GB_RTC_MODE_SYNC_TO_HOST,
GB_RTC_MODE_ACCURATE,
} GB_rtc_mode_t;
#ifdef GB_INTERNAL #ifdef GB_INTERNAL
#define LCDC_PERIOD 70224 #define LCDC_PERIOD 70224
#define CPU_FREQUENCY 0x400000 #define CPU_FREQUENCY 0x400000
@ -640,6 +635,7 @@ struct GB_gameboy_internal_s {
uint64_t last_sync; uint64_t last_sync;
uint64_t cycles_since_last_sync; // In 8MHz units uint64_t cycles_since_last_sync; // In 8MHz units
GB_rtc_mode_t rtc_mode; GB_rtc_mode_t rtc_mode;
uint32_t rtc_second_length;
/* Audio */ /* Audio */
GB_apu_output_t apu_output; GB_apu_output_t apu_output;
@ -862,9 +858,6 @@ void GB_disconnect_serial(GB_gameboy_t *gb);
/* For cartridges with an alarm clock */ /* For cartridges with an alarm clock */
unsigned GB_time_to_alarm(GB_gameboy_t *gb); // 0 if no alarm unsigned GB_time_to_alarm(GB_gameboy_t *gb); // 0 if no alarm
/* RTC emulation mode */
void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode);
/* For cartridges motion controls */ /* For cartridges motion controls */
bool GB_has_accelerometer(GB_gameboy_t *gb); bool GB_has_accelerometer(GB_gameboy_t *gb);
// In units of g (gravity's acceleration). // In units of g (gravity's acceleration).

View File

@ -248,11 +248,32 @@ static void advance_serial(GB_gameboy_t *gb, uint8_t cycles)
} }
void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode)
{
if (gb->rtc_mode != mode) {
gb->rtc_mode = mode;
gb->rtc_cycles = 0;
gb->last_rtc_second = time(NULL);
}
}
void GB_set_rtc_multiplier(GB_gameboy_t *gb, double multiplier)
{
if (multiplier == 1) {
gb->rtc_second_length = 0;
return;
}
gb->rtc_second_length = GB_get_unmultiplied_clock_rate(gb) * 2 * multiplier;
}
static void rtc_run(GB_gameboy_t *gb, uint8_t cycles) static void rtc_run(GB_gameboy_t *gb, uint8_t cycles)
{ {
if (gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc) return; if (gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc) return;
gb->rtc_cycles += cycles; gb->rtc_cycles += cycles;
time_t current_time = 0; 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) { switch (gb->rtc_mode) {
case GB_RTC_MODE_SYNC_TO_HOST: case GB_RTC_MODE_SYNC_TO_HOST:
@ -266,8 +287,8 @@ static void rtc_run(GB_gameboy_t *gb, uint8_t cycles)
gb->rtc_cycles -= cycles; gb->rtc_cycles -= cycles;
return; return;
} }
if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) * 2) return; if (gb->rtc_cycles < rtc_second_length) return;
gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) * 2; gb->rtc_cycles -= rtc_second_length;
current_time = gb->last_rtc_second + 1; current_time = gb->last_rtc_second + 1;
break; break;
} }

View File

@ -2,13 +2,23 @@
#define timing_h #define timing_h
#include "defs.h" #include "defs.h"
typedef enum {
GB_RTC_MODE_SYNC_TO_HOST,
GB_RTC_MODE_ACCURATE,
} GB_rtc_mode_t;
/* RTC emulation mode */
void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode);
/* Speed multiplier for the RTC, mostly for TAS syncing */
void GB_set_rtc_multiplier(GB_gameboy_t *gb, double multiplier);
#ifdef GB_INTERNAL #ifdef GB_INTERNAL
internal void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles); internal void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles);
internal void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac); internal void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac);
internal bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */ internal bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */
internal void GB_timing_sync(GB_gameboy_t *gb); 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_set_internal_div_counter(GB_gameboy_t *gb, uint16_t value);
enum { enum {
GB_TIMA_RUNNING = 0, GB_TIMA_RUNNING = 0,
GB_TIMA_RELOADING = 1, GB_TIMA_RELOADING = 1,