From fec4c064475615dcf5593fa8fa8d342913997936 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 12 Jun 2017 21:06:06 -0700 Subject: [PATCH] GBA Memory: Simplify prefetch logic (possibly more accurate, but more failing tests) --- src/gba/memory.c | 25 ++++++++++++------------- src/gba/timer.c | 8 ++++---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/gba/memory.c b/src/gba/memory.c index db4a30122..755a538a0 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -1505,33 +1505,32 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { previousLoads = dist; } - int32_t s = cpu->memory.activeSeqCycles16 + 1; - int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16 + 1; + int32_t s = cpu->memory.activeSeqCycles16; + int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16; // Figure out how many sequential loads we can jam in int32_t stall = s; int32_t loads = 1; - if (stall > wait && !previousLoads) { - // We might need to stall a bit extra if we haven't finished the first S cycle - wait = stall; - } else { - while (stall < wait) { + if (stall < wait) { + int32_t maxLoads = 8 - previousLoads; + while (stall < wait && loads < maxLoads) { stall += s; ++loads; } - if (loads + previousLoads > 8) { - loads = 8 - previousLoads; - } } + if (stall > wait) { + // The wait cannot take less time than the prefetch stalls + wait = stall; + } + // This instruction used to have an N, convert it to an S. wait -= n2s; - // TODO: Invalidate prefetch on branch - memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * loads; + memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * (loads + previousLoads - 1); // The next |loads|S waitstates disappear entirely, so long as they're all in a row - cpu->cycles -= (s - 1) * loads; + cpu->cycles -= stall; return wait; } diff --git a/src/gba/timer.c b/src/gba/timer.c index c62f64506..03af4fe34 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -83,13 +83,13 @@ void GBATimerInit(struct GBA* gba) { void GBATimerUpdateRegister(struct GBA* gba, int timer) { struct GBATimer* currentTimer = &gba->timers[timer]; if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) { - int32_t prefetchSkew = 0; - if (gba->memory.lastPrefetchedPc >= (uint32_t) gba->cpu->gprs[ARM_PC]) { - prefetchSkew = (gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * (gba->cpu->memory.activeSeqCycles16 + 1) / WORD_SIZE_THUMB; + int32_t prefetchSkew = -2; + if (gba->memory.lastPrefetchedPc > (uint32_t) gba->cpu->gprs[ARM_PC]) { + prefetchSkew += ((gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * gba->cpu->memory.activeSeqCycles16) / WORD_SIZE_THUMB; } // Reading this takes two cycles (1N+1I), so let's remove them preemptively int32_t diff = gba->cpu->cycles - (currentTimer->lastEvent - gba->timing.masterCycles); - gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((diff - 2 + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags)); + gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((diff + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags)); } }