inorder: use setupSquash for misspeculation
authorKorey Sewell <ksewell@umich.edu>
Mon, 20 Jun 2011 01:43:35 +0000 (21:43 -0400)
committerKorey Sewell <ksewell@umich.edu>
Mon, 20 Jun 2011 01:43:35 +0000 (21:43 -0400)
implement a clean interface to handle branch misprediction and eventually all pipeline
flushing

src/cpu/inorder/cpu.cc
src/cpu/inorder/cpu.hh
src/cpu/inorder/inorder_dyn_inst.cc
src/cpu/inorder/inorder_dyn_inst.hh
src/cpu/inorder/resource.cc
src/cpu/inorder/resource.hh
src/cpu/inorder/resources/branch_predictor.cc
src/cpu/inorder/resources/execution_unit.cc
src/cpu/inorder/resources/fetch_seq_unit.cc

index ce3796528370ebfe95737a694c46d16a4f4cca62..2e3b0188b04f5b3e4c91c8c2b637086291e38853 100644 (file)
@@ -1272,6 +1272,24 @@ InOrderCPU::addInst(DynInstPtr inst)
     return --(instList[tid].end());
 }
 
+InOrderCPU::ListIt
+InOrderCPU::findInst(InstSeqNum seq_num, ThreadID tid)
+{
+    ListIt it = instList[tid].begin();
+    ListIt end = instList[tid].end();
+
+    while (it != end) {
+        if ((*it)->seqNum == seq_num)
+            return it;
+        else if ((*it)->seqNum > seq_num)
+            break;
+
+        it++;
+    }
+
+    return instList[tid].end();
+}
+
 void 
 InOrderCPU::updateContextSwitchStats()
 {
index a1fc2de52243862539db3ebb729b7e4fd5b80e26..aad701ff4d8b94e4f0fac89f1d7343541208384f 100644 (file)
@@ -581,6 +581,9 @@ class InOrderCPU : public BaseCPU
      */
     ListIt addInst(DynInstPtr inst);
 
+    /** Find instruction on instruction list */
+    ListIt findInst(InstSeqNum seq_num, ThreadID tid);
+
     /** Function to tell the CPU that an instruction has completed. */
     void instDone(DynInstPtr inst, ThreadID tid);
 
index 1bbd4f639f0662bb56f210583acb326da1df907d..d8bfbacc7a333e82d9d3e75e0ebad47441ef1c6d 100644 (file)
@@ -315,6 +315,28 @@ InOrderDynInst::syscall(int64_t callnum)
 }
 #endif
 
+void
+InOrderDynInst::setSquashInfo(unsigned stage_num)
+{
+    squashingStage = stage_num;
+    bdelaySeqNum = seqNum;
+
+#if ISA_HAS_DELAY_SLOT
+    if (isControl()) {
+        TheISA::PCState nextPC = pc;
+        TheISA::advancePC(nextPC, staticInst);
+
+        // Check to see if we should squash after the
+        // branch or after a branch delay slot.
+        if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
+            bdelaySeqNum = seqNum + 1;
+        else
+            bdelaySeqNum = seqNum;
+
+    }
+#endif
+}
+
 void
 InOrderDynInst::releaseReq(ResourceRequest* req)
 {
index ff60120a3318b894a70229382b2e58ef17d1d525..73e723312b295e3ad4d5341d0a209d710106aa09 100644 (file)
@@ -576,6 +576,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
 
     bool procDelaySlotOnMispred;
 
+    void setSquashInfo(unsigned stage_num);
+
     ////////////////////////////////////////////
     //
     // MEMORY ACCESS
index cad5cfb09911789ad106e51200973fda3f848f13..23d33afbede6b6aa0e92ad8713c99e6dd6bdaaf5 100644 (file)
@@ -35,6 +35,7 @@
 #include "base/str.hh"
 #include "cpu/inorder/cpu.hh"
 #include "cpu/inorder/resource.hh"
+#include "cpu/inorder/resource_pool.hh"
 #include "debug/RefCount.hh"
 #include "debug/ResReqCount.hh"
 #include "debug/Resource.hh"
@@ -286,6 +287,18 @@ Resource::deactivateThread(ThreadID tid)
     squash(dummy_inst, 0, 0, tid);
 }
 
