git.y1.nz

SameBoy

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

Core/timing.c

      1 #include "gb.h"
      2 #ifdef _WIN32
      3 #ifndef _WIN32_WINNT
      4 #define _WIN32_WINNT 0x0500
      5 #endif
      6 #include <windows.h>
      7 #else
      8 #include <sys/time.h>
      9 #endif
     10 
     11 static const unsigned TAC_TRIGGER_BITS[] = {512, 8, 32, 128};
     12 
     13 #ifndef GB_DISABLE_TIMEKEEPING
     14 static int64_t get_nanoseconds(void)
     15 {
     16 #ifndef _WIN32
     17     struct timeval now;
     18     gettimeofday(&now, NULL);
     19     return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
     20 #else
     21     FILETIME time;
     22     GetSystemTimeAsFileTime(&time);
     23     return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L;
     24 #endif
     25 }
     26 
     27 static void nsleep(uint64_t nanoseconds)
     28 {
     29 #ifndef _WIN32
     30     struct timespec sleep = {0, nanoseconds};
     31     nanosleep(&sleep, NULL);
     32 #else
     33     HANDLE timer;
     34     LARGE_INTEGER time;
     35     timer = CreateWaitableTimer(NULL, true, NULL);
     36     time.QuadPart = -(nanoseconds / 100L);
     37     SetWaitableTimer(timer, &time, 0, NULL, NULL, false);
     38     WaitForSingleObject(timer, INFINITE);
     39     CloseHandle(timer);
     40 #endif
     41 }
     42 
     43 bool GB_timing_sync_turbo(GB_gameboy_t *gb)
     44 {
     45 #ifndef GB_DISABLE_DEBUGGER
     46     if (unlikely(gb->backstep_instructions)) return false;
     47 #endif
     48     if (!gb->turbo_dont_skip) {
     49         int64_t nanoseconds = get_nanoseconds();
     50         if (nanoseconds <= gb->last_render + 1000000000 / 60) {
     51             return true;
     52         }
     53         gb->last_render = nanoseconds;
     54     }
     55     return false;
     56 }
     57 
     58 void GB_timing_sync(GB_gameboy_t *gb)
     59 {
     60 #ifndef GB_DISABLE_DEBUGGER
     61     if (unlikely(gb->backstep_instructions)) return;
     62 #endif
     63     /* Prevent syncing if not enough time has passed.*/
     64     if (gb->cycles_since_last_sync < LCDC_PERIOD / 3) return;
     65 
     66     unsigned target_clock_rate;
     67     if (gb->turbo) {
     68         if (gb->turbo_cap_multiplier) {
     69             target_clock_rate = GB_get_clock_rate(gb) * gb->turbo_cap_multiplier;
     70         }
     71         else {
     72             gb->cycles_since_last_sync = 0;
     73             if (gb->update_input_hint_callback) {
     74                 gb->update_input_hint_callback(gb);
     75             }
     76             return;
     77         }
     78     }
     79     else {
     80         target_clock_rate = GB_get_clock_rate(gb);
     81     }
     82     
     83     uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / 2 / target_clock_rate; /* / 2 because we use 8MHz units */
     84     int64_t nanoseconds = get_nanoseconds();
     85     int64_t time_to_sleep = target_nanoseconds + gb->last_sync - nanoseconds;
     86     if (time_to_sleep > 0 && time_to_sleep < LCDC_PERIOD * 1200000000LL / target_clock_rate) { // +20% to be more forgiving
     87         nsleep(time_to_sleep);
     88         gb->last_sync += target_nanoseconds;
     89     }
     90     else {
     91         if (time_to_sleep < 0 && -time_to_sleep < LCDC_PERIOD * 1200000000LL / target_clock_rate) {
     92             // We're running a bit too slow, but the difference is small enough,
     93             // just skip this sync and let it even out
     94             return;
     95         }
     96         gb->last_sync = nanoseconds;
     97     }
     98 
     99     gb->cycles_since_last_sync = 0;
    100     if (gb->update_input_hint_callback) {
    101         gb->update_input_hint_callback(gb);
    102     }
    103 }
    104 #else
    105 
    106 bool GB_timing_sync_turbo(GB_gameboy_t *gb)
    107 {
    108     return false;
    109 }
    110 
    111 void GB_timing_sync(GB_gameboy_t *gb)
    112 {
    113 #ifndef GB_DISABLE_DEBUGGER
    114     if (unlikely(gb->backstep_instructions)) return;
    115 #endif
    116     if (gb->cycles_since_last_sync < LCDC_PERIOD / 3) return;
    117     gb->cycles_since_last_sync = 0;
    118 
    119     gb->cycles_since_last_sync = 0;
    120     if (gb->update_input_hint_callback) {
    121         gb->update_input_hint_callback(gb);
    122     }
    123     return;
    124 }
    125 
    126 #endif
    127 
    128 #define IR_DECAY 31500
    129 #define IR_WARMUP 19900
    130 #define IR_THRESHOLD 240
    131 #define IR_MAX IR_THRESHOLD * 2 + IR_DECAY + 268
    132 
    133 static void ir_run(GB_gameboy_t *gb, uint32_t cycles)
    134 {
    135     /* TODO: the way this thing works makes the CGB IR port behave inaccurately when used together with HUC1/3 IR ports*/
    136     if ((gb->model > GB_MODEL_CGB_E || !gb->cgb_mode) && gb->cartridge_type->mbc_type != GB_HUC1 && gb->cartridge_type->mbc_type != GB_HUC3) return;
    137     bool is_sensing = (gb->io_registers[GB_IO_RP] & 0xC0) == 0xC0 ||
    138                        (gb->cartridge_type->mbc_type == GB_HUC1 && gb->huc1.ir_mode) ||
    139                        (gb->cartridge_type->mbc_type == GB_HUC3 && gb->huc3.mode == 0xE);
    140     if (is_sensing && (gb->infrared_input || gb->cart_ir || (gb->io_registers[GB_IO_RP] & 1))) {
    141         gb->ir_sensor += cycles;
    142         if (gb->ir_sensor > IR_MAX) {
    143             gb->ir_sensor = IR_MAX;
    144         }
    145         
    146         gb->effective_ir_input = gb->ir_sensor >=  IR_WARMUP + IR_THRESHOLD && gb->ir_sensor <= IR_WARMUP + IR_THRESHOLD + IR_DECAY;
    147     }
    148     else {
    149         unsigned target = is_sensing? IR_WARMUP : 0;
    150         if (gb->ir_sensor < target) {
    151             gb->ir_sensor += cycles;
    152         }
    153         else if (gb->ir_sensor <= target + cycles) {
    154             gb->ir_sensor = target;
    155         }
    156         else {
    157             gb->ir_sensor -= cycles;
    158         }
    159         gb->effective_ir_input = false;
    160     }
    161     
    162 }
    163 
    164 static void advance_tima_state_machine(GB_gameboy_t *gb)
    165 {
    166     if (gb->tima_reload_state == GB_TIMA_RELOADED) {
    167         gb->tima_reload_state = GB_TIMA_RUNNING;
    168     }
    169     else if (gb->tima_reload_state == GB_TIMA_RELOADING) {
    170         gb->io_registers[GB_IO_IF] |= 4;
    171         gb->tima_reload_state = GB_TIMA_RELOADED;
    172     }
    173 }
    174 
    175 static void increase_tima(GB_gameboy_t *gb)
    176 {
    177     gb->io_registers[GB_IO_TIMA]++;
    178     if (gb->io_registers[GB_IO_TIMA] == 0) {
    179         gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA];
    180         gb->tima_reload_state = GB_TIMA_RELOADING;
    181     }
    182 }
    183 
    184 void GB_serial_master_edge(GB_gameboy_t *gb)
    185 {
    186     if (gb->printer_callback) {
    187         unsigned ticks = 1 << gb->serial_mask;
    188         if (unlikely((gb->printer.command_state || gb->printer.bits_received))) {
    189             gb->printer.idle_time +=ticks;
    190         }
    191         if (unlikely(gb->printer.time_remaining)) {
    192             if (gb->printer.time_remaining <= ticks) {
    193                 gb->printer.time_remaining = 0;
    194                 if (gb->printer_done_callback) {
    195                     gb->printer_done_callback(gb);
    196                 }
    197             }
    198             else {
    199                 gb->printer.time_remaining -= ticks;
    200             }
    201         }
    202     }
    203     
    204     gb->serial_master_clock ^= true;
    205     
    206     if (!gb->serial_master_clock && (gb->io_registers[GB_IO_SC] & 0x81) == 0x81) {
    207         gb->serial_count++;
    208         if (gb->serial_count == 8) {
    209             gb->serial_count = 0;
    210             gb->io_registers[GB_IO_SC] &= ~0x80;
    211             gb->io_registers[GB_IO_IF] |= 8;
    212         }
    213         
    214         gb->io_registers[GB_IO_SB] <<= 1;
    215         
    216         if (gb->serial_transfer_bit_end_callback) {
    217             gb->io_registers[GB_IO_SB] |= gb->serial_transfer_bit_end_callback(gb);
    218         }
    219         else {
    220             gb->io_registers[GB_IO_SB] |= 1;
    221         }
    222         
    223         if (gb->serial_count) {
    224             /* Still more bits to send */
    225             if (gb->serial_transfer_bit_start_callback) {
    226                 gb->serial_transfer_bit_start_callback(gb, gb->io_registers[GB_IO_SB] & 0x80);
    227             }
    228         }
    229         
    230     }
    231 }
    232 
    233 
    234 void GB_set_internal_div_counter(GB_gameboy_t *gb, uint16_t value)
    235 {
    236     /* TIMA increases when a specific high-bit becomes a low-bit. */
    237     uint16_t triggers = gb->div_counter & ~value;
    238     if ((gb->io_registers[GB_IO_TAC] & 4) && unlikely(triggers & TAC_TRIGGER_BITS[gb->io_registers[GB_IO_TAC] & 3])) {
    239         increase_tima(gb);
    240     }
    241     
    242     if (unlikely(triggers & gb->serial_mask)) {
    243         GB_serial_master_edge(gb);
    244     }
    245     
    246     /* TODO: Can switching to double speed mode trigger an event? */
    247     uint16_t apu_bit = gb->cgb_double_speed? 0x2000 : 0x1000;
    248     if (unlikely(triggers & apu_bit)) {
    249         GB_apu_div_event(gb);
    250     }
    251     else {
    252         uint16_t secondary_triggers = ~gb->div_counter & value;
    253         if (unlikely(secondary_triggers & apu_bit)) {
    254             GB_apu_div_secondary_event(gb);
    255         }
    256     }
    257     gb->div_counter = value;
    258 }
    259 
    260 static void timers_run(GB_gameboy_t *gb, uint8_t cycles)
    261 {
    262     if (gb->stopped) {
    263         if (GB_is_cgb(gb)) {
    264             gb->apu.apu_cycles += 1 << !gb->cgb_double_speed;
    265         }
    266         gb->apu_output.sample_cycles += (gb->apu_output.sample_rate << !gb->cgb_double_speed) << 1;
    267         return;
    268     }
    269     
    270     GB_STATE_MACHINE(gb, div, cycles, 1) {
    271         GB_STATE(gb, div, 1);
    272         GB_STATE(gb, div, 2);
    273     }
    274     
    275     GB_SLEEP(gb, div, 1, 3);
    276     while (true) {
    277         advance_tima_state_machine(gb);
    278         GB_set_internal_div_counter(gb, gb->div_counter + 4);
    279         gb->apu.apu_cycles += 1 << !gb->cgb_double_speed;
    280         gb->apu_output.sample_cycles += (gb->apu_output.sample_rate << !gb->cgb_double_speed) << 1;
    281         GB_SLEEP(gb, div, 2, 4);
    282         if (unlikely(gb->apu.pending_envelope_tick)) {
    283             GB_apu_delayed_envelope_tick(gb);
    284         }
    285     }
    286 }
    287 
    288 void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode)
    289 {
    290     if (gb->rtc_mode != mode) {
    291         gb->rtc_mode = mode;
    292         gb->rtc_cycles = 0;
    293         gb->last_rtc_second = time(NULL);
    294     }
    295 }
    296 
    297 
    298 void GB_set_rtc_multiplier(GB_gameboy_t *gb, double multiplier)
    299 {
    300     if (multiplier == 1) {
    301         gb->rtc_second_length = 0;
    302         return;
    303     }
    304     
    305     gb->rtc_second_length = GB_get_unmultiplied_clock_rate(gb) * 2 * multiplier;
    306 }
    307 
    308 void GB_rtc_set_time(GB_gameboy_t *gb, uint64_t current_time)
    309 {
    310     if (gb->cartridge_type->mbc_type == GB_HUC3) {
    311         while (gb->last_rtc_second / 60 < current_time / 60) {
    312             gb->last_rtc_second += 60;
    313             gb->huc3.minutes++;
    314             if (gb->huc3.minutes == 60 * 24) {
    315                 gb->huc3.days++;
    316                 gb->huc3.minutes = 0;
    317             }
    318         }
    319         return;
    320     }
    321     
    322     bool running = false;
    323     if (gb->cartridge_type->mbc_type == GB_TPP1) {
    324         running = gb->tpp1_mr4 & 0x4;
    325     }
    326     else {
    327         running = (gb->rtc_real.high & 0x40) == 0;
    328     }
    329     
    330     if (!running) return;
    331     
    332     while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
    333         gb->last_rtc_second += 60 * 60 * 24;
    334         if (gb->cartridge_type->mbc_type == GB_TPP1) {
    335             if (++gb->rtc_real.tpp1.weekday == 7) {
    336                 gb->rtc_real.tpp1.weekday = 0;
    337                 if (++gb->rtc_real.tpp1.weeks == 0) {
    338                     gb->tpp1_mr4 |= 8; /* Overflow bit */
    339                 }
    340             }
    341         }
    342         else if (++gb->rtc_real.days == 0) {
    343             if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
    344                 gb->rtc_real.high |= 0x80; /* Overflow bit */
    345             }
    346             
    347             gb->rtc_real.high ^= 1;
    348         }
    349     }
    350     
    351     while (gb->last_rtc_second < current_time) {
    352         gb->last_rtc_second++;
    353         if (++gb->rtc_real.seconds != 60) continue;
    354         gb->rtc_real.seconds = 0;
    355         
    356         if (++gb->rtc_real.minutes != 60) continue;
    357         gb->rtc_real.minutes = 0;
    358         
    359         if (gb->cartridge_type->mbc_type == GB_TPP1) {
    360             if (++gb->rtc_real.tpp1.hours != 24) continue;
    361             gb->rtc_real.tpp1.hours = 0;
    362             if (++gb->rtc_real.tpp1.weekday != 7) continue;
    363             gb->rtc_real.tpp1.weekday = 0;
    364             if (++gb->rtc_real.tpp1.weeks == 0) {
    365                 gb->tpp1_mr4 |= 8; /* Overflow bit */
    366             }
    367         }
    368         else {
    369             if (++gb->rtc_real.hours != 24) continue;
    370             gb->rtc_real.hours = 0;
    371             
    372             if (++gb->rtc_real.days != 0) continue;
    373             
    374             if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
    375                 gb->rtc_real.high |= 0x80; /* Overflow bit */
    376             }
    377             
    378             gb->rtc_real.high ^= 1;
    379         }
    380     }
    381 }
    382 
    383 static void rtc_run(GB_gameboy_t *gb, uint8_t cycles)
    384 {
    385     if (likely(gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc)) return;
    386     gb->rtc_cycles += cycles;
    387     time_t current_time = 0;
    388     uint32_t rtc_second_length = unlikely(gb->rtc_second_length)? gb->rtc_second_length : GB_get_unmultiplied_clock_rate(gb) * 2;
    389     
    390     switch (gb->rtc_mode) {
    391         case GB_RTC_MODE_SYNC_TO_HOST:
    392             // Sync in a 1/32s resolution
    393             if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) / 16) return;
    394             gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) / 16;
    395             current_time = time(NULL);
    396             break;
    397         case GB_RTC_MODE_ACCURATE:
    398             if (gb->cartridge_type->mbc_type != GB_HUC3 && (gb->rtc_real.high & 0x40)) {
    399                 gb->rtc_cycles -= cycles;
    400                 return;
    401             }
    402             if (gb->rtc_cycles < rtc_second_length) return;
    403             gb->rtc_cycles -= rtc_second_length;
    404             current_time = gb->last_rtc_second + 1;
    405             break;
    406     }
    407 
    408     GB_rtc_set_time(gb, current_time);
    409 }
    410 
    411 static void camera_run(GB_gameboy_t *gb, uint8_t cycles)
    412 {
    413     /* Do we have a camera? */
    414     if (likely(gb->cartridge_type->mbc_type != GB_CAMERA)) return;
    415 
    416     /* The camera mapper uses the PHI pin to clock itself */
    417 
    418     /* PHI does not run in halt nor stop mode */
    419     if (unlikely(gb->halted || gb->stopped)) return;
    420 
    421     /* Only every other PHI is used (as the camera wants a 512KiHz clock) */
    422     gb->camera_alignment += cycles;
    423 
    424     /* Is the camera processing an image? */
    425     if (likely(gb->camera_countdown == 0)) return;
    426 
    427     gb->camera_countdown -= cycles;
    428     if (gb->camera_countdown <= 0) {
    429         gb->camera_countdown = 0;
    430         GB_camera_updated(gb);
    431     }
    432 }
    433 
    434 
    435 void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
    436 {
    437     if (unlikely(gb->speed_switch_countdown)) {
    438         if (gb->speed_switch_countdown == cycles) {
    439             gb->cgb_double_speed ^= true;
    440             gb->speed_switch_countdown = 0;
    441         }
    442         else if (gb->speed_switch_countdown > cycles) {
    443             gb->speed_switch_countdown -= cycles;
    444         }
    445         else {
    446             uint8_t old_cycles = gb->speed_switch_countdown;
    447             cycles -= old_cycles;
    448             gb->speed_switch_countdown = 0;
    449             GB_advance_cycles(gb, old_cycles);
    450             gb->cgb_double_speed ^= true;
    451         }
    452     }
    453     gb->apu.pcm_mask[0] = gb->apu.pcm_mask[1] = 0xFF; // Sort of hacky, but too many cross-component interactions to do it right
    454     // Affected by speed boost
    455     gb->dma_cycles = cycles;
    456 
    457     timers_run(gb, cycles);
    458     camera_run(gb, cycles);
    459 
    460     if (unlikely(gb->speed_switch_halt_countdown)) {
    461         gb->speed_switch_halt_countdown -= cycles;
    462         if (gb->speed_switch_halt_countdown <= 0) {
    463             gb->speed_switch_halt_countdown = 0;
    464             gb->halted = false;
    465         }
    466     }
    467         
    468 #ifndef GB_DISABLE_DEBUGGER
    469     gb->debugger_ticks += cycles;
    470 #endif
    471     
    472     if (gb->speed_switch_freeze) {
    473         if (gb->speed_switch_freeze >= cycles) {
    474             gb->speed_switch_freeze -= cycles;
    475             return;
    476         }
    477         cycles -= gb->speed_switch_freeze;
    478         gb->speed_switch_freeze = 0;
    479     }
    480 
    481     if (unlikely(!gb->cgb_double_speed)) {
    482         cycles <<= 1;
    483     }
    484     
    485 #ifndef GB_DISABLE_DEBUGGER
    486     gb->absolute_debugger_ticks += cycles;
    487     *((gb->halted || gb->stopped)? &gb->current_frame_idle_cycles : &gb->current_frame_busy_cycles) += cycles;
    488     *((gb->halted || gb->stopped)? &gb->current_second_idle_cycles : &gb->current_second_busy_cycles) += cycles;
    489 #endif
    490     
    491     // Not affected by speed boost
    492     if (likely(gb->io_registers[GB_IO_LCDC] & GB_LCDC_ENABLE)) {
    493         gb->double_speed_alignment += cycles;
    494     }
    495     gb->cycles_since_last_sync += cycles;
    496     gb->cycles_since_run += cycles;
    497     
    498     gb->rumble_on_cycles += gb->rumble_strength & 3;
    499     gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3;
    500     
    501     if (unlikely(gb->data_bus_decay_countdown)) {
    502         if (gb->data_bus_decay_countdown <= cycles) {
    503             gb->data_bus_decay_countdown = 0;
    504             gb->data_bus = 0xFF;
    505         }
    506         else {
    507             gb->data_bus_decay_countdown -= cycles;
    508         }
    509     }
    510     
    511     GB_joypad_run(gb, cycles);
    512     GB_apu_run(gb, false);
    513     GB_display_run(gb, cycles, false);
    514     if (unlikely(!gb->stopped)) { // TODO: Verify what happens in STOP mode
    515         GB_dma_run(gb);
    516     }
    517     ir_run(gb, cycles);
    518     rtc_run(gb, cycles);
    519 }
    520 
    521 /* 
    522    This glitch is based on the expected results of mooneye-gb rapid_toggle test.
    523    This glitch happens because how TIMA is increased, see GB_set_internal_div_counter.
    524    According to GiiBiiAdvance, GBC's behavior is different, but this was not tested or implemented.
    525 */
    526 void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
    527 {
    528     /* Glitch only happens when old_tac is enabled. */
    529     if (!(old_tac & 4)) return;
    530 
    531     unsigned old_clocks = TAC_TRIGGER_BITS[old_tac & 3];
    532     unsigned new_clocks = TAC_TRIGGER_BITS[new_tac & 3];
    533 
    534     /* The bit used for overflow testing must have been 1 */
    535     if (gb->div_counter & old_clocks) {
    536         /* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
    537         if (!(new_tac & 4) || !(gb->div_counter & new_clocks)) {
    538             increase_tima(gb);
    539         }
    540     }
    541 }

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