Faults generated at fetch are passed to the backend by creating a dummy nop instructi...
authorKevin Lim <ktlim@umich.edu>
Wed, 17 May 2006 18:25:10 +0000 (14:25 -0400)
committerKevin Lim <ktlim@umich.edu>
Wed, 17 May 2006 18:25:10 +0000 (14:25 -0400)
cpu/checker/cpu.cc:
    Fixups for fetch fault being sent with the instruction.
cpu/o3/fetch_impl.hh:
cpu/ozone/front_end_impl.hh:
    Send any faults generated at fetch along with a fake nop instruction to the back end.  This avoids having to use direct communication to check if the entire front end has drained; it is naturally handled through the nop's fault being handled when it reaches the head of commit.
cpu/ozone/front_end.hh:
    Add extra status TrapPending.
cpu/ozone/lw_back_end_impl.hh:
    Fetch fault handled through a dummy nop carrying the fetch fault.

    Avoid putting Nops on the exeList.

--HG--
extra : convert_revision : 8d9899748b34c204763a49c48a9b5113864f5789

cpu/checker/cpu.cc
cpu/o3/fetch_impl.hh
cpu/ozone/front_end.hh
cpu/ozone/front_end_impl.hh
cpu/ozone/lw_back_end_impl.hh

index f1b43f6017bf55793d90bc93a59d8951881a37c1..f76f1e0634e376e6c3bda9cdd9ff1f3210d7ae2c 100644 (file)
@@ -607,41 +607,46 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
         bool succeeded = translateInstReq(memReq);
 
         if (!succeeded) {
-            warn("Instruction PC %#x was not found in the ITB!",
-                 cpuXC->readPC());
-            handleError();
+            if (inst->getFault() == NoFault) {
+                warn("Instruction PC %#x was not found in the ITB!",
+                     cpuXC->readPC());
+                handleError();
 
-            // go to the next instruction
-            cpuXC->setPC(cpuXC->readNextPC());
-            cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
+                // go to the next instruction
+                cpuXC->setPC(cpuXC->readNextPC());
+                cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
 
-            return;
+                return;
+            } else {
+                fault = inst->getFault();
+            }
         }
 
-//    if (fault == NoFault)
+        if (fault == NoFault) {
 //        fault = cpuXC->mem->read(memReq, machInst);
-        cpuXC->mem->read(memReq, machInst);
+            cpuXC->mem->read(memReq, machInst);
 
-        // If we've got a valid instruction (i.e., no fault on instruction
-        // fetch), then execute it.
+            // If we've got a valid instruction (i.e., no fault on instruction
+            // fetch), then execute it.
 
         // keep an instruction count
-        numInst++;
+            numInst++;
 //     numInsts++;
 
-        // decode the instruction
-        machInst = gtoh(machInst);
-        // Checks that the instruction matches what we expected it to be.
-        // Checks both the machine instruction and the PC.
-        validateInst(inst);
+            // decode the instruction
+            machInst = gtoh(machInst);
+            // Checks that the instruction matches what we expected it to be.
+            // Checks both the machine instruction and the PC.
+            validateInst(inst);
 
-        curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
+            curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
 
 #if FULL_SYSTEM
-        cpuXC->setInst(machInst);
+            cpuXC->setInst(machInst);
 #endif // FULL_SYSTEM
 
-        fault = inst->getFault();
+            fault = inst->getFault();
+        }
 
         // Either the instruction was a fault and we should process the fault,
         // or we should just go ahead execute the instruction.  This assumes
index b4ff69d895ea0cdbb7f64df38bd57492a46a0e65..523719945fd9d8ab32e20d8078fe329a64dd6951 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2004-2006 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include "arch/isa_traits.hh"
-#include "sim/byteswap.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/o3/fetch.hh"
 #include "mem/base_mem.hh"
 #include "mem/mem_interface.hh"
 #include "mem/mem_req.hh"
-
+#include "sim/byteswap.hh"
 #include "sim/root.hh"
 
 #if FULL_SYSTEM
+#include "arch/tlb.hh"
+#include "arch/vtophys.hh"
 #include "base/remote_gdb.hh"
 #include "mem/functional/memory_control.hh"
 #include "mem/functional/physical.hh"
 #include "sim/system.hh"
-#include "arch/tlb.hh"
-#include "arch/vtophys.hh"
 #else // !FULL_SYSTEM
 #include "mem/functional/functional.hh"
 #endif // FULL_SYSTEM
@@ -136,14 +135,7 @@ DefaultFetch<Impl>::DefaultFetch(Params *params)
 
         // Create a new memory request.
         memReq[tid] = NULL;
-//        memReq[tid] = new MemReq();
-/*
-        // Need a way of setting this correctly for parallel programs
-        // @todo: Figure out how to properly set asid vs thread_num.
-        memReq[tid]->asid = tid;
-        memReq[tid]->thread_num = tid;
-        memReq[tid]->data = new uint8_t[64];
-*/
+
         // Create space to store a cache line.
         cacheData[tid] = new uint8_t[cacheBlkSize];
 