+void
+Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
+{
+    assert(inst->isControl() && "Function Assumes Squash From A Branch");
+
+    // Squash In Pipeline Stage
+    cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+
+    // Schedule Squash Through-out Resource Pool
+    cpu->resPool->scheduleEvent(
+        (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
+}
 void
 Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
                  ThreadID tid)
index 0f2cde7d1c0bc6f190ed275e5b1e11297d1bac4f..09749736242c1dd1ec3bf47ac235e1ff14c742f9 100644 (file)
@@ -154,10 +154,14 @@ class Resource {
     virtual Fault doCacheAccess(DynInstPtr inst, uint64_t *res=NULL)
     { panic("doCacheAccess undefined for %s", name()); return NoFault; }
 
+    /** Setup Squash to be sent out to pipeline and resource pool */
+    void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid);
+
     /** Squash All Requests After This Seq Num */
     virtual void squash(DynInstPtr inst, int stage_num,
                         InstSeqNum squash_seq_num, ThreadID tid);
 
+    /** Squash Requests Due to a Memory Stall (By Default, same as "squash" */
     virtual void squashDueToMemStall(DynInstPtr inst, int stage_num,
                                      InstSeqNum squash_seq_num, ThreadID tid);
 
index a349918540caf9cb693012a02a09caa9902062ac..3132770d43caa1db00b9ba6d1a0e8653b15a958f 100644 (file)
@@ -148,19 +148,15 @@ void
 BranchPredictor::squash(DynInstPtr inst, int squash_stage,
                         InstSeqNum squash_seq_num, ThreadID tid)
 {
-    DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid, inst->seqNum);
-
-#if ISA_HAS_DELAY_SLOT
-    // We need to squash the actual branch , NOT the delay slot
-    // in the branch predictor
-    //squash_seq_num = squash_seq_num - 1;
-#endif
+    InstSeqNum bpred_squash_num = inst->seqNum;
+    DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid,
+            bpred_squash_num);
 
     if (squash_stage >= ThePipeline::BackEndStartStage) {
         bool taken = inst->predTaken();
-        branchPred.squash(squash_seq_num, inst->readPredTarg(), taken, tid);
+        branchPred.squash(bpred_squash_num, inst->readPredTarg(), taken, tid);
     } else {
-        branchPred.squash(squash_seq_num, tid);
+        branchPred.squash(bpred_squash_num, tid);
     }
 }
 
index ca1f4ade4c7b00cc8ecac94e4eabc27c28dd0624..4363f125d8240c7f9476b16ae14ea623c8b02e60 100644 (file)
@@ -143,87 +143,30 @@ ExecutionUnit::execute(int slot_num)
                 inst->setExecuted();
 
                 if (fault == NoFault) {
-                    // If branch is mispredicted, then signal squash
-                    // throughout all stages behind the pipeline stage
-                    // that got squashed.
                     if (inst->mispredicted()) {
-                        int stage_num = exec_req->getStageNum();
-                        ThreadID tid = inst->readTid();
-                        // If it's a branch ...
-                        if (inst->isDirectCtrl()) {
-                            assert(!inst->isIndirectCtrl());
-
-                            TheISA::PCState pc = inst->pcState();
-                            TheISA::advancePC(pc, inst->staticInst);
-                            inst->setPredTarg(pc);
-
-                            if (inst->predTaken() && inst->isCondDelaySlot()) {
-                                assert(0 && "Not Handling Conditional Delay Slots (1)");
-                                inst->bdelaySeqNum = seq_num;
-                                DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
-                                        " branch inst [sn:%i] PC %s mis"
-                                        "predicted as taken.\n", tid,
-                                        seq_num, inst->pcState());
-                            } else if (!inst->predTaken() && inst->isCondDelaySlot()) {
-                                assert(0 && "Not Handling Conditional Delay Slots (2)");
-                                inst->bdelaySeqNum = seq_num;
-                                inst->procDelaySlotOnMispred = true;
-
-                                DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
-                                        " branch inst [sn:%i] PC %s mis"
-                                        "predicted as not taken.\n", tid,
-                                        seq_num, inst->pcState());
-                            } else {
-                                inst->bdelaySeqNum = seq_num;
-
-                                DPRINTF(InOrderExecute, "[tid:%i]: "
-                                        "Misprediction detected at "
-                                        "[sn:%i] PC %s,\n\t squashing after "
-                                        "delay slot instruction [sn:%i].\n",
-                                        tid, seq_num, inst->pcState(),
-                                        inst->bdelaySeqNum);
-                                DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
-                                        " misprediction at %s\n",
-                                        tid, inst->pcState());
-                            }
-
-                            DPRINTF(InOrderExecute, "[tid:%i] Redirecting "
-                                    "fetch to %s.\n", tid,
-                                    inst->readPredTarg());
-
-                        } else if (inst->isIndirectCtrl()){
-                            TheISA::PCState pc = inst->pcState();
-                            TheISA::advancePC(pc, inst->staticInst);
-                            inst->seqNum = seq_num;
-                            inst->setPredTarg(pc);
-
-                            inst->bdelaySeqNum = seq_num;
+                        assert(inst->isControl());
 
-                            DPRINTF(InOrderExecute, "[tid:%i] Redirecting"
-                                    " fetch to %s.\n", tid,
-                                    inst->readPredTarg());
-                        } else {
-                            panic("Non-control instruction (%s) mispredict"
-                                  "ing?!!", inst->staticInst->getName());
-                        }
-
-                        DPRINTF(InOrderExecute, "[tid:%i] Squashing will "
-                                "start from stage %i.\n", tid, stage_num);
-
-                        cpu->pipelineStage[stage_num]->squashDueToBranch(inst,
-                                                                         tid);
+                        // Set up Squash Generated By this Misprediction
+                        unsigned stage_num = exec_req->getStageNum();
+                        ThreadID tid = inst->readTid();
+                        TheISA::PCState pc = inst->pcState();
+                        TheISA::advancePC(pc, inst->staticInst);
+                        inst->setPredTarg(pc);
+                        inst->setSquashInfo(stage_num);
 
