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.