@@ -261,10 +253,6 @@ DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr)
     DPRINTF(Fetch, "Setting the CPU pointer.\n");
     cpu = cpu_ptr;
 
-    // Set ExecContexts for Memory Requests
-//    for (int tid=0; tid < numThreads; tid++)
-//        memReq[tid]->xc = cpu->xcBase(tid);
-
     // Fetch needs to start fetching instructions at the very beginning,
     // so it must start up in active state.
     switchToActive();
@@ -362,9 +350,8 @@ DefaultFetch<Impl>::processCacheCompletion(MemReqPtr &req)
 
 //    memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size);
 
-    // Reset the completion event to NULL.
+    // Reset the mem req to NULL.
     memReq[tid] = NULL;
-//    memReq[tid]->completionEvent = NULL;
 }
 
 template <class Impl>
@@ -468,10 +455,6 @@ template <class Impl>
 bool
 DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid)
 {
-    // Check if the instruction exists within the cache.
-    // If it does, then proceed on to read the instruction and the rest
-    // of the instructions in the cache line until either the end of the
-    // cache line or a predicted taken branch is encountered.
     Fault fault = NoFault;
 
 #if FULL_SYSTEM
@@ -509,7 +492,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
 //#endif
 
     // In the case of faults, the fetch stage may need to stall and wait
-    // on what caused the fetch (ITB or Icache miss).
+    // for the ITB miss to be handled.
 
     // If translation was successful, attempt to read the first
     // instruction.
@@ -518,7 +501,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
         if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) ||
             memReq[tid]->flags & UNCACHEABLE) {
             DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a "
-                    "misspeculating path!",
+                    "misspeculating path)!",
                     memReq[tid]->paddr);
             ret_fault = TheISA::genMachineCheckFault();
             return false;
@@ -587,44 +570,9 @@ DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
     if (fetchStatus[tid] == IcacheMissStall && icacheInterface) {
         DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
                 tid);
-//        icacheInterface->squash(tid);
-/*
-        if (memReq[tid]->completionEvent) {
-            if (memReq[tid]->completionEvent->scheduled()) {
-                memReq[tid]->completionEvent->squash();
-            } else {
-                delete memReq[tid]->completionEvent;
-                memReq[tid]->completionEvent = NULL;
-            }
-        }
-*/
         memReq[tid] = NULL;
     }
 
-    if (fetchStatus[tid] == TrapPending) {
-        // @todo: Hardcoded number here
-
-        // This is only effective if communication to and from commit
-        // is identical.  If it's faster to commit than it is from
-        // commit to here, then it causes problems.
-
-        bool found_fault = false;
-        for (int i = 0; i > -5; --i) {
-            if (fetchQueue->access(i)->fetchFault) {
-                DPRINTF(Fetch, "[tid:%i]: Fetch used to be in a trap, "
-                        "clearing it.\n",
-                        tid);
-                fetchQueue->access(i)->fetchFault = NoFault;
-                found_fault = true;
-            }
-        }
-        if (!found_fault) {
-            warn("%lli Fault from fetch not found in time buffer!",
-                 curTick);
-        }
-        toDecode->clearFetchFault = true;
-    }
-
     fetchStatus[tid] = Squashing;
 
     ++fetchSquashCycles;
@@ -643,7 +591,6 @@ DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
     // Tell the CPU to remove any instructions that are in flight between
     // fetch and decode.
     cpu->removeInstsUntil(seq_num, tid);
-    youngestSN = seq_num;
 }
 
 template<class Impl>
@@ -829,7 +776,6 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
 
         // In any case, squash.
         squash(fromCommit->commitInfo[tid].nextPC,tid);
-        youngestSN = fromCommit->commitInfo[tid].doneSeqNum;
 
         // Also check if there's a mispredict that happened.
         if (fromCommit->commitInfo[tid].branchMispredict) {
@@ -1009,8 +955,6 @@ DefaultFetch<Impl>::fetch(bool &status_change)
             // Get a sequence number.
             inst_seq = cpu->getAndIncrementInstSeq();
 
-            youngestSN = inst_seq;
-
             // Make sure this is a valid index.
             assert(offset <= cacheBlkSize - instSize);
 
@@ -1095,14 +1039,37 @@ DefaultFetch<Impl>::fetch(bool &status_change)
         // This stage will not be able to continue until all the ROB
         // slots are empty, at which point the fault can be handled.
         // The only other way it can wake up is if a squash comes along
-        // and changes the PC.  Not sure how to handle that case...perhaps
-        // have it handled by the upper level CPU class which peeks into the
-        // time buffer and sees if a squash comes along, in which case it
-        // changes the status.
+        // and changes the PC.
 #if FULL_SYSTEM
+        assert(numInst != fetchWidth);
+        // Get a sequence number.
+        inst_seq = cpu->getAndIncrementInstSeq();
+        // We will use a nop in order to carry the fault.
+        ext_inst = TheISA::NoopMachInst;
+
+        // Create a new DynInst from the dummy nop.
+        DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
+                                             next_PC,
+                                             inst_seq, cpu);
+        instruction->setPredTarg(next_PC + instSize);
+        instruction->setThread(tid);
+
+        instruction->setASID(tid);
+
+        instruction->setState(cpu->thread[tid]);
+
+        instruction->traceData = NULL;
+
+        instruction->setInstListIt(cpu->addInst(instruction));
+
+        instruction->fault = fault;
+
+        toDecode->insts[numInst] = instruction;
+        toDecode->size++;
+
         // Tell the commit stage the fault we had.
