O3: Fix issue with interrupts/faults occuring in the middle of a macro-op
authorGeoffrey Blake <geoffrey.blake@arm.com>
Mon, 23 May 2011 15:40:18 +0000 (10:40 -0500)
committerGeoffrey Blake <geoffrey.blake@arm.com>
Mon, 23 May 2011 15:40:18 +0000 (10:40 -0500)
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
src/cpu/o3/fetch.hh
src/cpu/o3/fetch_impl.hh

index 7dd81a68138cb6fa7caa0b64629de7aff5e49180..3bd9f070c3275d8401bd61e3442b3b7f594c404f 100644 (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
index 53f0f631e87cae17638b763994cc28137446c1cc..92affc6dbb15b69163e1f57948509f5752c7d739 100644 (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];
 
index 0f7d908d115371569fad6cfb172c3d676ebdee91..d3a2fc83f9ecca632cc3b2adb430f4ff7205705b 100644 (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;
                 }
             }