|
|
@@ -1,4 +1,4 @@ |
|
|
-/* Copyright (c) 2013-2016 Jeffrey Pfau
|
|
|
+/* Copyright (c) 2013-2018 Jeffrey Pfau
|
|
|
*
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
@@ -12,6 +12,8 @@ |
|
|
#define TIMER_RELOAD_DELAY 0
|
|
|
#define TIMER_STARTUP_DELAY 2
|
|
|
|
|
|
+#define REG_TMCNT_LO(X) (REG_TM0CNT_LO + (X << 2))
|
|
|
+
|
|
|
static void GBATimerIrq(struct GBA* gba, int timerId) {
|
|
|
struct GBATimer* timer = &gba->timers[timerId];
|
|
|
if (GBATimerFlagsIsIrqPending(timer->flags)) {
|
|
|
@@ -46,11 +48,6 @@ static void GBATimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesL |
|
|
|
|
|
static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) {
|
|
|
struct GBATimer* timer = &gba->timers[timerId];
|
|
|
- gba->memory.io[(REG_TM0CNT_LO >> 1) + (timerId << 1)] = timer->reload;
|
|
|
- int32_t currentTime = mTimingCurrentTime(&gba->timing) - cyclesLate;
|
|
|
- int32_t tickMask = (1 << GBATimerFlagsGetPrescaleBits(timer->flags)) - 1;
|
|
|
- currentTime &= ~tickMask;
|
|
|
- timer->lastEvent = currentTime;
|
|
|
GBATimerUpdateRegister(gba, timerId, TIMER_RELOAD_DELAY + cyclesLate);
|
|
|
|
|
|
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
|
|
@@ -143,20 +140,29 @@ void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate) { |
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // Align timer
|
|
|
int prescaleBits = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
|
|
|
int32_t currentTime = mTimingCurrentTime(&gba->timing) - cyclesLate;
|
|
|
int32_t tickMask = (1 << prescaleBits) - 1;
|
|
|
currentTime &= ~tickMask;
|
|
|
+
|
|
|
+ // Update register
|
|
|
int32_t tickIncrement = currentTime - currentTimer->lastEvent;
|
|
|
currentTimer->lastEvent = currentTime;
|
|
|
tickIncrement >>= prescaleBits;
|
|
|
- tickIncrement += gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1];
|
|
|
- gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = tickIncrement;
|
|
|
- if (!mTimingIsScheduled(&gba->timing, ¤tTimer->event)) {
|
|
|
- tickIncrement = (0x10000 - tickIncrement) << prescaleBits;
|
|
|
- currentTime -= mTimingCurrentTime(&gba->timing) - cyclesLate;
|
|
|
- mTimingSchedule(&gba->timing, ¤tTimer->event, tickIncrement + currentTime);
|
|
|
+ tickIncrement += gba->memory.io[REG_TMCNT_LO(timer) >> 1];
|
|
|
+ while (tickIncrement >= 0x10000) {
|
|
|
+ tickIncrement -= 0x10000 - currentTimer->reload;
|
|
|
}
|
|
|
+ gba->memory.io[REG_TMCNT_LO(timer) >> 1] = tickIncrement;
|
|
|
+
|
|
|
+ // Schedule next update
|
|
|
+ tickIncrement = (0x10000 - tickIncrement) << prescaleBits;
|
|
|
+ currentTime += tickIncrement;
|
|
|
+ currentTime &= ~tickMask;
|
|
|
+ currentTime -= mTimingCurrentTime(&gba->timing);
|
|
|
+ mTimingDeschedule(&gba->timing, ¤tTimer->event);
|
|
|
+ mTimingSchedule(&gba->timing, ¤tTimer->event, currentTime);
|
|
|
}
|
|
|
|
|
|
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
|
|
|
@@ -190,7 +196,7 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { |
|
|
currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080);
|
|
|
if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) {
|
|
|
mTimingDeschedule(&gba->timing, ¤tTimer->event);
|
|
|
- gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
|
|
|
+ gba->memory.io[REG_TMCNT_LO(timer) >> 1] = currentTimer->reload;
|
|
|
int32_t tickMask = (1 << prescaleBits) - 1;
|
|
|
currentTimer->lastEvent = (mTimingCurrentTime(&gba->timing) - TIMER_STARTUP_DELAY) & ~tickMask;
|
|
|
GBATimerUpdateRegister(gba, timer, TIMER_STARTUP_DELAY);
|
|
|
|
0 comments on commit
e2a5efe