mirror of https://github.com/mgba-emu/mgba.git
GBA Timers: Fix toggling timer cascading while timer is active (fixes #2043)
This commit is contained in:
parent
2a35f0689a
commit
e12ca74d1e
1
CHANGES
1
CHANGES
|
@ -51,6 +51,7 @@ Emulation fixes:
|
|||
- GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800)
|
||||
- GBA SIO: Fix deseralizing SIO registers
|
||||
- GBA SIO: Fix hanging on starting a second multiplayer window (fixes mgba.io/i/854)
|
||||
- GBA Timers: Fix toggling timer cascading while timer is active (fixes mgba.io/i/2043)
|
||||
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
|
||||
- GBA Video: Fix Hblank timing
|
||||
- GBA Video: Implement green swap (fixes mgba.io/i/1609)
|
||||
|
|
|
@ -121,39 +121,33 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
|
|||
struct GBATimer* currentTimer = &gba->timers[timer];
|
||||
GBATimerUpdateRegister(gba, timer, 0);
|
||||
|
||||
unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
|
||||
unsigned prescaleBits;
|
||||
switch (control & 0x0003) {
|
||||
case 0x0000:
|
||||
prescaleBits = 0;
|
||||
break;
|
||||
case 0x0001:
|
||||
prescaleBits = 6;
|
||||
break;
|
||||
case 0x0002:
|
||||
prescaleBits = 8;
|
||||
break;
|
||||
case 0x0003:
|
||||
prescaleBits = 10;
|
||||
break;
|
||||
}
|
||||
const unsigned prescaleTable[4] = { 0, 6, 8, 10 };
|
||||
unsigned prescaleBits = prescaleTable[control & 0x0003];
|
||||
|
||||
GBATimerFlags oldFlags = currentTimer->flags;
|
||||
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, prescaleBits);
|
||||
currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, timer > 0 && (control & 0x0004));
|
||||
currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040);
|
||||
bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags);
|
||||
currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080);
|
||||
if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||
|
||||
bool reschedule = false;
|
||||
if (GBATimerFlagsIsEnable(oldFlags) != GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||
reschedule = true;
|
||||
if (GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||
gba->memory.io[REG_TMCNT_LO(timer) >> 1] = currentTimer->reload;
|
||||
}
|
||||
} else if (GBATimerFlagsIsCountUp(oldFlags) != GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||
reschedule = true;
|
||||
} else if (GBATimerFlagsGetPrescaleBits(currentTimer->flags) != GBATimerFlagsGetPrescaleBits(oldFlags)) {
|
||||
reschedule = true;
|
||||
}
|
||||
|
||||
if (reschedule) {
|
||||
mTimingDeschedule(&gba->timing, ¤tTimer->event);
|
||||
gba->memory.io[REG_TMCNT_LO(timer) >> 1] = currentTimer->reload;
|
||||
int32_t tickMask = (1 << prescaleBits) - 1;
|
||||
currentTimer->lastEvent = mTimingCurrentTime(&gba->timing) & ~tickMask;
|
||||
GBATimerUpdateRegister(gba, timer, 0);
|
||||
} else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||
mTimingDeschedule(&gba->timing, ¤tTimer->event);
|
||||
} else if (GBATimerFlagsIsEnable(currentTimer->flags) && GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||
mTimingDeschedule(&gba->timing, ¤tTimer->event);
|
||||
int32_t tickMask = (1 << prescaleBits) - 1;
|
||||
currentTimer->lastEvent = mTimingCurrentTime(&gba->timing) & ~tickMask;
|
||||
GBATimerUpdateRegister(gba, timer, 0);
|
||||
if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||
int32_t tickMask = (1 << prescaleBits) - 1;
|
||||
currentTimer->lastEvent = mTimingCurrentTime(&gba->timing) & ~tickMask;
|
||||
GBATimerUpdateRegister(gba, timer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue