From 6dd996aabbfcd6c519e70ded3b54e44159deb685 Mon Sep 17 00:00:00 2001 From: Geoffrey Blake Date: Mon, 23 May 2011 10:40:18 -0500 Subject: [PATCH] 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. --- src/arch/arm/faults.cc | 2 ++ src/cpu/o3/fetch.hh | 3 +++ src/cpu/o3/fetch_impl.hh | 28 +++++++++++++++++++++------- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index 7dd81a681..3bd9f070c 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -219,6 +219,8 @@ AbortFault::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 diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 53f0f631e..92affc6db 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -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]; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 0f7d908d1..d3a2fc83f 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -346,6 +346,7 @@ DefaultFetch::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::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::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::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::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::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; } } -- 2.30.2