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; 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;
} }

View File

@ -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 {

View File

@ -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;
} }
} }

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 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)