-                        inst->squashingStage = stage_num;
+                        setupSquash(inst, stage_num, tid);
 
-                        // Squash throughout other resources
-                        cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)
-                                                    ResourcePool::SquashAll,
-                                                    inst, 0, 0, tid);
+                        DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i] Squashing from "
+                                "stage %i. Redirecting  fetch to %s.\n", tid,
+                                inst->seqNum, stage_num, pc);
+                        DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
+                                " misprediction at %s\n", tid, inst->pcState());
 
                         if (inst->predTaken()) {
                             predictedTakenIncorrect++;
                             DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
-                                    "PC %s ... Mispredicts! (Taken)\n",
+                                    "PC %s ... Mispredicts! "
+                                    "(Prediction: Taken)\n",
                                     tid, inst->seqNum,
                                     inst->staticInst->disassemble(
                                         inst->instAddr()),
@@ -231,7 +174,8 @@ ExecutionUnit::execute(int slot_num)
                         } else {
                             predictedNotTakenIncorrect++;
                             DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
-                                    "PC %s ... Mispredicts! (Not Taken)\n",
+                                    "PC %s ... Mispredicts! "
+                                    "(Prediction: Not Taken)\n",
                                     tid, inst->seqNum,
                                     inst->staticInst->disassemble(
                                         inst->instAddr()),
@@ -247,7 +191,7 @@ ExecutionUnit::execute(int slot_num)
                     exec_req->done();
                 } else {
                     warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
-
+                    inst->fault = fault;
                     exec_req->done();
                 }
             } else {
index 579f9d45b6f645e5353db37a7549c271e19e213b..62dbb452ada028780ed80e6639edf97238748f2c 100644 (file)
@@ -78,7 +78,6 @@ FetchSeqUnit::execute(int slot_num)
     DynInstPtr inst = fs_req->inst;
     ThreadID tid = inst->readTid();
     int stage_num = fs_req->getStageNum();
-    InstSeqNum seq_num = inst->seqNum;
 
     DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
             pc[tid]);