-        toDecode->fetchFault = fault;
-        toDecode->fetchFaultSN = cpu->globalSeqNum;
+//        toDecode->fetchFault = fault;
+//        toDecode->fetchFaultSN = cpu->globalSeqNum;
 
         DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid);
 
index f9db9ea5cf8ec7b823629f92c697c0a05c717e3c..326f7d2c9a18313cd1b807999118893b716ac6c4 100644 (file)
@@ -120,6 +120,7 @@ class FrontEnd
         SerializeComplete,
         RenameBlocked,
         QuiescePending,
+        TrapPending,
         BEBlocked
     };
 
index 8ae9ec696c81d845f18eaf28255bd695eb30b210..cd57aeef41389d3784ddd7af61cd25e7191b0274 100644 (file)
@@ -268,11 +268,9 @@ FrontEnd<Impl>::tick()
     }
 
     if (status == RenameBlocked || status == SerializeBlocked ||
-        status == BEBlocked) {
-        // This might cause the front end to run even though it
-        // shouldn't, but this should only be a problem for one cycle.
-        // Also will cause a one cycle bubble between changing state
-        // and restarting.
+        status == TrapPending || status == BEBlocked) {
+        // Will cause a one cycle bubble between changing state and
+        // restarting.
         DPRINTF(FE, "In blocked status.\n");
 
         fetchBlockedCycles++;
@@ -537,9 +535,32 @@ void
 FrontEnd<Impl>::handleFault(Fault &fault)
 {
     DPRINTF(FE, "Fault at fetch, telling commit\n");
-    backEnd->fetchFault(fault);
+//    backEnd->fetchFault(fault);
     // We're blocked on the back end until it handles this fault.
-    status = BEBlocked;
+    status = TrapPending;
+
+    // Get a sequence number.
+    InstSeqNum inst_seq = getAndIncrementInstSeq();
+    // We will use a nop in order to carry the fault.
+    ExtMachInst ext_inst = TheISA::NoopMachInst;
+
+    // Create a new DynInst from the dummy nop.
+    DynInstPtr instruction = new DynInst(ext_inst, PC,
+                                         PC+sizeof(MachInst),
+                                         inst_seq, cpu);
+    instruction->setPredTarg(instruction->readNextPC());
+//    instruction->setThread(tid);
+
+//    instruction->setASID(tid);
+
+    instruction->setState(thread);
+
+    instruction->traceData = NULL;
+
+    instruction->fault = fault;
+    instruction->setCanIssue();
+    instBuffer.push_back(instruction);
+    ++instBufferSize;
 }
 
 template <class Impl>
@@ -881,7 +902,6 @@ FrontEnd<Impl>::dumpInsts()
                 (*buff_it)->isSquashed());
         buff_it++;
     }
-
 }
 
 template <class Impl>
index a82dd5b70908d28fab319a9d4fb68db4b084ccdb..db0872e522d6a97afa31e13a25ddb3e23de9e16f 100644 (file)
@@ -652,7 +652,7 @@ LWBackEnd<Impl>::tick()
         squashFromTrap();
     } else if (xcSquash) {
         squashFromXC();
-    } else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) {
+    } /*else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) {
         DPRINTF(BE, "ROB and front end empty, handling fetch fault\n");
         Fault fetch_fault = frontEnd->getFault();
         if (fetch_fault == NoFault) {
@@ -662,7 +662,7 @@ LWBackEnd<Impl>::tick()
             handleFault(fetch_fault);
             fetchHasFault = false;
         }
-    }
+        }*/
 #endif
 
     if (dispatchStatus != Blocked) {
@@ -777,6 +777,12 @@ LWBackEnd<Impl>::dispatchInsts()
                             inst->seqNum);
                     exeList.push(inst);
                 }
+            } else if (inst->isNop()) {
+                DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n",
+                        inst->seqNum);
+                inst->setIssued();
+                inst->setExecuted();
+                inst->setCanCommit();
             } else {
                 DPRINTF(BE, "Instruction [sn:%lli] ready, addding to exeList.\n",
                         inst->seqNum);