Fixes to get MIPS_SE to compile.
[gem5.git] / src / cpu / o3 / bpred_unit_impl.hh
index a6311527b8fadf5badf752e0337ca16cc0de88ca..dbc603082db32a16268b065e210e4d67919ed553 100644 (file)
  * Authors: Kevin Lim
  */
 
+#include "arch/types.hh"
+#include "arch/isa_traits.hh"
 #include "base/trace.hh"
 #include "base/traceflags.hh"
 #include "cpu/o3/bpred_unit.hh"
 
 template<class Impl>
-TwobitBPredUnit<Impl>::TwobitBPredUnit(Params &params)
-  : BP(params.local_predictor_size,
-       params.local_ctr_bits,
-       params.instShiftAmt),
-    BTB(params.BTBEntries,
-        params.BTBTagSize,
-        params.instShiftAmt),
-    RAS(params.RASSize)
+BPredUnit<Impl>::BPredUnit(Params *params)
+  : BTB(params->BTBEntries,
+        params->BTBTagSize,
+        params->instShiftAmt)
 {
+    // Setup the selected predictor.
+    if (params->predType == "local") {
+        localBP = new LocalBP(params->localPredictorSize,
+                              params->localCtrBits,
+                              params->instShiftAmt);
+        predictor = Local;
+    } else if (params->predType == "tournament") {
+        tournamentBP = new TournamentBP(params->localPredictorSize,
+                                        params->localCtrBits,
+                                        params->localHistoryTableSize,
+                                        params->localHistoryBits,
+                                        params->globalPredictorSize,
+                                        params->globalHistoryBits,
+                                        params->globalCtrBits,
+                                        params->choicePredictorSize,
+                                        params->choiceCtrBits,
+                                        params->instShiftAmt);
+        predictor = Tournament;
+    } else {
+        fatal("Invalid BP selected!");
+    }
+
+    for (int i=0; i < Impl::MaxThreads; i++)
+        RAS[i].init(params->RASSize);
 }
 
 template <class Impl>
 void
-TwobitBPredUnit<Impl>::regStats()
+BPredUnit<Impl>::regStats()
 {
     lookups
         .name(name() + ".BPredUnit.lookups")
@@ -81,7 +103,7 @@ TwobitBPredUnit<Impl>::regStats()
 
     usedRAS
         .name(name() + ".BPredUnit.usedRAS")
-        .desc("Number of times the RAS was used.")
+        .desc("Number of times the RAS was used to get a target.")
         ;
 
     RASIncorrect
@@ -90,13 +112,37 @@ TwobitBPredUnit<Impl>::regStats()
         ;
 }
 
+template <class Impl>
+void
+BPredUnit<Impl>::switchOut()
+{
+    // Clear any state upon switch out.
+    for (int i = 0; i < Impl::MaxThreads; ++i) {
+        squash(0, i);
+    }
+}
+
+template <class Impl>
+void
+BPredUnit<Impl>::takeOverFrom()
+{
+    // Can reset all predictor state, but it's not necessarily better
+    // than leaving it be.
+/*
+    for (int i = 0; i < Impl::MaxThreads; ++i)
+        RAS[i].reset();
+
+    BP.reset();
+    BTB.reset();
+*/
+}
+
 template <class Impl>
 bool
-TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
+BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
 {
     // See if branch predictor predicts taken.
     // If so, get its target addr either from the BTB or the RAS.
-    // Once that's done, speculatively update the predictor?
     // Save off record of branch stuff so the RAS can be fixed
     // up once it's done.
 
@@ -107,19 +153,25 @@ TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
 
     ++lookups;
 
+    void *bp_history = NULL;
+
     if (inst->isUncondCtrl()) {
-        DPRINTF(Fetch, "BranchPred: Unconditional control.\n");
+        DPRINTF(Fetch, "BranchPred: [tid:%i]: Unconditional control.\n", tid);
         pred_taken = true;
+        // Tell the BP there was an unconditional branch.
+        BPUncond(bp_history);
     } else {
         ++condPredicted;
 
-        pred_taken = BPLookup(PC);
+        pred_taken = BPLookup(PC, bp_history);
 
-        DPRINTF(Fetch, "BranchPred: Branch predictor predicted %i for PC %#x"
-                "\n", pred_taken, inst->readPC());
+        DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+                "for PC %#x\n",
+                tid, pred_taken, inst->readPC());
     }
 
