cpu: re-organizes the branch predictor structure.

Committed by: Nilay Vaish <nilay@cs.wisc.edu>
This commit is contained in:
Dibakar Gope 2015-04-13 17:33:57 -05:00
parent e596e52498
commit 34ad1123ee
16 changed files with 605 additions and 620 deletions

View file

@ -88,8 +88,7 @@ class O3_ARM_v7a_FUP(FUPool):
O3_ARM_v7a_Load(), O3_ARM_v7a_Store(), O3_ARM_v7a_FP()] O3_ARM_v7a_Load(), O3_ARM_v7a_Store(), O3_ARM_v7a_FP()]
# Bi-Mode Branch Predictor # Bi-Mode Branch Predictor
class O3_ARM_v7a_BP(BranchPredictor): class O3_ARM_v7a_BP(BiModeBP):
predType = "bi-mode"
globalPredictorSize = 8192 globalPredictorSize = 8192
globalCtrBits = 2 globalCtrBits = 2
choicePredictorSize = 8192 choicePredictorSize = 8192

View file

@ -29,7 +29,7 @@
from m5.params import * from m5.params import *
from m5.proxy import * from m5.proxy import *
from BaseCPU import BaseCPU from BaseCPU import BaseCPU
from BranchPredictor import BranchPredictor from BranchPredictor import *
class ThreadModel(Enum): class ThreadModel(Enum):
vals = ['Single', 'SMT', 'SwitchOnCacheMiss'] vals = ['Single', 'SMT', 'SwitchOnCacheMiss']
@ -72,6 +72,6 @@ class InOrderCPU(BaseCPU):
div32Latency = Param.Cycles(1, "Latency for 32-bit Divide Operations") div32Latency = Param.Cycles(1, "Latency for 32-bit Divide Operations")
div32RepeatRate = Param.Cycles(1, "Repeat Rate for 32-bit Divide Operations") div32RepeatRate = Param.Cycles(1, "Repeat Rate for 32-bit Divide Operations")
branchPred = Param.BranchPredictor(BranchPredictor(numThreads = branchPred = Param.BranchPredictor(TournamentBP(numThreads =
Parent.numThreads), Parent.numThreads),
"Branch Predictor") "Branch Predictor")

View file

@ -46,7 +46,7 @@ from m5.proxy import *
from m5.SimObject import SimObject from m5.SimObject import SimObject
from BaseCPU import BaseCPU from BaseCPU import BaseCPU
from DummyChecker import DummyChecker from DummyChecker import DummyChecker
from BranchPredictor import BranchPredictor from BranchPredictor import *
from TimingExpr import TimingExpr from TimingExpr import TimingExpr
from FuncUnit import OpClass from FuncUnit import OpClass
@ -266,7 +266,7 @@ class MinorCPU(BaseCPU):
enableIdling = Param.Bool(True, enableIdling = Param.Bool(True,
"Enable cycle skipping when the processor is idle\n"); "Enable cycle skipping when the processor is idle\n");
branchPred = Param.BranchPredictor(BranchPredictor( branchPred = Param.BranchPredictor(TournamentBP(
numThreads = Parent.numThreads), "Branch Predictor") numThreads = Parent.numThreads), "Branch Predictor")
def addCheckerCpu(self): def addCheckerCpu(self):

View file

