O3: Fix issue with interrupts/faults occuring in the middle of a macro-op

This patch fixes two problems with the O3 cpu model. The first is an issue
with an instruction fetch causing a fault on the next address while the
current macro-op is being issued. This happens when the micro-ops exceed
the fetch bandwdith and then on the next cycle the fetch stage attempts
to issue a request to the next line while it still has micro-ops to issue
if the next line faults a fault is attached to a micro-op in the currently
executing macro-op rather than a "nop" from the next instruction block.
This leads to an instruction incorrectly faulting when on fetch when
it had no reason to fault.

A similar problem occurs with interrupts. When an interrupt occurs the
fetch stage nominally stops issuing instructions immediately. This is incorrect
in the case of a macro-op as the current location might not be interruptable.
This commit is contained in:
Geoffrey Blake 2011-05-23 10:40:18 -05:00
parent fc1d2d9679
commit 6dd996aabb
3 changed files with 26 additions and 7 deletions

View file

@ -219,6 +219,8 @@ AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
fsr.ext = 0;
tc->setMiscReg(T::FsrIndex, fsr);
tc->setMiscReg(T::FarIndex, faultAddr);
DPRINTF(Faults, "Abort Fault fsr=%#x faultAddr=%#x\n", fsr, faultAddr);
}
void

View file

@ -403,6 +403,9 @@ class DefaultFetch
StaticInstPtr macroop[Impl::MaxThreads];
/** Can the fetch stage redirect from an interrupt on this instruction? */
bool delayedCommit[Impl::MaxThreads];
/** Memory request used to access cache. */
RequestPtr memReq[Impl::MaxThreads];

View file

@ -346,6 +346,7 @@ DefaultFetch<Impl>::initStage()
pc[tid] = cpu->pcState(tid);
fetchOffset[tid] = 0;
macroop[tid] = NULL;
delayedCommit[tid] = false;
}
for (ThreadID tid = 0; tid < numThreads; tid++) {
@ -1070,6 +1071,9 @@ DefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
assert(numInst < fetchWidth);
toDecode->insts[toDecode->size++] = instruction;
// Keep track of if we can take an interrupt at this boundary
delayedCommit[tid] = instruction->isDelayedCommit();
return instruction;
}
@ -1112,8 +1116,11 @@ DefaultFetch<Impl>::fetch(bool &status_change)
// Align the fetch PC so its at the start of a cache block.
Addr block_PC = icacheBlockAlignPC(fetchAddr);
// Unless buffer already got the block, fetch it from icache.
if (!(cacheDataValid[tid] && block_PC == cacheDataPC[tid]) && !inRom) {
// If buffer is no longer valid or fetchAddr has moved to point
// to the next cache block, AND we have no remaining ucode
// from a macro-op, then start fetch from icache.
if (!(cacheDataValid[tid] && block_PC == cacheDataPC[tid])
&& !inRom && !macroop[tid]) {
DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
"instruction, starting at PC %s.\n", tid, thisPC);
@ -1126,7 +1133,11 @@ DefaultFetch<Impl>::fetch(bool &status_change)
else
++fetchMiscStallCycles;
return;
} else if (checkInterrupt(thisPC.instAddr()) || isSwitchedOut()) {
} else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])
|| isSwitchedOut()) {
// Stall CPU if an interrupt is posted and we're not issuing
// an delayed commit micro-op currently (delayed commit instructions
// are not interruptable by interrupts, only faults)
++fetchMiscStallCycles;
return;
}
@ -1184,9 +1195,11 @@ DefaultFetch<Impl>::fetch(bool &status_change)
unsigned blkOffset = (fetchAddr - cacheDataPC[tid]) / instSize;
// Loop through instruction memory from the cache.
while (blkOffset < numInsts &&
numInst < fetchWidth &&
!predictedBranch) {
// Keep issuing while we have not reached the end of the block or a
// macroop is active and fetchWidth is available and branch is not
// predicted taken
while ((blkOffset < numInsts || curMacroop) &&
numInst < fetchWidth && !predictedBranch) {
// If we need to process more memory, do it now.
if (!(curMacroop || inRom) && !predecoder.extMachInstReady()) {
@ -1232,7 +1245,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
pcOffset = 0;
}
} else {
// We need more bytes for this instruction.
// We need more bytes for this instruction so blkOffset and
// pcOffset will be updated
break;
}
}