diff --git a/include/mgba/core/timing.h b/include/mgba/core/timing.h index 19de59dc7..634631bed 100644 --- a/include/mgba/core/timing.h +++ b/include/mgba/core/timing.h @@ -38,6 +38,7 @@ bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent* int32_t mTimingTick(struct mTiming* timing, int32_t cycles); int32_t mTimingCurrentTime(const struct mTiming* timing); int32_t mTimingNextEvent(struct mTiming* timing); +int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*); CXX_GUARD_END diff --git a/src/core/timing.c b/src/core/timing.c index 11b808a93..5f51272ad 100644 --- a/src/core/timing.c +++ b/src/core/timing.c @@ -91,3 +91,7 @@ int32_t mTimingNextEvent(struct mTiming* timing) { } return next->when - timing->masterCycles; } + +int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent* event) { + return event->when - timing->masterCycles; +} diff --git a/src/gb/timer.c b/src/gb/timer.c index 48383f652..1533792eb 100644 --- a/src/gb/timer.c +++ b/src/gb/timer.c @@ -9,8 +9,6 @@ #include #include -static void _GBTimerUpdateDIV(struct GBTimer* timer, uint32_t cyclesLate); - void _GBTimerIRQ(struct mTiming* timing, void* context, uint32_t cyclesLate) { UNUSED(timing); UNUSED(cyclesLate); @@ -36,12 +34,8 @@ void _GBTimerIncrement(struct mTiming* timing, void* context, uint32_t cyclesLat ++timer->internalDiv; timer->p->memory.io[REG_DIV] = timer->internalDiv >> 4; } - _GBTimerUpdateDIV(timer, cyclesLate); -} - -void _GBTimerUpdateDIV(struct GBTimer* timer, uint32_t cyclesLate) { // Batch div increments - int divsToGo = 16 - (timer->internalDiv & 15) + (timer->nextDiv / GB_DMG_DIV_PERIOD); + int divsToGo = 16 - (timer->internalDiv & 15); int timaToGo = INT_MAX; if (timer->timaPeriod) { timaToGo = timer->timaPeriod - (timer->internalDiv & (timer->timaPeriod - 1)); @@ -49,12 +43,8 @@ void _GBTimerUpdateDIV(struct GBTimer* timer, uint32_t cyclesLate) { if (timaToGo < divsToGo) { divsToGo = timaToGo; } - if (divsToGo > 16) { - divsToGo = 16; - } - timer->nextDiv &= GB_DMG_DIV_PERIOD - 1; - timer->nextDiv += GB_DMG_DIV_PERIOD * divsToGo; - mTimingSchedule(&timer->p->timing, &timer->event, timer->nextDiv - cyclesLate); + timer->nextDiv = GB_DMG_DIV_PERIOD * divsToGo; + mTimingSchedule(timing, &timer->event, timer->nextDiv - cyclesLate); } void GBTimerReset(struct GBTimer* timer) { @@ -96,11 +86,13 @@ uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) { timer->timaPeriod = 256 >> 4; break; } + + timer->nextDiv -= mTimingUntil(&timer->p->timing, &timer->event); + mTimingDeschedule(&timer->p->timing, &timer->event); + mTimingSchedule(&timer->p->timing, &timer->event, 0); } else { timer->timaPeriod = 0; } - mTimingDeschedule(&timer->p->timing, &timer->event); - _GBTimerUpdateDIV(timer, 0); return tac; }