GBA: Bitfield-ize GBATimer flags

This commit is contained in:
Jeffrey Pfau 2015-10-14 22:52:03 -07:00
parent 0211106a3d
commit 576ba689f1
4 changed files with 44 additions and 37 deletions

View File

@ -252,7 +252,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
struct GBATimer* nextTimer;
timer = &gba->timers[0];
if (timer->enable) {
if (GBATimerFlagsIsEnable(timer->flags)) {
timer->nextEvent -= cycles;
timer->lastEvent -= cycles;
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;
timer->oldReload = timer->reload;
if (timer->doIrq) {
if (GBATimerFlagsIsDoIrq(timer->flags)) {
GBARaiseIRQ(gba, IRQ_TIMER0);
}
@ -276,7 +276,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
}
nextTimer = &gba->timers[1];
if (nextTimer->countUp) {
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
++gba->memory.io[REG_TM1CNT_LO >> 1];
if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
nextTimer->nextEvent = 0;
@ -287,7 +287,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
}
timer = &gba->timers[1];
if (timer->enable) {
if (GBATimerFlagsIsEnable(timer->flags)) {
timer->nextEvent -= cycles;
timer->lastEvent -= cycles;
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;
timer->oldReload = timer->reload;
if (timer->doIrq) {
if (GBATimerFlagsIsDoIrq(timer->flags)) {
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;
}
nextTimer = &gba->timers[2];
if (nextTimer->countUp) {
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
++gba->memory.io[REG_TM2CNT_LO >> 1];
if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
nextTimer->nextEvent = 0;
@ -328,7 +328,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
}
timer = &gba->timers[2];
if (timer->enable) {
if (GBATimerFlagsIsEnable(timer->flags)) {
timer->nextEvent -= cycles;
timer->lastEvent -= cycles;
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;
timer->oldReload = timer->reload;
if (timer->doIrq) {
if (GBATimerFlagsIsDoIrq(timer->flags)) {
GBARaiseIRQ(gba, IRQ_TIMER2);
}
if (timer->countUp) {
if (GBATimerFlagsIsCountUp(timer->flags)) {
timer->nextEvent = INT_MAX;
}
nextTimer = &gba->timers[3];
if (nextTimer->countUp) {
if (GBATimerFlagsIsCountUp(nextTimer->flags)) {
++gba->memory.io[REG_TM3CNT_LO >> 1];
if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
nextTimer->nextEvent = 0;
@ -359,7 +359,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
}
timer = &gba->timers[3];
if (timer->enable) {
if (GBATimerFlagsIsEnable(timer->flags)) {
timer->nextEvent -= cycles;
timer->lastEvent -= cycles;
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;
timer->oldReload = timer->reload;
if (timer->doIrq) {
if (GBATimerFlagsIsDoIrq(timer->flags)) {
GBARaiseIRQ(gba, IRQ_TIMER3);
}
if (timer->countUp) {
if (GBATimerFlagsIsCountUp(timer->flags)) {
timer->nextEvent = INT_MAX;
}
}
@ -481,47 +481,47 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
void GBATimerUpdateRegister(struct GBA* gba, int timer) {
struct GBATimer* currentTimer = &gba->timers[timer];
if (currentTimer->enable && !currentTimer->countUp) {
if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
int32_t prefetchSkew = 0;
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;
}
// 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) {
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) {
struct GBATimer* currentTimer = &gba->timers[timer];
GBATimerUpdateRegister(gba, timer);
int oldPrescale = currentTimer->prescaleBits;
unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
switch (control & 0x0003) {
case 0x0000:
currentTimer->prescaleBits = 0;
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 0);
break;
case 0x0001:
currentTimer->prescaleBits = 6;
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 6);
break;
case 0x0002:
currentTimer->prescaleBits = 8;
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 8);
break;
case 0x0003:
currentTimer->prescaleBits = 10;
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 10);
break;
}
currentTimer->countUp = !!(control & 0x0004);
currentTimer->doIrq = !!(control & 0x0040);
currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
int wasEnabled = currentTimer->enable;
currentTimer->enable = !!(control & 0x0080);
if (!wasEnabled && currentTimer->enable) {
if (!currentTimer->countUp) {
currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, control & 0x0004);
currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040);
currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << GBATimerFlagsGetPrescaleBits(currentTimer->flags);
bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags);
currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080);
if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) {
if (!GBATimerFlagsIsCountUp(currentTimer->flags)) {
currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval;
} else {
currentTimer->nextEvent = INT_MAX;
@ -530,12 +530,12 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
currentTimer->oldReload = currentTimer->reload;
currentTimer->lastEvent = gba->cpu->cycles;
gba->timersEnabled |= 1 << timer;
} else if (wasEnabled && !currentTimer->enable) {
if (!currentTimer->countUp) {
} else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) {
if (!GBATimerFlagsIsCountUp(currentTimer->flags)) {
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale);
}
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
currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
}

View File

@ -59,16 +59,19 @@ struct GBAThread;
struct Patch;
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 {
uint16_t reload;
uint16_t oldReload;
int32_t lastEvent;
int32_t nextEvent;
int32_t overflowInterval;
unsigned prescaleBits : 4;
unsigned countUp : 1;
unsigned doIrq : 1;
unsigned enable : 1;
GBATimerFlags flags;
};
struct GBA {

View File

@ -730,7 +730,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
}
if (gba->timers[i].enable) {
if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
gba->timersEnabled |= 1 << i;
}
}

View File

@ -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 CLEAR_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
#define ATTRIBUTE_UNUSED
@ -112,6 +113,9 @@ typedef intptr_t ssize_t;
} \
ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE 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)