bsnes/Core/timing.c

81 lines
2.5 KiB
C

#include "gb.h"
#include "timing.h"
#include "memory.h"
void advance_cycles(GB_gameboy_t *gb, unsigned char cycles)
{
// Affected by speed boost
if (gb->dma_cycles > cycles){
gb->dma_cycles -= cycles;
}
else {
gb->dma_cycles = 0;
}
if (gb->cgb_double_speed) {
cycles >>=1;
}
// Not affected by speed boost
gb->hdma_cycles += cycles;
gb->display_cycles += cycles;
gb->div_cycles += cycles;
gb->tima_cycles += cycles;
gb->apu_cycles += cycles;
hdma_run(gb);
timers_run(gb);
apu_run(gb);
}
void timers_run(GB_gameboy_t *gb)
{
/* Standard Timers */
static const unsigned long GB_TAC_RATIOS[] = {1024, 16, 64, 256};
if (gb->div_cycles >= DIV_CYCLES) {
gb->div_cycles -= DIV_CYCLES;
gb->io_registers[GB_IO_DIV]++;
}
while (gb->tima_cycles >= GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3]) {
gb->tima_cycles -= GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3];
if (gb->io_registers[GB_IO_TAC] & 4) {
gb->io_registers[GB_IO_TIMA]++;
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;
}
}
}
/* RTC */
if (gb->display_cycles >= LCDC_PERIOD) { /* Time is a syscall and therefore is slow, so we update the RTC
only during vblanks. */
if ((gb->rtc_high & 0x40) == 0) { /* is timer running? */
time_t current_time = time(NULL);
while (gb->last_rtc_second < current_time) {
gb->last_rtc_second++;
if (++gb->rtc_seconds == 60)
{
gb->rtc_seconds = 0;
if (++gb->rtc_minutes == 60)
{
gb->rtc_minutes = 0;
if (++gb->rtc_hours == 24)
{
gb->rtc_hours = 0;
if (++gb->rtc_days == 0)
{
if (gb->rtc_high & 1) /* Bit 8 of days*/
{
gb->rtc_high |= 0x80; /* Overflow bit */
}
gb->rtc_high ^= 1;
}
}
}
}
}
}
}
}