mirror of https://github.com/mgba-emu/mgba.git
GBA Memory: Simplify prefetch logic (possibly more accurate, but more failing tests)
This commit is contained in:
parent
e2dc5575b9
commit
fec4c06447
|
@ -1505,33 +1505,32 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) {
|
||||||
previousLoads = dist;
|
previousLoads = dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t s = cpu->memory.activeSeqCycles16 + 1;
|
int32_t s = cpu->memory.activeSeqCycles16;
|
||||||
int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16 + 1;
|
int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16;
|
||||||
|
|
||||||
// Figure out how many sequential loads we can jam in
|
// Figure out how many sequential loads we can jam in
|
||||||
int32_t stall = s;
|
int32_t stall = s;
|
||||||
int32_t loads = 1;
|
int32_t loads = 1;
|
||||||
|
|
||||||
if (stall > wait && !previousLoads) {
|
if (stall < wait) {
|
||||||
// We might need to stall a bit extra if we haven't finished the first S cycle
|
int32_t maxLoads = 8 - previousLoads;
|
||||||
wait = stall;
|
while (stall < wait && loads < maxLoads) {
|
||||||
} else {
|
|
||||||
while (stall < wait) {
|
|
||||||
stall += s;
|
stall += s;
|
||||||
++loads;
|
++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.
|
// This instruction used to have an N, convert it to an S.
|
||||||
wait -= n2s;
|
wait -= n2s;
|
||||||
|
|
||||||
// TODO: Invalidate prefetch on branch
|
memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * (loads + previousLoads - 1);
|
||||||
memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * loads;
|
|
||||||
|
|
||||||
// The next |loads|S waitstates disappear entirely, so long as they're all in a row
|
// 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;
|
return wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,13 +83,13 @@ void GBATimerInit(struct GBA* gba) {
|
||||||
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 (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
|
||||||
int32_t prefetchSkew = 0;
|
int32_t prefetchSkew = -2;
|
||||||
if (gba->memory.lastPrefetchedPc >= (uint32_t) gba->cpu->gprs[ARM_PC]) {
|
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;
|
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
|
// Reading this takes two cycles (1N+1I), so let's remove them preemptively
|
||||||
int32_t diff = gba->cpu->cycles - (currentTimer->lastEvent - gba->timing.masterCycles);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue