mirror of https://github.com/mgba-emu/mgba.git
GBA: Bitfield-ize GBATimer flags
This commit is contained in:
parent
0211106a3d
commit
576ba689f1
|
@ -252,7 +252,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
struct GBATimer* nextTimer;
|
struct GBATimer* nextTimer;
|
||||||
|
|
||||||
timer = &gba->timers[0];
|
timer = &gba->timers[0];
|
||||||
if (timer->enable) {
|
if (GBATimerFlagsIsEnable(timer->flags)) {
|
||||||
timer->nextEvent -= cycles;
|
timer->nextEvent -= cycles;
|
||||||
timer->lastEvent -= cycles;
|
timer->lastEvent -= cycles;
|
||||||
while (timer->nextEvent <= 0) {
|
while (timer->nextEvent <= 0) {
|
||||||
|
@ -261,7 +261,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
|
gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
|
||||||
timer->oldReload = timer->reload;
|
timer->oldReload = timer->reload;
|
||||||
|
|
||||||
if (timer->doIrq) {
|
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||||
GBARaiseIRQ(gba, IRQ_TIMER0);
|
GBARaiseIRQ(gba, IRQ_TIMER0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTimer = &gba->timers[1];
|
nextTimer = &gba->timers[1];
|
||||||
if (nextTimer->countUp) {
|
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
|
||||||
++gba->memory.io[REG_TM1CNT_LO >> 1];
|
++gba->memory.io[REG_TM1CNT_LO >> 1];
|
||||||
if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
|
if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
|
||||||
nextTimer->nextEvent = 0;
|
nextTimer->nextEvent = 0;
|
||||||
|
@ -287,7 +287,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = &gba->timers[1];
|
timer = &gba->timers[1];
|
||||||
if (timer->enable) {
|
if (GBATimerFlagsIsEnable(timer->flags)) {
|
||||||
timer->nextEvent -= cycles;
|
timer->nextEvent -= cycles;
|
||||||
timer->lastEvent -= cycles;
|
timer->lastEvent -= cycles;
|
||||||
if (timer->nextEvent <= 0) {
|
if (timer->nextEvent <= 0) {
|
||||||
|
@ -296,7 +296,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
|
gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
|
||||||
timer->oldReload = timer->reload;
|
timer->oldReload = timer->reload;
|
||||||
|
|
||||||
if (timer->doIrq) {
|
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||||
GBARaiseIRQ(gba, IRQ_TIMER1);
|
GBARaiseIRQ(gba, IRQ_TIMER1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,12 +310,12 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer->countUp) {
|
if (GBATimerFlagsIsCountUp(timer->flags)) {
|
||||||
timer->nextEvent = INT_MAX;
|
timer->nextEvent = INT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTimer = &gba->timers[2];
|
nextTimer = &gba->timers[2];
|
||||||
if (nextTimer->countUp) {
|
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
|
||||||
++gba->memory.io[REG_TM2CNT_LO >> 1];
|
++gba->memory.io[REG_TM2CNT_LO >> 1];
|
||||||
if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
|
if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
|
||||||
nextTimer->nextEvent = 0;
|
nextTimer->nextEvent = 0;
|
||||||
|
@ -328,7 +328,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = &gba->timers[2];
|
timer = &gba->timers[2];
|
||||||
if (timer->enable) {
|
if (GBATimerFlagsIsEnable(timer->flags)) {
|
||||||
timer->nextEvent -= cycles;
|
timer->nextEvent -= cycles;
|
||||||
timer->lastEvent -= cycles;
|
timer->lastEvent -= cycles;
|
||||||
if (timer->nextEvent <= 0) {
|
if (timer->nextEvent <= 0) {
|
||||||
|
@ -337,16 +337,16 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
|
gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
|
||||||
timer->oldReload = timer->reload;
|
timer->oldReload = timer->reload;
|
||||||
|
|
||||||
if (timer->doIrq) {
|
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||||
GBARaiseIRQ(gba, IRQ_TIMER2);
|
GBARaiseIRQ(gba, IRQ_TIMER2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer->countUp) {
|
if (GBATimerFlagsIsCountUp(timer->flags)) {
|
||||||
timer->nextEvent = INT_MAX;
|
timer->nextEvent = INT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTimer = &gba->timers[3];
|
nextTimer = &gba->timers[3];
|
||||||
if (nextTimer->countUp) {
|
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
|
||||||
++gba->memory.io[REG_TM3CNT_LO >> 1];
|
++gba->memory.io[REG_TM3CNT_LO >> 1];
|
||||||
if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
|
if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
|
||||||
nextTimer->nextEvent = 0;
|
nextTimer->nextEvent = 0;
|
||||||
|
@ -359,7 +359,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = &gba->timers[3];
|
timer = &gba->timers[3];
|
||||||
if (timer->enable) {
|
if (GBATimerFlagsIsEnable(timer->flags)) {
|
||||||
timer->nextEvent -= cycles;
|
timer->nextEvent -= cycles;
|
||||||
timer->lastEvent -= cycles;
|
timer->lastEvent -= cycles;
|
||||||
if (timer->nextEvent <= 0) {
|
if (timer->nextEvent <= 0) {
|
||||||
|
@ -368,11 +368,11 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
||||||
gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
|
gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
|
||||||
timer->oldReload = timer->reload;
|
timer->oldReload = timer->reload;
|
||||||
|
|
||||||
if (timer->doIrq) {
|
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||||
GBARaiseIRQ(gba, IRQ_TIMER3);
|
GBARaiseIRQ(gba, IRQ_TIMER3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer->countUp) {
|
if (GBATimerFlagsIsCountUp(timer->flags)) {
|
||||||
timer->nextEvent = INT_MAX;
|
timer->nextEvent = INT_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,47 +481,47 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
|
||||||
|
|
||||||
void GBATimerUpdateRegister(struct GBA* gba, int timer) {
|
void GBATimerUpdateRegister(struct GBA* gba, int timer) {
|
||||||
struct GBATimer* currentTimer = &gba->timers[timer];
|
struct GBATimer* currentTimer = &gba->timers[timer];
|
||||||
if (currentTimer->enable && !currentTimer->countUp) {
|
if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||||
int32_t prefetchSkew = 0;
|
int32_t prefetchSkew = 0;
|
||||||
if (gba->memory.lastPrefetchedPc - gba->memory.lastPrefetchedLoads * WORD_SIZE_THUMB >= (uint32_t) gba->cpu->gprs[ARM_PC]) {
|
if (gba->memory.lastPrefetchedPc - gba->memory.lastPrefetchedLoads * WORD_SIZE_THUMB >= (uint32_t) gba->cpu->gprs[ARM_PC]) {
|
||||||
prefetchSkew = (gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * (gba->cpu->memory.activeSeqCycles16 + 1) / WORD_SIZE_THUMB;
|
prefetchSkew = (gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * (gba->cpu->memory.activeSeqCycles16 + 1) / WORD_SIZE_THUMB;
|
||||||
}
|
}
|
||||||
// Reading this takes two cycles (1N+1I), so let's remove them preemptively
|
// Reading this takes two cycles (1N+1I), so let's remove them preemptively
|
||||||
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> currentTimer->prescaleBits);
|
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
|
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
|
||||||
gba->timers[timer].reload = reload;
|
gba->timers[timer].reload = reload;
|
||||||
gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << gba->timers[timer].prescaleBits;
|
gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << GBATimerFlagsGetPrescaleBits(gba->timers[timer].flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
|
void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
|
||||||
struct GBATimer* currentTimer = &gba->timers[timer];
|
struct GBATimer* currentTimer = &gba->timers[timer];
|
||||||
GBATimerUpdateRegister(gba, timer);
|
GBATimerUpdateRegister(gba, timer);
|
||||||
|
|
||||||
int oldPrescale = currentTimer->prescaleBits;
|
unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
|
||||||
switch (control & 0x0003) {
|
switch (control & 0x0003) {
|
||||||
case 0x0000:
|
case 0x0000:
|
||||||
currentTimer->prescaleBits = 0;
|
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 0);
|
||||||
break;
|
break;
|
||||||
case 0x0001:
|
case 0x0001:
|
||||||
currentTimer->prescaleBits = 6;
|
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 6);
|
||||||
break;
|
break;
|
||||||
case 0x0002:
|
case 0x0002:
|
||||||
currentTimer->prescaleBits = 8;
|
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 8);
|
||||||
break;
|
break;
|
||||||
case 0x0003:
|
case 0x0003:
|
||||||
currentTimer->prescaleBits = 10;
|
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 10);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
currentTimer->countUp = !!(control & 0x0004);
|
currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, control & 0x0004);
|
||||||
currentTimer->doIrq = !!(control & 0x0040);
|
currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040);
|
||||||
currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
|
currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << GBATimerFlagsGetPrescaleBits(currentTimer->flags);
|
||||||
int wasEnabled = currentTimer->enable;
|
bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags);
|
||||||
currentTimer->enable = !!(control & 0x0080);
|
currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080);
|
||||||
if (!wasEnabled && currentTimer->enable) {
|
if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||||
if (!currentTimer->countUp) {
|
if (!GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||||
currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval;
|
currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval;
|
||||||
} else {
|
} else {
|
||||||
currentTimer->nextEvent = INT_MAX;
|
currentTimer->nextEvent = INT_MAX;
|
||||||
|
@ -530,12 +530,12 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
|
||||||
currentTimer->oldReload = currentTimer->reload;
|
currentTimer->oldReload = currentTimer->reload;
|
||||||
currentTimer->lastEvent = gba->cpu->cycles;
|
currentTimer->lastEvent = gba->cpu->cycles;
|
||||||
gba->timersEnabled |= 1 << timer;
|
gba->timersEnabled |= 1 << timer;
|
||||||
} else if (wasEnabled && !currentTimer->enable) {
|
} else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) {
|
||||||
if (!currentTimer->countUp) {
|
if (!GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||||
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale);
|
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale);
|
||||||
}
|
}
|
||||||
gba->timersEnabled &= ~(1 << timer);
|
gba->timersEnabled &= ~(1 << timer);
|
||||||
} else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
|
} else if (GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||||
// FIXME: this might be before present
|
// FIXME: this might be before present
|
||||||
currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
|
currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,16 +59,19 @@ struct GBAThread;
|
||||||
struct Patch;
|
struct Patch;
|
||||||
struct VFile;
|
struct VFile;
|
||||||
|
|
||||||
|
DECL_BITFIELD(GBATimerFlags, uint32_t);
|
||||||
|
DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4);
|
||||||
|
DECL_BIT(GBATimerFlags, CountUp, 4);
|
||||||
|
DECL_BIT(GBATimerFlags, DoIrq, 5);
|
||||||
|
DECL_BIT(GBATimerFlags, Enable, 6);
|
||||||
|
|
||||||
struct GBATimer {
|
struct GBATimer {
|
||||||
uint16_t reload;
|
uint16_t reload;
|
||||||
uint16_t oldReload;
|
uint16_t oldReload;
|
||||||
int32_t lastEvent;
|
int32_t lastEvent;
|
||||||
int32_t nextEvent;
|
int32_t nextEvent;
|
||||||
int32_t overflowInterval;
|
int32_t overflowInterval;
|
||||||
unsigned prescaleBits : 4;
|
GBATimerFlags flags;
|
||||||
unsigned countUp : 1;
|
|
||||||
unsigned doIrq : 1;
|
|
||||||
unsigned enable : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBA {
|
struct GBA {
|
||||||
|
|
|
@ -730,7 +730,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||||
GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
|
GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gba->timers[i].enable) {
|
if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
|
||||||
gba->timersEnabled |= 1 << i;
|
gba->timersEnabled |= 1 << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ typedef intptr_t ssize_t;
|
||||||
#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END)))
|
#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END)))
|
||||||
#define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END))
|
#define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END))
|
||||||
#define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END))
|
#define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END))
|
||||||
|
#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END)))
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define ATTRIBUTE_UNUSED
|
#define ATTRIBUTE_UNUSED
|
||||||
|
@ -112,6 +113,9 @@ typedef intptr_t ssize_t;
|
||||||
} \
|
} \
|
||||||
ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \
|
ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \
|
||||||
return INS_BITS(src, (START), (START) + (SIZE), bits); \
|
return INS_BITS(src, (START), (START) + (SIZE), bits); \
|
||||||
|
} \
|
||||||
|
ATTRIBUTE_UNUSED static inline TYPE TYPE ## TestFill ## FIELD (TYPE src, bool test) { \
|
||||||
|
return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1)
|
#define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1)
|
||||||
|
|
Loading…
Reference in New Issue