GB Timer: Fix DIV batching if TAC changes

This commit is contained in:
Vicki Pfau 2017-06-12 07:14:19 -07:00
parent 126afa12d9
commit 59922fe2e9
2 changed files with 16 additions and 3 deletions

View File

@ -66,6 +66,7 @@ Bugfixes:
- LR35902: Fix decoding LD r, $imm and 0-valued immediates (fixes mgba.io/i/735)
- GB: Fix STAT blocking
- GB MBC: Fix swapping carts not detect new MBC
- GB Timer: Fix DIV batching if TAC changes
Misc:
- SDL: Remove scancode key input
- GBA Video: Clean up unused timers

View File

@ -9,6 +9,8 @@
#include <mgba/internal/gb/io.h>
#include <mgba/internal/gb/serialize.h>
static void _GBTimerUpdateDIV(struct GBTimer* timer, uint32_t cyclesLate);
void _GBTimerIRQ(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
@ -34,8 +36,12 @@ 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);
int divsToGo = 16 - (timer->internalDiv & 15) + (timer->nextDiv / GB_DMG_DIV_PERIOD);
int timaToGo = INT_MAX;
if (timer->timaPeriod) {
timaToGo = timer->timaPeriod - (timer->internalDiv & (timer->timaPeriod - 1));
@ -43,8 +49,12 @@ void _GBTimerIncrement(struct mTiming* timing, void* context, uint32_t cyclesLat
if (timaToGo < divsToGo) {
divsToGo = timaToGo;
}
timer->nextDiv = GB_DMG_DIV_PERIOD * divsToGo;
mTimingSchedule(timing, &timer->event, timer->nextDiv - cyclesLate);
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);
}
void GBTimerReset(struct GBTimer* timer) {
@ -89,6 +99,8 @@ uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
} else {
timer->timaPeriod = 0;
}
mTimingDeschedule(&timer->p->timing, &timer->event);
_GBTimerUpdateDIV(timer, 0);
return tac;
}