GBA: Bitfield-ize GBATimer flags
@@ -252,7 +252,7 @@ struct GBATimer* timer;
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 @@ timer->nextEvent += timer->overflowInterval;
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 @@ }
} 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 @@ nextEvent = timer->nextEvent;
} 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 @@ timer->nextEvent += timer->overflowInterval;
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 @@ GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
} } - 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 @@ }
} 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 @@ timer->nextEvent += timer->overflowInterval;
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 @@ }
} 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 @@ timer->nextEvent += timer->overflowInterval;
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 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 @@ gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
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; }
@@ -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 {
@@ -730,7 +730,7 @@ if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]); } - if (gba->timers[i].enable) { + if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { gba->timersEnabled |= 1 << i; } }
@@ -86,6 +86,7 @@ #define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1))
#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 @@ return FILL_BITS(src, (START), (START) + (SIZE)); \
} \ 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)