-    PredictorHistory predict_record(inst->seqNum, PC, pred_taken);
+    PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+                                    bp_history, tid);
 
     // Now lookup in the BTB or RAS.
     if (pred_taken) {
@@ -128,151 +180,225 @@ TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
 
             // If it's a function return call, then look up the address
             // in the RAS.
-            target = RAS.top();
+            target = RAS[tid].top();
 
             // Record the top entry of the RAS, and its index.
             predict_record.usedRAS = true;
-            predict_record.RASIndex = RAS.topIdx();
+            predict_record.RASIndex = RAS[tid].topIdx();
             predict_record.RASTarget = target;
 
-            RAS.pop();
+            assert(predict_record.RASIndex < 16);
+
+            RAS[tid].pop();
 
-            DPRINTF(Fetch, "BranchPred: Instruction %#x is a return, RAS "
-                    "predicted target: %#x, RAS index: %i.\n",
-                    inst->readPC(), target, predict_record.RASIndex);
+            DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, "
+                    "RAS predicted target: %#x, RAS index: %i.\n",
+                    tid, inst->readPC(), target, predict_record.RASIndex);
         } else {
             ++BTBLookups;
 
             if (inst->isCall()) {
-                RAS.push(PC+sizeof(MachInst));
+#if ISA_HAS_DELAY_SLOT
+                Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
+#else
+                Addr ras_pc = PC + sizeof(MachInst); // Next PC
+#endif
+                RAS[tid].push(ras_pc);
 
                 // Record that it was a call so that the top RAS entry can
                 // be popped off if the speculation is incorrect.
                 predict_record.wasCall = true;
 
-                DPRINTF(Fetch, "BranchPred: Instruction %#x was a call, "
-                        "adding %#x to the RAS.\n",
-                        inst->readPC(), PC+sizeof(MachInst));
+                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x was a call"
+                        ", adding %#x to the RAS index: %i.\n",
+                        tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
             }
 
-            if (BTB.valid(PC)) {
+            if (BTB.valid(PC, tid)) {
                 ++BTBHits;
 
-                //If it's anything else, use the BTB to get the target addr.
-                target = BTB.lookup(PC);
+                // If it's not a return, use the BTB to get the target addr.
+                target = BTB.lookup(PC, tid);
 
-                DPRINTF(Fetch, "BranchPred: Instruction %#x predicted target "
-                        "is %#x.\n", inst->readPC(), target);
+                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
+                        " target is %#x.\n",
+                        tid, inst->readPC(), target);
 
             } else {
-                DPRINTF(Fetch, "BranchPred: BTB doesn't have a valid entry."
-                        "\n");
+                DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
+                        "valid entry.\n",tid);
                 pred_taken = false;
             }
 
         }
     }
 
-    if (pred_taken) {
-        // Set the PC and the instruction's predicted target.
-        PC = target;
-        inst->setPredTarg(target);
-    } else {
-        PC = PC + sizeof(MachInst);
-        inst->setPredTarg(PC);
-    }
-
-    predHist.push_front(predict_record);
+    predHist[tid].push_front(predict_record);
 
-    assert(!predHist.empty());
+    DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());
 
     return pred_taken;
 }
 
 template <class Impl>
 void
-TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn)
+BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid)
 {
-    DPRINTF(Fetch, "BranchPred: Commiting branches until sequence number "
-            "%i.\n", done_sn);
+    DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until "
+            "[sn:%lli].\n", tid, done_sn);
 
-    while (!predHist.empty() && predHist.back().seqNum <= done_sn) {
-        assert(!predHist.empty());
+    while (!predHist[tid].empty() &&
+           predHist[tid].back().seqNum <= done_sn) {
+        // Update the branch predictor with the correct results.
+        BPUpdate(predHist[tid].back().PC,
+                 predHist[tid].back().predTaken,
+                 predHist[tid].back().bpHistory);
 
-        // Update the branch predictor with the correct results of branches.
-        BP.update(predHist.back().PC, predHist.back().predTaken);
-
-        predHist.pop_back();
+        predHist[tid].pop_back();
     }
 }
 
 template <class Impl>
 void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn)
+BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid)
 {
-    while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
-        if (predHist.front().usedRAS) {
-            DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
-                    "target: %#x.\n",
-                    predHist.front().RASIndex,
-                    predHist.front().RASTarget);
-
-            RAS.restore(predHist.front().RASIndex,
-                        predHist.front().RASTarget);
-        } else if (predHist.front().wasCall) {
-            DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
-                    "to the RAS.\n");
-
-            RAS.pop();
+    History &pred_hist = predHist[tid];
+
+    while (!pred_hist.empty() &&
+           pred_hist.front().seqNum > squashed_sn) {
+        if (pred_hist.front().usedRAS) {
+            DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
+                    " target: %#x.\n",
+                    tid,
+                    pred_hist.front().RASIndex,
+                    pred_hist.front().RASTarget);
+
+            RAS[tid].restore(pred_hist.front().RASIndex,
+                             pred_hist.front().RASTarget);
+        } else if (pred_hist.front().wasCall) {
+            DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry "
+                    "added to the RAS.\n",tid);
+
+            RAS[tid].pop();
         }
 