@ -32,7 +32,7 @@ from m5.proxy import *
from BaseCPU import BaseCPU from BaseCPU import BaseCPU
from FUPool import * from FUPool import *
from O3Checker import O3Checker from O3Checker import O3Checker
from BranchPredictor import BranchPredictor from BranchPredictor import *
class DerivO3CPU(BaseCPU): class DerivO3CPU(BaseCPU):
type = 'DerivO3CPU' type = 'DerivO3CPU'
@ -139,7 +139,7 @@ class DerivO3CPU(BaseCPU):
smtROBThreshold = Param.Int(100, "SMT ROB Threshold Sharing Parameter") smtROBThreshold = Param.Int(100, "SMT ROB Threshold Sharing Parameter")
smtCommitPolicy = Param.String('RoundRobin', "SMT Commit Policy") smtCommitPolicy = Param.String('RoundRobin', "SMT Commit Policy")
branchPred = Param.BranchPredictor(BranchPredictor(numThreads = branchPred = Param.BranchPredictor(TournamentBP(numThreads =
Parent.numThreads), Parent.numThreads),
"Branch Predictor") "Branch Predictor")
needsTSO = Param.Bool(buildEnv['TARGET_ISA'] == 'x86', needsTSO = Param.Bool(buildEnv['TARGET_ISA'] == 'x86',

View file

@ -34,11 +34,10 @@
#include "cpu/pred/2bit_local.hh" #include "cpu/pred/2bit_local.hh"
#include "debug/Fetch.hh" #include "debug/Fetch.hh"
LocalBP::LocalBP(const Params *params) LocalBP::LocalBP(const LocalBPParams *params)
: BPredUnit(params), : BPredUnit(params),
localPredictorSize(params->localPredictorSize), localPredictorSize(params->localPredictorSize),
localCtrBits(params->localCtrBits), localCtrBits(params->localCtrBits)
instShiftAmt(params->instShiftAmt)
{ {
if (!isPowerOf2(localPredictorSize)) { if (!isPowerOf2(localPredictorSize)) {
fatal("Invalid local predictor size!\n"); fatal("Invalid local predictor size!\n");
@ -153,6 +152,12 @@ LocalBP::getLocalIndex(Addr &branch_addr)
} }
void void
LocalBP::uncondBranch(void *&bp_history) LocalBP::uncondBranch(Addr pc, void *&bp_history)
{ {
} }
LocalBP*
LocalBPParams::create()
{
return new LocalBP(this);
}

View file

@ -49,6 +49,7 @@
#include "base/types.hh" #include "base/types.hh"
#include "cpu/pred/bpred_unit.hh" #include "cpu/pred/bpred_unit.hh"
#include "cpu/pred/sat_counter.hh" #include "cpu/pred/sat_counter.hh"
#include "params/LocalBP.hh"
/** /**
* Implements a local predictor that uses the PC to index into a table of * Implements a local predictor that uses the PC to index into a table of
@ -63,9 +64,9 @@ class LocalBP : public BPredUnit
/** /**
* Default branch predictor constructor. * Default branch predictor constructor.
*/ */
LocalBP(const Params *params); LocalBP(const LocalBPParams *params);
virtual void uncondBranch(void * &bp_history); virtual void uncondBranch(Addr pc, void * &bp_history);
/** /**
* Looks up the given address in the branch predictor and returns * Looks up the given address in the branch predictor and returns
@ -124,9 +125,6 @@ class LocalBP : public BPredUnit
/** Number of bits of the local predictor's counters. */ /** Number of bits of the local predictor's counters. */
unsigned localCtrBits; unsigned localCtrBits;
/** Number of bits to shift the PC when calculating index. */
unsigned instShiftAmt;
/** Mask to get index bits. */ /** Mask to get index bits. */
unsigned indexMask; unsigned indexMask;
}; };

View file

@ -1,4 +1,5 @@
# Copyright (c) 2012 Mark D. Hill and David A. Wood # Copyright (c) 2012 Mark D. Hill and David A. Wood
# Copyright (c) 2015 The University of Wisconsin
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -24,7 +25,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# #
# Authors: Nilay Vaish # Authors: Nilay Vaish and Dibakar Gope
from m5.SimObject import SimObject from m5.SimObject import SimObject
from m5.params import * from m5.params import *
@ -33,20 +34,45 @@ class BranchPredictor(SimObject):
type = 'BranchPredictor' type = 'BranchPredictor'
cxx_class = 'BPredUnit' cxx_class = 'BPredUnit'
cxx_header = "cpu/pred/bpred_unit.hh" cxx_header = "cpu/pred/bpred_unit.hh"
abstract = True
numThreads = Param.Unsigned(1, "Number of threads") numThreads = Param.Unsigned(1, "Number of threads")
predType = Param.String("tournament", BTBEntries = Param.Unsigned(4096, "Number of BTB entries")
"Branch predictor type ('local', 'tournament', 'bi-mode')") BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits")
RASSize = Param.Unsigned(16, "RAS size")
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
class LocalBP(BranchPredictor):
type = 'LocalBP'
cxx_class = 'LocalBP'
cxx_header = "cpu/pred/2bit_local.hh"
localPredictorSize = Param.Unsigned(2048, "Size of local predictor") localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
localCtrBits = Param.Unsigned(2, "Bits per counter") localCtrBits = Param.Unsigned(2, "Bits per counter")
localHistoryTableSize = Param.Unsigned(2048, "Size of local history table")
class TournamentBP(BranchPredictor):
type = 'TournamentBP'
cxx_class = 'TournamentBP'
cxx_header = "cpu/pred/tournament.hh"
localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
localCtrBits = Param.Unsigned(2, "Bits per counter")
localHistoryTableSize = Param.Unsigned(2048, "size of local history table")
globalPredictorSize = Param.Unsigned(8192, "Size of global predictor") globalPredictorSize = Param.Unsigned(8192, "Size of global predictor")
globalCtrBits = Param.Unsigned(2, "Bits per counter") globalCtrBits = Param.Unsigned(2, "Bits per counter")
choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor") choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor")
choiceCtrBits = Param.Unsigned(2, "Bits of choice counters") choiceCtrBits = Param.Unsigned(2, "Bits of choice counters")
BTBEntries = Param.Unsigned(4096, "Number of BTB entries")
BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits")
RASSize = Param.Unsigned(16, "RAS size") class BiModeBP(BranchPredictor):
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") type = 'BiModeBP'
cxx_class = 'BiModeBP'
cxx_header = "cpu/pred/bi_mode.hh"
globalPredictorSize = Param.Unsigned(8192, "Size of global predictor")
globalCtrBits = Param.Unsigned(2, "Bits per counter")
choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor")
choiceCtrBits = Param.Unsigned(2, "Bits of choice counters")

View file

@ -43,3 +43,4 @@ Source('tournament.cc')
Source ('bi_mode.cc') Source ('bi_mode.cc')
DebugFlag('FreeList') DebugFlag('FreeList')
DebugFlag('Branch') DebugFlag('Branch')
DebugFlag('LTage')

View file

@ -36,8 +36,8 @@
#include "base/intmath.hh" #include "base/intmath.hh"
#include "cpu/pred/bi_mode.hh" #include "cpu/pred/bi_mode.hh"
BiModeBP::BiModeBP(const Params *params) BiModeBP::BiModeBP(const BiModeBPParams *params)
: BPredUnit(params), instShiftAmt(params->instShiftAmt), : BPredUnit(params),
globalHistoryReg(0), globalHistoryReg(0),
globalHistoryBits(ceilLog2(params->globalPredictorSize)), globalHistoryBits(ceilLog2(params->globalPredictorSize)),
choicePredictorSize(params->choicePredictorSize), choicePredictorSize(params->choicePredictorSize),
@ -77,7 +77,7 @@ BiModeBP::BiModeBP(const Params *params)
* chooses the taken array and the taken array predicts taken. * chooses the taken array and the taken array predicts taken.
*/ */
void void
BiModeBP::uncondBranch(void * &bpHistory) BiModeBP::uncondBranch(Addr pc, void * &bpHistory)
{ {
BPHistory *history = new BPHistory; BPHistory *history = new BPHistory;
history->globalHistoryReg = globalHistoryReg; history->globalHistoryReg = globalHistoryReg;
@ -243,3 +243,9 @@ BiModeBP::updateGlobalHistReg(bool taken)
(globalHistoryReg << 1); (globalHistoryReg << 1);
globalHistoryReg &= historyRegisterMask; globalHistoryReg &= historyRegisterMask;
} }
BiModeBP*
BiModeBPParams::create()
{
return new BiModeBP(this);
}

View file

@ -37,6 +37,7 @@
#include "cpu/pred/bpred_unit.hh" #include "cpu/pred/bpred_unit.hh"
#include "cpu/pred/sat_counter.hh" #include "cpu/pred/sat_counter.hh"
#include "params/BiModeBP.hh"
/** /**
* Implements a bi-mode branch predictor. The bi-mode predictor is a two-level * Implements a bi-mode branch predictor. The bi-mode predictor is a two-level
@ -55,8 +56,8 @@
class BiModeBP : public BPredUnit class BiModeBP : public BPredUnit
{ {
public: public:
BiModeBP(const Params *params); BiModeBP(const BiModeBPParams *params);
void uncondBranch(void * &bp_history); void uncondBranch(Addr pc, void * &bp_history);
void squash(void *bp_history); void squash(void *bp_history);
bool lookup(Addr branch_addr, void * &bp_history); bool lookup(Addr branch_addr, void * &bp_history);
void btbUpdate(Addr branch_addr, void * &bp_history); void btbUpdate(Addr branch_addr, void * &bp_history);
@ -93,8 +94,6 @@ class BiModeBP : public BPredUnit
// not-taken direction predictors // not-taken direction predictors
std::vector<SatCounter> notTakenCounters; std::vector<SatCounter> notTakenCounters;
unsigned instShiftAmt;
unsigned globalHistoryReg; unsigned globalHistoryReg;
unsigned globalHistoryBits; unsigned globalHistoryBits;
unsigned historyRegisterMask; unsigned historyRegisterMask;

View file

@ -1,7 +1,19 @@
/* /*
* Copyright (c) 2004-2006 The Regents of The University of Michigan * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2010 The University of Edinburgh * Copyright (c) 2010 The University of Edinburgh
* Copyright (c) 2012 Mark D. Hill and David A. Wood * Copyright (c) 2012 Mark D. Hill and David A. Wood
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -28,25 +40,517 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Authors: Kevin Lim * Authors: Kevin Lim
* Timothy M. Jones
*/ */
#include "cpu/pred/2bit_local.hh" #include "cpu/pred/bpred_unit.hh"
#include "cpu/pred/bi_mode.hh"
#include "cpu/pred/bpred_unit_impl.hh"
#include "cpu/pred/tournament.hh"
BPredUnit * #include <algorithm>
BranchPredictorParams::create()
#include "arch/isa_traits.hh"
#include "arch/types.hh"
#include "arch/utility.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "debug/Branch.hh"
BPredUnit::BPredUnit(const Params *params)
: SimObject(params),
numThreads(params->numThreads),
predHist(numThreads),
BTB(params->BTBEntries,
params->BTBTagSize,
params->instShiftAmt),
RAS(numThreads),
instShiftAmt(params->instShiftAmt)
{ {
// Setup the selected predictor. for (auto& r : RAS)
if (predType == "local") { r.init(params->RASSize);
return new LocalBP(this); }
} else if (predType == "tournament") {
return new TournamentBP(this); void
} else if (predType == "bi-mode") { BPredUnit::regStats()
return new BiModeBP(this); {
lookups
.name(name() + ".lookups")
.desc("Number of BP lookups")
;
condPredicted
.name(name() + ".condPredicted")
.desc("Number of conditional branches predicted")
;
condIncorrect
.name(name() + ".condIncorrect")
.desc("Number of conditional branches incorrect")
;
BTBLookups
.name(name() + ".BTBLookups")
.desc("Number of BTB lookups")
;
BTBHits
.name(name() + ".BTBHits")
.desc("Number of BTB hits")
;
BTBCorrect
.name(name() + ".BTBCorrect")
.desc("Number of correct BTB predictions (this stat may not "
"work properly.")
;
BTBHitPct
.name(name() + ".BTBHitPct")
.desc("BTB Hit Percentage")
.precision(6);
BTBHitPct = (BTBHits / BTBLookups) * 100;
usedRAS
.name(name() + ".usedRAS")
.desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
.name(name() + ".RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
}
ProbePoints::PMUUPtr
BPredUnit::pmuProbePoint(const char *name)
{
ProbePoints::PMUUPtr ptr;
ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
return ptr;
}
void
BPredUnit::regProbePoints()
{
ppBranches = pmuProbePoint("Branches");
ppMisses = pmuProbePoint("Misses");
}
void
BPredUnit::drainSanityCheck() const
{
// We shouldn't have any outstanding requests when we resume from
// a drained system.
for (const auto& ph M5_VAR_USED : predHist)
assert(ph.empty());
}
bool
BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
TheISA::PCState &pc, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
bool pred_taken = false;
TheISA::PCState target = pc;
++lookups;
ppBranches->notify(1);
void *bp_history = NULL;
if (inst->isUncondCtrl()) {
DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
uncondBranch(pc.instAddr(), bp_history);
} else { } else {
fatal("Invalid BP selected!"); ++condPredicted;
pred_taken = lookup(pc.instAddr(), bp_history);
DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
" predicted %i for PC %s\n", tid, seqNum, pred_taken, pc);
}
DPRINTF(Branch, "[tid:%i]: [sn:%i] Creating prediction history "
"for PC %s\n", tid, seqNum, pc);
PredictorHistory predict_record(seqNum, pc.instAddr(),
pred_taken, bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
if (inst->isReturn()) {
++usedRAS;
predict_record.wasReturn = true;
// If it's a function return call, then look up the address
// in the RAS.
TheISA::PCState rasTop = RAS[tid].top();
target = TheISA::buildRetPC(pc, rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = rasTop;
RAS[tid].pop();
DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i.\n",
tid, pc, target, predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
RAS[tid].push(pc);
predict_record.pushedRAS = true;
// 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(Branch, "[tid:%i]: Instruction %s was a "
"call, adding %s to the RAS index: %i.\n",
tid, pc, pc, RAS[tid].topIdx());
}
if (BTB.valid(pc.instAddr(), tid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
target = BTB.lookup(pc.instAddr(), tid);
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
" target is %s.\n", tid, pc, target);
} else {
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
"valid entry.\n",tid);
pred_taken = false;
// The Direction of the branch predictor is altered because the
// BTB did not have an entry
// The predictor needs to be updated accordingly
if (!inst->isCall() && !inst->isReturn()) {
btbUpdate(pc.instAddr(), bp_history);
DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
" called for %s\n", tid, seqNum, pc);
} else if (inst->isCall() && !inst->isUncondCtrl()) {
RAS[tid].pop();
predict_record.pushedRAS = false;
}
TheISA::advancePC(target, inst);
} }
} }
} else {
if (inst->isReturn()) {
predict_record.wasReturn = true;
}
TheISA::advancePC(target, inst);
}
pc = target;
predHist[tid].push_front(predict_record);
DPRINTF(Branch, "[tid:%i]: [sn:%i]: History entry added."
"predHist.size(): %i\n", tid, seqNum, predHist[tid].size());
return pred_taken;
}
bool
BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
int asid, TheISA::PCState &instPC,
TheISA::PCState &predPC, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
using TheISA::MachInst;
bool pred_taken = false;
TheISA::PCState target;
++lookups;
ppBranches->notify(1);
DPRINTF(Branch, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
"prediction\n", tid, seqNum,
inst->disassemble(instPC.instAddr()), instPC);
void *bp_history = NULL;
if (inst->isUncondCtrl()) {
DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
uncondBranch(instPC.instAddr(), bp_history);
if (inst->isReturn() && RAS[tid].empty()) {
DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
"false.\n", tid);
pred_taken = false;
}
} else {
++condPredicted;
pred_taken = lookup(predPC.instAddr(), bp_history);
}
PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
if (inst->isReturn()) {
++usedRAS;
// If it's a function return call, then look up the address
// in the RAS.
TheISA::PCState rasTop = RAS[tid].top();
target = TheISA::buildRetPC(instPC, rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = rasTop;
assert(predict_record.RASIndex < 16);
RAS[tid].pop();
DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i.\n",
tid, instPC, target,
predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
RAS[tid].push(instPC);
predict_record.pushedRAS = true;
// 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(Branch, "[tid:%i]: Instruction %s was a call"
", adding %s to the RAS index: %i.\n",
tid, instPC, predPC,
RAS[tid].topIdx());
}
if (inst->isCall() &&
inst->isUncondCtrl() &&
inst->isDirectCtrl()) {
target = inst->branchTarget(instPC);
} else if (BTB.valid(predPC.instAddr(), asid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
target = BTB.lookup(predPC.instAddr(), asid);
DPRINTF(Branch, "[tid:%i]: [asid:%i] Instruction %s "
"predicted target is %s.\n",
tid, asid, instPC, target);
} else {
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
"valid entry, predicting false.\n",tid);
pred_taken = false;
}
}
}
if (pred_taken) {
// Set the PC and the instruction's predicted target.
predPC = target;
}
DPRINTF(Branch, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
tid, seqNum, predPC);
predHist[tid].push_front(predict_record);
DPRINTF(Branch, "[tid:%i] [sn:%i] pushed onto front of predHist "
"...predHist.size(): %i\n",
tid, seqNum, predHist[tid].size());
return pred_taken;
}
void
BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
{
DPRINTF(Branch, "[tid:%i]: Committing branches until "
"[sn:%lli].\n", tid, done_sn);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
if (!predHist[tid].back().wasSquashed) {
update(predHist[tid].back().pc, predHist[tid].back().predTaken,
predHist[tid].back().bpHistory, false);
} else {
retireSquashed(predHist[tid].back().bpHistory);
}
predHist[tid].pop_back();
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
{
History &pred_hist = predHist[tid];
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
DPRINTF(Branch, "[tid:%i]: Restoring top of RAS to: %i,"
" target: %s.\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 && pred_hist.front().pushedRAS) {
// Was a call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid: %i] Squashing"
" Call [sn:%i] PC: %s Popping RAS\n", tid,
pred_hist.front().seqNum, pred_hist.front().pc);
RAS[tid].pop();
}
// This call should delete the bpHistory.
squash(pred_hist.front().bpHistory);
DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
"PC %s.\n", tid, pred_hist.front().seqNum,
pred_hist.front().pc);
pred_hist.pop_front();
DPRINTF(Branch, "[tid:%i]: predHist.size(): %i\n",
tid, predHist[tid].size());
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn,
const TheISA::PCState &corrTarget,
bool actually_taken, ThreadID 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.
// NOTE: This should be call conceivably in 2 scenarios:
// (1) After an branch is executed, it updates its status in the ROB
// The commit stage then checks the ROB update and sends a signal to
// the fetch stage to squash history after the mispredict
// (2) In the decode stage, you can find out early if a unconditional
// PC-relative, branch was predicted incorrectly. If so, a signal
// to the fetch stage is sent to squash history after the mispredict
History &pred_hist = predHist[tid];
++condIncorrect;
ppMisses->notify(1);
DPRINTF(Branch, "[tid:%i]: Squashing from sequence number %i, "
"setting target to %s.\n", tid, squashed_sn, corrTarget);
// Squash All Branches AFTER this mispredicted branch
squash(squashed_sn, tid);
// 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()) {
auto hist_it = pred_hist.begin();
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
// squashed_sn);
//assert(hist_it != pred_hist.end());
if (pred_hist.front().seqNum != squashed_sn) {
DPRINTF(Branch, "Front sn %i != Squash sn %i\n",
pred_hist.front().seqNum, squashed_sn);
assert(pred_hist.front().seqNum == squashed_sn);
}
if ((*hist_it).usedRAS) {
++RASIncorrect;
}
update((*hist_it).pc, actually_taken,
pred_hist.front().bpHistory, true);
hist_it->wasSquashed = true;
if (actually_taken) {
if (hist_it->wasReturn && !hist_it->usedRAS) {
DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
" return [sn:%i] PC: %s\n", tid, hist_it->seqNum,
hist_it->pc);
RAS[tid].pop();
hist_it->usedRAS = true;
}
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
BTB.update((*hist_it).pc, corrTarget, tid);
} else {
//Actually not Taken
if (hist_it->usedRAS) {
DPRINTF(Branch,"[tid: %i] Incorrectly predicted"
" return [sn:%i] PC: %s Restoring RAS\n", tid,
hist_it->seqNum, hist_it->pc);
DPRINTF(Branch, "[tid:%i]: Restoring top of RAS"
" to: %i, target: %s.\n", tid,
hist_it->RASIndex, hist_it->RASTarget);
RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget);
hist_it->usedRAS = false;
} else if (hist_it->wasCall && hist_it->pushedRAS) {
//Was a Call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
" Call [sn:%i] PC: %s Popping RAS\n", tid,
hist_it->seqNum, hist_it->pc);
RAS[tid].pop();
hist_it->pushedRAS = false;
}
}
} else {
DPRINTF(Branch, "[tid:%i]: [sn:%i] pred_hist empty, can't "
"update.\n", tid, squashed_sn);
}
}
void
BPredUnit::dump()
{
int i = 0;
for (const auto& ph : predHist) {
if (!ph.empty()) {
auto pred_hist_it = ph.begin();
cprintf("predHist[%i].size(): %i\n", i++, ph.size());
while (pred_hist_it != ph.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");
}
}
}

View file

@ -97,7 +97,7 @@ class BPredUnit : public SimObject
TheISA::PCState &predPC, ThreadID tid); TheISA::PCState &predPC, ThreadID tid);
// @todo: Rename this function. // @todo: Rename this function.
virtual void uncondBranch(void * &bp_history) = 0; virtual void uncondBranch(Addr pc, void * &bp_history) = 0;
/** /**
* Tells the branch predictor to commit any updates until the given * Tells the branch predictor to commit any updates until the given
@ -260,7 +260,8 @@ class BPredUnit : public SimObject
typedef std::deque<PredictorHistory> History; typedef std::deque<PredictorHistory> History;
/** Number of the threads for which the branch history is maintained. */ /** Number of the threads for which the branch history is maintained. */
uint32_t numThreads; const unsigned numThreads;
/** /**
* The per-thread predictor history. This is used to update the predictor * The per-thread predictor history. This is used to update the predictor
@ -295,6 +296,9 @@ class BPredUnit : public SimObject
Stats::Scalar RASIncorrect; Stats::Scalar RASIncorrect;
protected: protected:
/** Number of bits to shift instructions by for predictor addresses. */
const unsigned instShiftAmt;
/** /**
* @{ * @{
* @name PMU Probe points. * @name PMU Probe points.

View file

@ -1,558 +0,0 @@
/*
* Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2010 The University of Edinburgh
* Copyright (c) 2012 Mark D. Hill and David A. Wood
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
*/
#ifndef __CPU_PRED_BPRED_UNIT_IMPL_HH__
#define __CPU_PRED_BPRED_UNIT_IMPL_HH__
#include <algorithm>
#include "arch/isa_traits.hh"
#include "arch/types.hh"
#include "arch/utility.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "cpu/pred/bpred_unit.hh"
#include "debug/Branch.hh"
BPredUnit::BPredUnit(const Params *params)
: SimObject(params),
numThreads(params->numThreads),
predHist(numThreads),
BTB(params->BTBEntries,
params->BTBTagSize,
params->instShiftAmt),
RAS(numThreads)
{
for (auto& r : RAS)
r.init(params->RASSize);
}
void
BPredUnit::regStats()
{
lookups
.name(name() + ".lookups")
.desc("Number of BP lookups")
;
condPredicted
.name(name() + ".condPredicted")
.desc("Number of conditional branches predicted")
;
condIncorrect
.name(name() + ".condIncorrect")
.desc("Number of conditional branches incorrect")
;
BTBLookups
.name(name() + ".BTBLookups")
.desc("Number of BTB lookups")
;
BTBHits
.name(name() + ".BTBHits")
.desc("Number of BTB hits")
;
BTBCorrect
.name(name() + ".BTBCorrect")
.desc("Number of correct BTB predictions (this stat may not "
"work properly.")
;
BTBHitPct
.name(name() + ".BTBHitPct")
.desc("BTB Hit Percentage")
.precision(6);
BTBHitPct = (BTBHits / BTBLookups) * 100;
usedRAS
.name(name() + ".usedRAS")
.desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
.name(name() + ".RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
}
ProbePoints::PMUUPtr
BPredUnit::pmuProbePoint(const char *name)
{
ProbePoints::PMUUPtr ptr;
ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
return ptr;
}
void
BPredUnit::regProbePoints()
{
ppBranches = pmuProbePoint("Branches");
ppMisses = pmuProbePoint("Misses");
}
void
BPredUnit::drainSanityCheck() const
{
// We shouldn't have any outstanding requests when we resume from
// a drained system.
for (const auto& ph M5_VAR_USED : predHist)
assert(ph.empty());
}
bool
BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
TheISA::PCState &pc, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
bool pred_taken = false;
TheISA::PCState target = pc;
++lookups;
ppBranches->notify(1);
void *bp_history = NULL;
if (inst->isUncondCtrl()) {
DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
uncondBranch(bp_history);
} else {
++condPredicted;
pred_taken = lookup(pc.instAddr(), bp_history);
DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
" predicted %i for PC %s\n", tid, seqNum, pred_taken, pc);
}
DPRINTF(Branch, "[tid:%i]: [sn:%i] Creating prediction history "
"for PC %s\n", tid, seqNum, pc);
PredictorHistory predict_record(seqNum, pc.instAddr(),
pred_taken, bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
if (inst->isReturn()) {
++usedRAS;
predict_record.wasReturn = true;
// If it's a function return call, then look up the address
// in the RAS.
TheISA::PCState rasTop = RAS[tid].top();
target = TheISA::buildRetPC(pc, rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = rasTop;
RAS[tid].pop();
DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i.\n",
tid, pc, target, predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
RAS[tid].push(pc);
predict_record.pushedRAS = true;
// 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(Branch, "[tid:%i]: Instruction %s was a "
"call, adding %s to the RAS index: %i.\n",
tid, pc, pc, RAS[tid].topIdx());
}
if (BTB.valid(pc.instAddr(), tid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
target = BTB.lookup(pc.instAddr(), tid);
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
" target is %s.\n", tid, pc, target);
} else {
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
"valid entry.\n",tid);
pred_taken = false;
// The Direction of the branch predictor is altered because the
// BTB did not have an entry
// The predictor needs to be updated accordingly
if (!inst->isCall() && !inst->isReturn()) {
btbUpdate(pc.instAddr(), bp_history);
DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
" called for %s\n", tid, seqNum, pc);
} else if (inst->isCall() && !inst->isUncondCtrl()) {
RAS[tid].pop();
predict_record.pushedRAS = false;
}
TheISA::advancePC(target, inst);
}
}
} else {
if (inst->isReturn()) {
predict_record.wasReturn = true;
}
TheISA::advancePC(target, inst);
}
pc = target;
predHist[tid].push_front(predict_record);
DPRINTF(Branch, "[tid:%i]: [sn:%i]: History entry added."
"predHist.size(): %i\n", tid, seqNum, predHist[tid].size());
return pred_taken;
}
bool
BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
int asid, TheISA::PCState &instPC,
TheISA::PCState &predPC, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
using TheISA::MachInst;
bool pred_taken = false;
TheISA::PCState target;
++lookups;
ppBranches->notify(1);
DPRINTF(Branch, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
"prediction\n", tid, seqNum,
inst->disassemble(instPC.instAddr()), instPC);
void *bp_history = NULL;
if (inst->isUncondCtrl()) {
DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
uncondBranch(bp_history);
if (inst->isReturn() && RAS[tid].empty()) {
DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
"false.\n", tid);
pred_taken = false;
}
} else {
++condPredicted;
pred_taken = lookup(predPC.instAddr(), bp_history);
}
PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
if (inst->isReturn()) {
++usedRAS;
// If it's a function return call, then look up the address
// in the RAS.
TheISA::PCState rasTop = RAS[tid].top();
target = TheISA::buildRetPC(instPC, rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = rasTop;
assert(predict_record.RASIndex < 16);
RAS[tid].pop();
DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i.\n",
tid, instPC, target,
predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
RAS[tid].push(instPC);
predict_record.pushedRAS = true;
// 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(Branch, "[tid:%i]: Instruction %s was a call"
", adding %s to the RAS index: %i.\n",
tid, instPC, predPC,
RAS[tid].topIdx());
}
if (inst->isCall() &&
inst->isUncondCtrl() &&
inst->isDirectCtrl()) {
target = inst->branchTarget(instPC);
} else if (BTB.valid(predPC.instAddr(), asid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
target = BTB.lookup(predPC.instAddr(), asid);
DPRINTF(Branch, "[tid:%i]: [asid:%i] Instruction %s "
"predicted target is %s.\n",
tid, asid, instPC, target);
} else {
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
"valid entry, predicting false.\n",tid);
pred_taken = false;
}
}
}
if (pred_taken) {
// Set the PC and the instruction's predicted target.
predPC = target;
}
DPRINTF(Branch, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
tid, seqNum, predPC);
predHist[tid].push_front(predict_record);
DPRINTF(Branch, "[tid:%i] [sn:%i] pushed onto front of predHist "
"...predHist.size(): %i\n",
tid, seqNum, predHist[tid].size());
return pred_taken;
}
void
BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
{
DPRINTF(Branch, "[tid:%i]: Committing branches until "
"[sn:%lli].\n", tid, done_sn);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
if (!predHist[tid].back().wasSquashed) {
update(predHist[tid].back().pc, predHist[tid].back().predTaken,
predHist[tid].back().bpHistory, false);
} else {
retireSquashed(predHist[tid].back().bpHistory);
}
predHist[tid].pop_back();
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
{
History &pred_hist = predHist[tid];
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
DPRINTF(Branch, "[tid:%i]: Restoring top of RAS to: %i,"
" target: %s.\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 && pred_hist.front().pushedRAS) {
// Was a call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid: %i] Squashing"
" Call [sn:%i] PC: %s Popping RAS\n", tid,
pred_hist.front().seqNum, pred_hist.front().pc);
RAS[tid].pop();
}
// This call should delete the bpHistory.
squash(pred_hist.front().bpHistory);
DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
"PC %s.\n", tid, pred_hist.front().seqNum,
pred_hist.front().pc);
pred_hist.pop_front();
DPRINTF(Branch, "[tid:%i]: predHist.size(): %i\n",
tid, predHist[tid].size());
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn,
const TheISA::PCState &corrTarget,
bool actually_taken, ThreadID 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.
// NOTE: This should be call conceivably in 2 scenarios:
// (1) After an branch is executed, it updates its status in the ROB
// The commit stage then checks the ROB update and sends a signal to
// the fetch stage to squash history after the mispredict
// (2) In the decode stage, you can find out early if a unconditional
// PC-relative, branch was predicted incorrectly. If so, a signal
// to the fetch stage is sent to squash history after the mispredict
History &pred_hist = predHist[tid];
++condIncorrect;
ppMisses->notify(1);
DPRINTF(Branch, "[tid:%i]: Squashing from sequence number %i, "
"setting target to %s.\n", tid, squashed_sn, corrTarget);
// Squash All Branches AFTER this mispredicted branch
squash(squashed_sn, tid);
// 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()) {
auto hist_it = pred_hist.begin();
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
// squashed_sn);
//assert(hist_it != pred_hist.end());
if (pred_hist.front().seqNum != squashed_sn) {
DPRINTF(Branch, "Front sn %i != Squash sn %i\n",
pred_hist.front().seqNum, squashed_sn);
assert(pred_hist.front().seqNum == squashed_sn);
}
if ((*hist_it).usedRAS) {
++RASIncorrect;
}
update((*hist_it).pc, actually_taken,
pred_hist.front().bpHistory, true);
hist_it->wasSquashed = true;
if (actually_taken) {
if (hist_it->wasReturn && !hist_it->usedRAS) {
DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
" return [sn:%i] PC: %s\n", tid, hist_it->seqNum,
hist_it->pc);
RAS[tid].pop();
hist_it->usedRAS = true;
}
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
BTB.update((*hist_it).pc, corrTarget, tid);
} else {
//Actually not Taken
if (hist_it->usedRAS) {
DPRINTF(Branch,"[tid: %i] Incorrectly predicted"
" return [sn:%i] PC: %s Restoring RAS\n", tid,
hist_it->seqNum, hist_it->pc);
DPRINTF(Branch, "[tid:%i]: Restoring top of RAS"
" to: %i, target: %s.\n", tid,
hist_it->RASIndex, hist_it->RASTarget);
RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget);
hist_it->usedRAS = false;
} else if (hist_it->wasCall && hist_it->pushedRAS) {
//Was a Call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
" Call [sn:%i] PC: %s Popping RAS\n", tid,
hist_it->seqNum, hist_it->pc);
RAS[tid].pop();
hist_it->pushedRAS = false;
}
}
} else {
DPRINTF(Branch, "[tid:%i]: [sn:%i] pred_hist empty, can't "
"update.\n", tid, squashed_sn);
}
}
void
BPredUnit::dump()
{
int i = 0;
for (const auto& ph : predHist) {
if (!ph.empty()) {
auto pred_hist_it = ph.begin();
cprintf("predHist[%i].size(): %i\n", i++, ph.size());
while (pred_hist_it != ph.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");
}
}
}
#endif//__CPU_PRED_BPRED_UNIT_IMPL_HH__

View file

@ -44,7 +44,7 @@
#include "base/intmath.hh" #include "base/intmath.hh"
#include "cpu/pred/tournament.hh" #include "cpu/pred/tournament.hh"
TournamentBP::TournamentBP(const Params *params) TournamentBP::TournamentBP(const TournamentBPParams *params)
: BPredUnit(params), : BPredUnit(params),
localPredictorSize(params->localPredictorSize), localPredictorSize(params->localPredictorSize),
localCtrBits(params->localCtrBits), localCtrBits(params->localCtrBits),
@ -58,8 +58,7 @@ TournamentBP::TournamentBP(const Params *params)
ceilLog2(params->globalPredictorSize) : ceilLog2(params->globalPredictorSize) :
ceilLog2(params->choicePredictorSize)), ceilLog2(params->choicePredictorSize)),
choicePredictorSize(params->choicePredictorSize), choicePredictorSize(params->choicePredictorSize),
choiceCtrBits(params->choiceCtrBits), choiceCtrBits(params->choiceCtrBits)
instShiftAmt(params->instShiftAmt)
{ {
if (!isPowerOf2(localPredictorSize)) { if (!isPowerOf2(localPredictorSize)) {
fatal("Invalid local predictor size!\n"); fatal("Invalid local predictor size!\n");
@ -249,7 +248,7 @@ TournamentBP::lookup(Addr branch_addr, void * &bp_history)
} }
void void
TournamentBP::uncondBranch(void * &bp_history) TournamentBP::uncondBranch(Addr pc, void * &bp_history)
{ {
// Create BPHistory and pass it back to be recorded. // Create BPHistory and pass it back to be recorded.
BPHistory *history = new BPHistory; BPHistory *history = new BPHistory;
@ -376,6 +375,12 @@ TournamentBP::squash(void *bp_history)
delete history; delete history;
} }
TournamentBP*
TournamentBPParams::create()
{
return new TournamentBP(this);
}
#ifdef DEBUG #ifdef DEBUG
int int
TournamentBP::BPHistory::newCount = 0; TournamentBP::BPHistory::newCount = 0;

View file

@ -50,6 +50,7 @@
#include "base/types.hh" #include "base/types.hh"
#include "cpu/pred/bpred_unit.hh" #include "cpu/pred/bpred_unit.hh"
#include "cpu/pred/sat_counter.hh" #include "cpu/pred/sat_counter.hh"
#include "params/TournamentBP.hh"
/** /**
* Implements a tournament branch predictor, hopefully identical to the one * Implements a tournament branch predictor, hopefully identical to the one
@ -66,7 +67,7 @@ class TournamentBP : public BPredUnit
/** /**
* Default branch predictor constructor. * Default branch predictor constructor.
*/ */
TournamentBP(const Params *params); TournamentBP(const TournamentBPParams *params);
/** /**
* Looks up the given address in the branch predictor and returns * Looks up the given address in the branch predictor and returns
@ -84,7 +85,7 @@ class TournamentBP : public BPredUnit
* global history stored in it. * global history stored in it.
* @param bp_history Pointer that will be set to the BPHistory object. * @param bp_history Pointer that will be set to the BPHistory object.
*/ */
void uncondBranch(void * &bp_history); void uncondBranch(Addr pc, void * &bp_history);
/** /**
* Updates the branch predictor to Not Taken if a BTB entry is * Updates the branch predictor to Not Taken if a BTB entry is
* invalid or not found. * invalid or not found.
@ -234,11 +235,6 @@ class TournamentBP : public BPredUnit
/** Number of bits in the choice predictor's counters. */ /** Number of bits in the choice predictor's counters. */
unsigned choiceCtrBits; unsigned choiceCtrBits;
/** Number of bits to shift the instruction over to get rid of the word
* offset.
*/
unsigned instShiftAmt;
/** Thresholds for the counter value; above the threshold is taken, /** Thresholds for the counter value; above the threshold is taken,
* equal to or below the threshold is not taken. * equal to or below the threshold is not taken.
*/ */

View file

@ -30,7 +30,7 @@ from m5.defines import buildEnv
from m5.params import * from m5.params import *
from BaseCPU import BaseCPU from BaseCPU import BaseCPU
from DummyChecker import DummyChecker from DummyChecker import DummyChecker
from BranchPredictor import BranchPredictor from BranchPredictor import *
class BaseSimpleCPU(BaseCPU): class BaseSimpleCPU(BaseCPU):
type = 'BaseSimpleCPU' type = 'BaseSimpleCPU'