@@ -109,48 +108,26 @@ FetchSeqUnit::execute(int slot_num)
 
       case UpdateTargetPC:
         {
+            assert(!inst->isCondDelaySlot()  &&
+                   "Not Handling Conditional Delay Slot");
+
             if (inst->isControl()) {
-                // If it's a return, then we must wait for resolved address.
-                // The Predictor will mark a return a false as "not taken"
-                // if there is no RAS entry
                 if (inst->isReturn() && !inst->predTaken()) {
+                    // If it's a return, then we must wait for resolved address.
+                    // The Predictor will mark a return a false as "not taken"
+                    // if there is no RAS entry
                     cpu->pipelineStage[stage_num]->
                         toPrevStages->stageBlock[stage_num][tid] = true;
                     pcValid[tid] = false;
                     pcBlockStage[tid] = stage_num;
-                } else if (inst->isCondDelaySlot() && !inst->predTaken()) {
-                    assert(0 && "Not Handling Conditional Delay Slot");
-                    // Not-Taken AND Conditional Control
-                    DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%s] "
-                            "Predicted Not-Taken Cond. Delay inst. Skipping "
-                            "delay slot and  Updating PC to %s\n",
-                            tid, inst->seqNum, inst->pcState(),
-                            inst->readPredTarg());
-
-                    DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
-                            "start from stage %i, after [sn:%i].\n", tid,
-                            stage_num, seq_num);
-
-                    inst->bdelaySeqNum = seq_num;
-                    inst->squashingStage = stage_num;
-
-                    squashAfterInst(inst, stage_num, tid);
-                } else if (!inst->isCondDelaySlot() && !inst->predTaken()) {
-                    // Not-Taken Control
-                    DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted "
-                            "Not-Taken Control "
-                            "inst. updating PC to %s\n", tid, inst->seqNum,
-                            inst->readPredTarg());
                 } else if (inst->predTaken()) {
                     // Taken Control
-                    inst->bdelaySeqNum = seq_num;
-                    inst->squashingStage = stage_num;
+                    inst->setSquashInfo(stage_num);
+                    setupSquash(inst, stage_num, tid);
+
                     DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
                             "start from stage %i, after [sn:%i].\n",
                             tid, stage_num, inst->bdelaySeqNum);
-
-                    // Do Squashing
-                    squashAfterInst(inst, stage_num, tid);
                 }
             } else {
                 DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch "
@@ -167,17 +144,6 @@ FetchSeqUnit::execute(int slot_num)
     }
 }
 
-inline void
-FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, ThreadID tid)
-{
-    // Squash In Pipeline Stage
-    cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
-
-    // Schedule Squash Through-out Resource Pool
-    cpu->resPool->scheduleEvent(
-            (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
-}
-
 void
 FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
                      InstSeqNum squash_seq_num, ThreadID tid)
@@ -185,25 +151,6 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
     DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from %s (%s) "
             "stage %i.\n", tid, inst->instName(), inst->pcState(),
             squash_stage);
-    assert(squash_seq_num == inst->seqNum);
-
-    TheISA::PCState nextPC = inst->pcState();
-    assert(inst->staticInst);
-    advancePC(nextPC, inst->staticInst);
-
-#if ISA_HAS_DELAY_SLOT
-    if (inst->isControl()) {
-        if (inst->onInstList) {
-            ListIt inst_it = inst->getInstListIt();
-            inst_it++;
-            if (inst_it != cpu->instList[tid].end())  {
-                DynInstPtr delaySlotInst = (*inst_it);
-                if (delaySlotInst->pcState() != nextPC)
-                    squash_seq_num = delaySlotInst->seqNum;
-            }
-        }
-    }
-#endif
 
     if (squashSeqNum[tid] <= squash_seq_num &&
         lastSquashCycle[tid] == curTick()) {
@@ -214,6 +161,45 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
         squashSeqNum[tid] = squash_seq_num;
         lastSquashCycle[tid] = curTick();
 
+        TheISA::PCState nextPC;
+        assert(inst->staticInst);
+        if (inst->isControl()) {
+            nextPC = inst->readPredTarg();
+
+            // If we are already fetching this PC then advance to next PC
+            // =======
+            // This should handle ISAs w/delay slots and annulled delay
+            // slots to figure out which is the next PC to fetch after
+            // a mispredict
+            DynInstPtr bdelay_inst = NULL;
+            ListIt bdelay_it;
+            if (inst->onInstList) {
+                bdelay_it = inst->getInstListIt();
+                bdelay_it++;
+            } else {
+                InstSeqNum branch_delay_num = inst->seqNum + 1;
+                bdelay_it = cpu->findInst(branch_delay_num, tid);
+            }
+
+            if (bdelay_it != cpu->instList[tid].end()) {
+                bdelay_inst = (*bdelay_it);
+            }
+
+            if (bdelay_inst) {
+                DPRINTF(Resource, "Evaluating %s v. %s\n",
+                        bdelay_inst->pc, nextPC);
+
+                if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
+                    advancePC(nextPC, inst->staticInst);
+                    DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
+                }
+            }
+        } else {
+            nextPC = inst->pcState();
+            advancePC(nextPC, inst->staticInst);
+        }
+
+
         DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
                 tid, nextPC);
         pc[tid] = nextPC;