-        predHist.pop_front();
+        // This call should delete the bpHistory.
+        BPSquash(pred_hist.front().bpHistory);
+
+        pred_hist.pop_front();
     }
+
 }
 
 template <class Impl>
 void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
-                              const Addr &corr_target,
-                              const bool actually_taken)
+BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
+                        const Addr &corr_target,
+                        const bool actually_taken,
+                        unsigned tid)
 {
     // Now that we know that a branch was mispredicted, we need to undo
     // all the branches that have been seen up until this branch and
     // fix up everything.
 
+    History &pred_hist = predHist[tid];
+
     ++condIncorrect;
 
-    DPRINTF(Fetch, "BranchPred: Squashing from sequence number %i, "
+    DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
             "setting target to %#x.\n",
-            squashed_sn, corr_target);
+            tid, squashed_sn, corr_target);
 
-    while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
+    squash(squashed_sn, tid);
 
-        if (predHist.front().usedRAS) {
-            DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
-                    "target: %#x.\n",
-                    predHist.front().RASIndex,
-                    predHist.front().RASTarget);
+    // If there's a squash due to a syscall, there may not be an entry
+    // corresponding to the squash.  In that case, don't bother trying to
+    // fix up the entry.
+    if (!pred_hist.empty()) {
+        assert(pred_hist.front().seqNum == squashed_sn);
+        if (pred_hist.front().usedRAS) {
+            ++RASIncorrect;
+        }
 
-            RAS.restore(predHist.front().RASIndex,
-                        predHist.front().RASTarget);
-        } else if (predHist.front().wasCall) {
-            DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
-                    "to the RAS.\n");
+        BPUpdate(pred_hist.front().PC, actually_taken,
+                 pred_hist.front().bpHistory);
 
-            RAS.pop();
-        }
+        BTB.update(pred_hist.front().PC, corr_target, tid);
+        pred_hist.pop_front();
+    }
+}
 
-        predHist.pop_front();
+template <class Impl>
+void
+BPredUnit<Impl>::BPUncond(void * &bp_history)
+{
+    // Only the tournament predictor cares about unconditional branches.
+    if (predictor == Tournament) {
+        tournamentBP->uncondBr(bp_history);
     }
+}
 
-    predHist.front().predTaken = actually_taken;
+template <class Impl>
+void
+BPredUnit<Impl>::BPSquash(void *bp_history)
+{
+    if (predictor == Local) {
+        localBP->squash(bp_history);
+    } else if (predictor == Tournament) {
+        tournamentBP->squash(bp_history);
+    } else {
+        panic("Predictor type is unexpected value!");
+    }
+}
+
+template <class Impl>
+bool
+BPredUnit<Impl>::BPLookup(Addr &inst_PC, void * &bp_history)
+{
+    if (predictor == Local) {
+        return localBP->lookup(inst_PC, bp_history);
+    } else if (predictor == Tournament) {
+        return tournamentBP->lookup(inst_PC, bp_history);
+    } else {
+        panic("Predictor type is unexpected value!");
+    }
+}
 
-    if (predHist.front().usedRAS) {
-        ++RASIncorrect;
+template <class Impl>
+void
+BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+{
+    if (predictor == Local) {
+        localBP->update(inst_PC, taken, bp_history);
+    } else if (predictor == Tournament) {
+        tournamentBP->update(inst_PC, taken, bp_history);
+    } else {
+        panic("Predictor type is unexpected value!");
     }
+}
 
-    BP.update(predHist.front().PC, actually_taken);
+template <class Impl>
+void
+BPredUnit<Impl>::dump()
+{
+    typename History::iterator pred_hist_it;
+
+    for (int i = 0; i < Impl::MaxThreads; ++i) {
+        if (!predHist[i].empty()) {
+            pred_hist_it = predHist[i].begin();
 
-    BTB.update(predHist.front().PC, corr_target);
+            cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
+
+            while (pred_hist_it != predHist[i].end()) {
+                cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
+                        "bpHistory:%#x\n",
+                        (*pred_hist_it).seqNum, (*pred_hist_it).PC,
+                        (*pred_hist_it).tid, (*pred_hist_it).predTaken,
+                        (*pred_hist_it).bpHistory);
+                pred_hist_it++;
+            }
+
+            cprintf("\n");
+        }
+    }
 }