GB Timer: Improve timer stepping when updating
Vicki Pfau vi@endrift.com
Thu, 22 Jun 2017 02:18:22 -0700
1 files changed,
17 insertions(+),
9 deletions(-)
jump to
M
src/gb/timer.c
→
src/gb/timer.c
@@ -19,22 +19,26 @@ timer->p->memory.io[REG_IF] |= (1 << GB_IRQ_TIMER);
GBUpdateIRQs(timer->p); } -void _GBTimerIncrement(struct mTiming* timing, void* context, uint32_t cyclesLate) { - struct GBTimer* timer = context; - timer->nextDiv += cyclesLate; - while (timer->nextDiv > 0) { +static void _GBTimerDivIncrement(struct GBTimer* timer, uint32_t cyclesLate) { + while (timer->nextDiv >= GB_DMG_DIV_PERIOD) { timer->nextDiv -= GB_DMG_DIV_PERIOD; // Make sure to trigger when the correct bit is a falling edge if (timer->timaPeriod > 0 && (timer->internalDiv & (timer->timaPeriod - 1)) == timer->timaPeriod - 1) { ++timer->p->memory.io[REG_TIMA]; if (!timer->p->memory.io[REG_TIMA]) { - mTimingSchedule(timing, &timer->irq, 4 - cyclesLate); + mTimingSchedule(&timer->p->timing, &timer->irq, 4 - cyclesLate); } } ++timer->internalDiv; timer->p->memory.io[REG_DIV] = timer->internalDiv >> 4; } +} + +void _GBTimerUpdate(struct mTiming* timing, void* context, uint32_t cyclesLate) { + struct GBTimer* timer = context; + timer->nextDiv += cyclesLate; + _GBTimerDivIncrement(timer, cyclesLate); // Batch div increments int divsToGo = 16 - (timer->internalDiv & 15); int timaToGo = INT_MAX;@@ -51,7 +55,7 @@
void GBTimerReset(struct GBTimer* timer) { timer->event.context = timer; timer->event.name = "GB Timer"; - timer->event.callback = _GBTimerIncrement; + timer->event.callback = _GBTimerUpdate; timer->event.priority = 0x20; timer->irq.context = timer; timer->irq.name = "GB Timer IRQ";@@ -64,16 +68,18 @@ timer->internalDiv = 0;
} void GBTimerDivReset(struct GBTimer* timer) { + timer->nextDiv -= mTimingUntil(&timer->p->timing, &timer->event); + mTimingDeschedule(&timer->p->timing, &timer->event); + _GBTimerDivIncrement(timer, (timer->p->cpu->executionState + 1) & 3); if (timer->internalDiv & (timer->timaPeriod >> 1)) { ++timer->p->memory.io[REG_TIMA]; if (!timer->p->memory.io[REG_TIMA]) { - mTimingSchedule(&timer->p->timing, &timer->irq, 4 - ((timer->p->cpu->executionState + 1) & 3)); + mTimingSchedule(&timer->p->timing, &timer->irq, 4 - (timer->p->cpu->executionState + 1) & 3); } } timer->p->memory.io[REG_DIV] = 0; timer->internalDiv = 0; timer->nextDiv = GB_DMG_DIV_PERIOD; - mTimingDeschedule(&timer->p->timing, &timer->event); mTimingSchedule(&timer->p->timing, &timer->event, timer->nextDiv - ((timer->p->cpu->executionState + 1) & 3)); }@@ -96,7 +102,9 @@ }
timer->nextDiv -= mTimingUntil(&timer->p->timing, &timer->event); mTimingDeschedule(&timer->p->timing, &timer->event); - mTimingSchedule(&timer->p->timing, &timer->event, 0); + _GBTimerDivIncrement(timer, (timer->p->cpu->executionState + 1) & 3); + timer->nextDiv += GB_DMG_DIV_PERIOD; + mTimingSchedule(&timer->p->timing, &timer->event, timer->nextDiv); } else { timer->timaPeriod = 0; }