cpu: Restructure BTB

- A new abstract BTB class is created to enable different BTB
  implementations. The new BTB class gets its own parameter
  and stats.
- An enum is added to differentiate branch instruction types.
  This enum is used to enhance statistics and BPU management.
- The existing BTB is moved into `simple_btb` as default.
- An additional function is added to store the static instruction in
  the BTB. This function is used for the decoupled front-end.
- Update configs to match new BTB parameters.

Change-Id: I99b29a19a1b57e59ea2b188ed7d62a8b79426529
Signed-off-by: David Schall <david.schall@ed.ac.uk>
This commit is contained in:
David Schall
2023-10-07 17:26:16 +00:00
parent ae104cc431
commit edf9092fee
13 changed files with 646 additions and 206 deletions

View File

@@ -1679,7 +1679,13 @@ class HPI_MMU(ArmMMU):
dtb = ArmTLB(entry_type="data", size=256) dtb = ArmTLB(entry_type="data", size=256)
class HPI_BTB(SimpleBTB):
numEntries = 128
tagBits = 18
class HPI_BP(TournamentBP): class HPI_BP(TournamentBP):
btb = HPI_BTB()
localPredictorSize = 64 localPredictorSize = 64
localCtrBits = 2 localCtrBits = 2
localHistoryTableSize = 64 localHistoryTableSize = 64
@@ -1687,8 +1693,6 @@ class HPI_BP(TournamentBP):
globalCtrBits = 2 globalCtrBits = 2
choicePredictorSize = 1024 choicePredictorSize = 1024
choiceCtrBits = 2 choiceCtrBits = 2
BTBEntries = 128
BTBTagSize = 18
RASSize = 8 RASSize = 8
instShiftAmt = 2 instShiftAmt = 2

View File

@@ -107,14 +107,18 @@ class O3_ARM_v7a_FUP(FUPool):
] ]
class O3_ARM_v7a_BTB(SimpleBTB):
numEntries = 2048
tagBits = 18
# Bi-Mode Branch Predictor # Bi-Mode Branch Predictor
class O3_ARM_v7a_BP(BiModeBP): class O3_ARM_v7a_BP(BiModeBP):
btb = O3_ARM_v7a_BTB()
globalPredictorSize = 8192 globalPredictorSize = 8192
globalCtrBits = 2 globalCtrBits = 2
choicePredictorSize = 8192 choicePredictorSize = 8192
choiceCtrBits = 2 choiceCtrBits = 2
BTBEntries = 2048
BTBTagSize = 18
RASSize = 16 RASSize = 16
instShiftAmt = 2 instShiftAmt = 2

View File

@@ -104,14 +104,18 @@ class ex5_big_FUP(FUPool):
] ]
class ex5_big_BTB(SimpleBTB):
numEntries = 4096
tagBits = 18
# Bi-Mode Branch Predictor # Bi-Mode Branch Predictor
class ex5_big_BP(BiModeBP): class ex5_big_BP(BiModeBP):
btb = ex5_big_BTB()
globalPredictorSize = 4096 globalPredictorSize = 4096
globalCtrBits = 2 globalCtrBits = 2
choicePredictorSize = 1024 choicePredictorSize = 1024
choiceCtrBits = 3 choiceCtrBits = 3
BTBEntries = 4096
BTBTagSize = 18
RASSize = 48 RASSize = 48
instShiftAmt = 2 instShiftAmt = 2

View File

@@ -1,3 +1,15 @@
# Copyright (c) 2022-2023 The University of Edinburgh
# 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) 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 # Copyright (c) 2015 The University of Wisconsin
# All rights reserved. # All rights reserved.
@@ -25,10 +37,46 @@
# (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.
from m5.SimObject import SimObject from m5.SimObject import *
from m5.params import * from m5.params import *
from m5.proxy import * from m5.proxy import *
from m5.objects.ClockedObject import ClockedObject
class BranchType(Enum):
vals = [
"NoBranch",
"Return",
"CallDirect",
"CallIndirect", # 'Call',
"DirectCond",
"DirectUncond", # 'Direct',
"IndirectCond",
"IndirectUncond", #'Indirect',
]
class BranchTargetBuffer(ClockedObject):
type = "BranchTargetBuffer"
cxx_class = "gem5::branch_prediction::BranchTargetBuffer"
cxx_header = "cpu/pred/btb.hh"
abstract = True
numThreads = Param.Unsigned(Parent.numThreads, "Number of threads")
class SimpleBTB(BranchTargetBuffer):
type = "SimpleBTB"
cxx_class = "gem5::branch_prediction::SimpleBTB"
cxx_header = "cpu/pred/simple_btb.hh"
numEntries = Param.Unsigned(4096, "Number of BTB entries")
tagBits = Param.Unsigned(16, "Size of the BTB tags, in bits")
instShiftAmt = Param.Unsigned(
Parent.instShiftAmt, "Number of bits to shift instructions by"
)
class IndirectPredictor(SimObject): class IndirectPredictor(SimObject):
type = "IndirectPredictor" type = "IndirectPredictor"
@@ -63,11 +111,12 @@ class BranchPredictor(SimObject):
abstract = True abstract = True
numThreads = Param.Unsigned(Parent.numThreads, "Number of threads") numThreads = Param.Unsigned(Parent.numThreads, "Number of threads")
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")
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
RASSize = Param.Unsigned(16, "RAS size")
btb = Param.BranchTargetBuffer(SimpleBTB(), "Branch target buffer (BTB)")
indirectBranchPred = Param.IndirectPredictor( indirectBranchPred = Param.IndirectPredictor(
SimpleIndirectPredictor(), SimpleIndirectPredictor(),
"Indirect branch predictor, set to NULL to disable indirect predictions", "Indirect branch predictor, set to NULL to disable indirect predictions",

View File

@@ -1,5 +1,17 @@
# -*- mode:python -*- # -*- mode:python -*-
# Copyright (c) 2022-2023 The University of Edinburgh
# 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) 2006 The Regents of The University of Michigan # Copyright (c) 2006 The Regents of The University of Michigan
# All rights reserved. # All rights reserved.
# #
@@ -28,8 +40,12 @@
Import('*') Import('*')
SimObject('BranchPredictor.py', sim_objects=[
'IndirectPredictor', 'SimpleIndirectPredictor', 'BranchPredictor', SimObject('BranchPredictor.py',
sim_objects=[
'BranchPredictor',
'IndirectPredictor', 'SimpleIndirectPredictor',
'BranchTargetBuffer', 'SimpleBTB',
'LocalBP', 'TournamentBP', 'BiModeBP', 'TAGEBase', 'TAGE', 'LoopPredictor', 'LocalBP', 'TournamentBP', 'BiModeBP', 'TAGEBase', 'TAGE', 'LoopPredictor',
'TAGE_SC_L_TAGE', 'TAGE_SC_L_TAGE_64KB', 'TAGE_SC_L_TAGE_8KB', 'TAGE_SC_L_TAGE', 'TAGE_SC_L_TAGE_64KB', 'TAGE_SC_L_TAGE_8KB',
'LTAGE', 'TAGE_SC_L_LoopPredictor', 'StatisticalCorrector', 'TAGE_SC_L', 'LTAGE', 'TAGE_SC_L_LoopPredictor', 'StatisticalCorrector', 'TAGE_SC_L',
@@ -41,17 +57,16 @@ SimObject('BranchPredictor.py', sim_objects=[
'MultiperspectivePerceptronTAGE', 'MPP_StatisticalCorrector_64KB', 'MultiperspectivePerceptronTAGE', 'MPP_StatisticalCorrector_64KB',
'MultiperspectivePerceptronTAGE64KB', 'MPP_TAGE_8KB', 'MultiperspectivePerceptronTAGE64KB', 'MPP_TAGE_8KB',
'MPP_LoopPredictor_8KB', 'MPP_StatisticalCorrector_8KB', 'MPP_LoopPredictor_8KB', 'MPP_StatisticalCorrector_8KB',
'MultiperspectivePerceptronTAGE8KB']) 'MultiperspectivePerceptronTAGE8KB'],
enums=['BranchType'])
DebugFlag('Indirect')
Source('bpred_unit.cc') Source('bpred_unit.cc')
Source('2bit_local.cc') Source('2bit_local.cc')
Source('btb.cc')
Source('simple_indirect.cc') Source('simple_indirect.cc')
Source('indirect.cc') Source('indirect.cc')
Source('ras.cc') Source('ras.cc')
Source('tournament.cc') Source('tournament.cc')
Source ('bi_mode.cc') Source('bi_mode.cc')
Source('tage_base.cc') Source('tage_base.cc')
Source('tage.cc') Source('tage.cc')
Source('loop_predictor.cc') Source('loop_predictor.cc')
@@ -66,6 +81,10 @@ Source('statistical_corrector.cc')
Source('tage_sc_l.cc') Source('tage_sc_l.cc')
Source('tage_sc_l_8KB.cc') Source('tage_sc_l_8KB.cc')
Source('tage_sc_l_64KB.cc') Source('tage_sc_l_64KB.cc')
Source('btb.cc')
Source('simple_btb.cc')
DebugFlag('Indirect')
DebugFlag('BTB')
DebugFlag('FreeList') DebugFlag('FreeList')
DebugFlag('Branch') DebugFlag('Branch')
DebugFlag('Tage') DebugFlag('Tage')

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2011-2012, 2014 ARM Limited * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2010 The University of Edinburgh * Copyright (c) 2010,2022-2023 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 * All rights reserved
* *
@@ -59,10 +59,7 @@ BPredUnit::BPredUnit(const Params &params)
: SimObject(params), : SimObject(params),
numThreads(params.numThreads), numThreads(params.numThreads),
predHist(numThreads), predHist(numThreads),
BTB(params.BTBEntries, btb(params.btb),
params.BTBTagSize,
params.instShiftAmt,
params.numThreads),
RAS(numThreads), RAS(numThreads),
iPred(params.indirectBranchPred), iPred(params.indirectBranchPred),
stats(this), stats(this),
@@ -218,10 +215,13 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
if (inst->isDirectCtrl() || !iPred) { if (inst->isDirectCtrl() || !iPred) {
++stats.BTBLookups; ++stats.BTBLookups;
// Check BTB on direct branches // Check BTB on direct branches
if (BTB.valid(pc.instAddr(), tid)) { const PCStateBase * btb_target = btb->lookup(tid,
pc.instAddr(),
getBranchType(inst));
if (btb_target) {
++stats.BTBHits; ++stats.BTBHits;
// If it's not a return, use the BTB to get target addr. // If it's not a return, use the BTB to get target addr.
set(target, BTB.lookup(pc.instAddr(), tid)); set(target, btb_target);
DPRINTF(Branch, DPRINTF(Branch,
"[tid:%i] [sn:%llu] Instruction %s predicted " "[tid:%i] [sn:%llu] Instruction %s predicted "
"target is %s\n", "target is %s\n",
@@ -482,7 +482,8 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
hist_it->seqNum, hist_it->pc); hist_it->seqNum, hist_it->pc);
++stats.BTBUpdates; ++stats.BTBUpdates;
BTB.update(hist_it->pc, corr_target, tid); btb->update(tid, hist_it->pc, corr_target,
getBranchType(hist_it->inst));
} }
} else { } else {
//Actually not Taken //Actually not Taken

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2011-2012, 2014 ARM Limited * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2010 The University of Edinburgh * Copyright (c) 2010,2022-2023 The University of Edinburgh
* All rights reserved * All rights reserved
* *
* The license below extends only to copyright in the software and shall * The license below extends only to copyright in the software and shall
@@ -46,6 +46,7 @@
#include "base/statistics.hh" #include "base/statistics.hh"
#include "base/types.hh" #include "base/types.hh"
#include "cpu/pred/branch_type.hh"
#include "cpu/pred/btb.hh" #include "cpu/pred/btb.hh"
#include "cpu/pred/indirect.hh" #include "cpu/pred/indirect.hh"
#include "cpu/pred/ras.hh" #include "cpu/pred/ras.hh"
@@ -152,7 +153,14 @@ class BPredUnit : public SimObject
* @param inst_PC The PC to look up. * @param inst_PC The PC to look up.
* @return Whether the BTB contains the given PC. * @return Whether the BTB contains the given PC.
*/ */
bool BTBValid(Addr instPC) { return BTB.valid(instPC, 0); } bool BTBValid(ThreadID tid, Addr instPC)
{
return btb->valid(tid, instPC);
}
bool BTBValid(ThreadID tid, PCStateBase &instPC)
{
return BTBValid(tid, instPC.instAddr());
}
/** /**
* Looks up a given PC in the BTB to get the predicted target. The PC may * Looks up a given PC in the BTB to get the predicted target. The PC may
@@ -162,9 +170,9 @@ class BPredUnit : public SimObject
* @return The address of the target of the branch. * @return The address of the target of the branch.
*/ */
const PCStateBase * const PCStateBase *
BTBLookup(Addr inst_pc) BTBLookup(ThreadID tid, PCStateBase &instPC)
{ {
return BTB.lookup(inst_pc, 0); return btb->lookup(tid, instPC.instAddr());
} }
/** /**
@@ -189,10 +197,10 @@ class BPredUnit : public SimObject
* @param target_PC The branch's target that will be added to the BTB. * @param target_PC The branch's target that will be added to the BTB.
*/ */
void void
BTBUpdate(Addr instPC, const PCStateBase &target) BTBUpdate(ThreadID tid, Addr instPC, const PCStateBase &target)
{ {
++stats.BTBUpdates; ++stats.BTBUpdates;
BTB.update(instPC, target, 0); return btb->update(tid, instPC, target);
} }
@@ -295,7 +303,7 @@ class BPredUnit : public SimObject
std::vector<History> predHist; std::vector<History> predHist;
/** The BTB. */ /** The BTB. */
DefaultBTB BTB; BranchTargetBuffer* btb;
/** The per-thread return address stack. */ /** The per-thread return address stack. */
std::vector<ReturnAddrStack> RAS; std::vector<ReturnAddrStack> RAS;

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* 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.
*
* 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.
*/
/* @file
* A helper for branch type information
*/
#ifndef __CPU_PRED_BRANCH_TYPE_HH__
#define __CPU_PRED_BRANCH_TYPE_HH__
#include "cpu/static_inst.hh"
#include "enums/BranchType.hh"
namespace gem5
{
namespace branch_prediction
{
typedef enums::BranchType BranchType;
inline BranchType getBranchType(StaticInstPtr inst)
{
if (inst->isReturn()) {
return BranchType::Return;
}
if (inst->isCall()) {
return inst->isDirectCtrl()
? BranchType::CallDirect
: BranchType::CallIndirect;
}
if (inst->isDirectCtrl()) {
return inst->isCondCtrl()
? BranchType::DirectCond
: BranchType::DirectUncond;
}
if (inst->isIndirectCtrl()) {
return inst->isCondCtrl()
? BranchType::IndirectCond
: BranchType::IndirectUncond;
}
return BranchType::NoBranch;
}
inline std::string toString(BranchType type)
{
return std::string(enums::BranchTypeStrings[type]);
}
} // namespace branch_prediction
} // namespace gem5
#endif // __CPU_PRED_BRANCH_TYPE_HH__

View File

@@ -1,4 +1,16 @@
/* /*
* Copyright (c) 2022-2023 The University of Edinburgh
* 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 * Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
@@ -28,119 +40,59 @@
#include "cpu/pred/btb.hh" #include "cpu/pred/btb.hh"
#include "base/intmath.hh"
#include "base/trace.hh"
#include "debug/Fetch.hh"
namespace gem5 namespace gem5
{ {
namespace branch_prediction namespace branch_prediction
{ {
DefaultBTB::DefaultBTB(unsigned _numEntries, BranchTargetBuffer::BranchTargetBuffer(const Params &params)
unsigned _tagBits, : ClockedObject(params),
unsigned _instShiftAmt, numThreads(params.numThreads),
unsigned _num_threads) stats(this)
: numEntries(_numEntries),
tagBits(_tagBits),
instShiftAmt(_instShiftAmt),
log2NumThreads(floorLog2(_num_threads))
{ {
DPRINTF(Fetch, "BTB: Creating BTB object.\n"); }
if (!isPowerOf2(numEntries)) { BranchTargetBuffer::BranchTargetBufferStats::BranchTargetBufferStats(
fatal("BTB entries is not a power of 2!"); statistics::Group *parent)
: statistics::Group(parent),
ADD_STAT(lookups, statistics::units::Count::get(),
"Number of BTB lookups"),
ADD_STAT(misses, statistics::units::Count::get(),
"Number of BTB misses"),
ADD_STAT(updates, statistics::units::Count::get(),
"Number of BTB updates"),
ADD_STAT(mispredict, statistics::units::Count::get(),
"Number of BTB mispredictions. "
"No target found or target wrong."),
ADD_STAT(evictions, statistics::units::Count::get(),
"Number of BTB evictions")
{
using namespace statistics;
lookups
.init(enums::Num_BranchType)
.flags(total | pdf);
misses
.init(enums::Num_BranchType)
.flags(total | pdf);
updates
.init(enums::Num_BranchType)
.flags(total | pdf);
mispredict
.init(enums::Num_BranchType)
.flags(total | pdf);
evictions.flags(nozero);
for (int i = 0; i < enums::Num_BranchType; i++) {
lookups.subname(i, enums::BranchTypeStrings[i]);
misses.subname(i, enums::BranchTypeStrings[i]);
updates.subname(i, enums::BranchTypeStrings[i]);
mispredict.subname(i, enums::BranchTypeStrings[i]);
} }
btb.resize(numEntries);
for (unsigned i = 0; i < numEntries; ++i) {
btb[i].valid = false;
}
idxMask = numEntries - 1;
tagMask = (1 << tagBits) - 1;
tagShiftAmt = instShiftAmt + floorLog2(numEntries);
}
void
DefaultBTB::reset()
{
for (unsigned i = 0; i < numEntries; ++i) {
btb[i].valid = false;
}
}
inline
unsigned
DefaultBTB::getIndex(Addr instPC, ThreadID tid)
{
// Need to shift PC over by the word offset.
return ((instPC >> instShiftAmt)
^ (tid << (tagShiftAmt - instShiftAmt - log2NumThreads)))
& idxMask;
}
inline
Addr
DefaultBTB::getTag(Addr instPC)
{
return (instPC >> tagShiftAmt) & tagMask;
}
bool
DefaultBTB::valid(Addr instPC, ThreadID tid)
{
unsigned btb_idx = getIndex(instPC, tid);
Addr inst_tag = getTag(instPC);
assert(btb_idx < numEntries);
if (btb[btb_idx].valid
&& inst_tag == btb[btb_idx].tag
&& btb[btb_idx].tid == tid) {
return true;
} else {
return false;
}
}
// @todo Create some sort of return struct that has both whether or not the
// address is valid, and also the address. For now will just use addr = 0 to
// represent invalid entry.
const PCStateBase *
DefaultBTB::lookup(Addr inst_pc, ThreadID tid)
{
unsigned btb_idx = getIndex(inst_pc, tid);
Addr inst_tag = getTag(inst_pc);
assert(btb_idx < numEntries);
if (btb[btb_idx].valid
&& inst_tag == btb[btb_idx].tag
&& btb[btb_idx].tid == tid) {
return btb[btb_idx].target.get();
} else {
return nullptr;
}
}
void
DefaultBTB::update(Addr inst_pc, const PCStateBase &target, ThreadID tid)
{
unsigned btb_idx = getIndex(inst_pc, tid);
assert(btb_idx < numEntries);
btb[btb_idx].tid = tid;
btb[btb_idx].valid = true;
set(btb[btb_idx].target, target);
btb[btb_idx].tag = getTag(inst_pc);
} }
} // namespace branch_prediction } // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/* /*
* Copyright (c) 2022-2023 The University of Edinburgh
* 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 * Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
@@ -29,9 +41,13 @@
#ifndef __CPU_PRED_BTB_HH__ #ifndef __CPU_PRED_BTB_HH__
#define __CPU_PRED_BTB_HH__ #define __CPU_PRED_BTB_HH__
#include "arch/generic/pcstate.hh" #include "arch/generic/pcstate.hh"
#include "base/logging.hh" #include "base/statistics.hh"
#include "base/types.hh" #include "cpu/pred/branch_type.hh"
#include "cpu/static_inst.hh"
#include "params/BranchTargetBuffer.hh"
#include "sim/clocked_object.hh"
namespace gem5 namespace gem5
{ {
@@ -39,93 +55,73 @@ namespace gem5
namespace branch_prediction namespace branch_prediction
{ {
class DefaultBTB class BranchTargetBuffer : public ClockedObject
{ {
private:
struct BTBEntry
{
/** The entry's tag. */
Addr tag = 0;
/** The entry's target. */
std::unique_ptr<PCStateBase> target;
/** The entry's thread id. */
ThreadID tid;
/** Whether or not the entry is valid. */
bool valid = false;
};
public: public:
/** Creates a BTB with the given number of entries, number of bits per typedef BranchTargetBufferParams Params;
* tag, and instruction offset amount. typedef enums::BranchType BranchType;
* @param numEntries Number of entries for the BTB.
* @param tagBits Number of bits for each tag in the BTB.
* @param instShiftAmt Offset amount for instructions to ignore alignment.
*/
DefaultBTB(unsigned numEntries, unsigned tagBits,
unsigned instShiftAmt, unsigned numThreads);
void reset(); BranchTargetBuffer(const Params &params);
/** Looks up an address in the BTB. Must call valid() first on the address. virtual void memInvalidate() override = 0;
/** Checks if a branch address is in the BTB. Intended as a quick check
* before calling lookup. Does not update statistics.
* @param inst_PC The address of the branch to look up. * @param inst_PC The address of the branch to look up.
* @param tid The thread id.
* @return Returns the target of the branch.
*/
const PCStateBase *lookup(Addr instPC, ThreadID tid);
/** Checks if a branch is in the BTB.
* @param inst_PC The address of the branch to look up.
* @param tid The thread id.
* @return Whether or not the branch exists in the BTB. * @return Whether or not the branch exists in the BTB.
*/ */
bool valid(Addr instPC, ThreadID tid); virtual bool valid(ThreadID tid, Addr instPC) = 0;
/** Looks up an address in the BTB to get the target of the branch.
* @param inst_PC The address of the branch to look up.
* @param type Optional type of the branch to look up.
* @return The target of the branch or nullptr if the branch is not
* in the BTB.
*/
virtual const PCStateBase *lookup(ThreadID tid, Addr instPC,
BranchType type = BranchType::NoBranch) = 0;
/** Looks up an address in the BTB and return the instruction
* information if existant. Does not update statistics.
* @param inst_PC The address of the branch to look up.
* @return Returns the target of the branch.
*/
virtual const StaticInstPtr getInst(ThreadID tid, Addr instPC) = 0;
/** Updates the BTB with the target of a branch. /** Updates the BTB with the target of a branch.
* @param inst_pc The address of the branch being updated. * @param inst_pc The address of the branch being updated.
* @param target_pc The target address of the branch. * @param target_pc The target address of the branch.
* @param tid The thread id.
*/ */
void update(Addr inst_pc, const PCStateBase &target_pc, ThreadID tid); virtual void update(ThreadID tid, Addr inst_pc,
const PCStateBase &target_pc,
BranchType type = BranchType::NoBranch,
StaticInstPtr inst = nullptr) = 0;
private: /** Update BTB statistics
/** Returns the index into the BTB, based on the branch's PC.
* @param inst_PC The branch to look up.
* @return Returns the index into the BTB.
*/ */
inline unsigned getIndex(Addr instPC, ThreadID tid); virtual void incorrectTarget(Addr inst_pc,
BranchType type = BranchType::NoBranch)
{
stats.mispredict[type]++;
}
/** Returns the tag bits of a given address. protected:
* @param inst_PC The branch's address. /** Number of the threads for which the branch history is maintained. */
* @return Returns the tag bits. const unsigned numThreads;
*/
inline Addr getTag(Addr instPC);
/** The actual BTB. */ struct BranchTargetBufferStats : public statistics::Group
std::vector<BTBEntry> btb; {
BranchTargetBufferStats(statistics::Group *parent);
/** The number of entries in the BTB. */ statistics::Vector lookups;
unsigned numEntries; statistics::Vector misses;
statistics::Vector updates;
statistics::Vector mispredict;
statistics::Scalar evictions;
/** The index mask. */ } stats;
unsigned idxMask;
/** The number of tag bits per entry. */
unsigned tagBits;
/** The tag mask. */
unsigned tagMask;
/** Number of bits to shift PC when calculating index. */
unsigned instShiftAmt;
/** Number of bits to shift PC when calculating tag. */
unsigned tagShiftAmt;
/** Log2 NumThreads used for hashing threadid */
unsigned log2NumThreads;
}; };
} // namespace branch_prediction } // namespace branch_prediction

176
src/cpu/pred/simple_btb.cc Normal file
View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* 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.
*/
#include "cpu/pred/simple_btb.hh"
#include "base/intmath.hh"
#include "base/trace.hh"
#include "debug/BTB.hh"
namespace gem5
{
namespace branch_prediction
{
SimpleBTB::SimpleBTB(const SimpleBTBParams &p)
: BranchTargetBuffer(p),
numEntries(p.numEntries),
tagBits(p.tagBits),
instShiftAmt(p.instShiftAmt),
log2NumThreads(floorLog2(p.numThreads))
{
DPRINTF(BTB, "BTB: Creating BTB object.\n");
if (!isPowerOf2(numEntries)) {
fatal("BTB entries is not a power of 2!");
}
btb.resize(numEntries);
for (unsigned i = 0; i < numEntries; ++i) {
btb[i].valid = false;
}
idxMask = numEntries - 1;
tagMask = (1 << tagBits) - 1;
tagShiftAmt = instShiftAmt + floorLog2(numEntries);
}
void
SimpleBTB::memInvalidate()
{
for (unsigned i = 0; i < numEntries; ++i) {
btb[i].valid = false;
}
}
inline
unsigned
SimpleBTB::getIndex(Addr instPC, ThreadID tid)
{
// Need to shift PC over by the word offset.
return ((instPC >> instShiftAmt)
^ (tid << (tagShiftAmt - instShiftAmt - log2NumThreads)))
& idxMask;
}
inline
Addr
SimpleBTB::getTag(Addr instPC)
{
return (instPC >> tagShiftAmt) & tagMask;
}
SimpleBTB::BTBEntry *
SimpleBTB::findEntry(Addr instPC, ThreadID tid)
{
unsigned btb_idx = getIndex(instPC, tid);
Addr inst_tag = getTag(instPC);
assert(btb_idx < numEntries);
if (btb[btb_idx].valid
&& inst_tag == btb[btb_idx].tag
&& btb[btb_idx].tid == tid) {
return &btb[btb_idx];
}
return nullptr;
}
bool
SimpleBTB::valid(ThreadID tid, Addr instPC)
{
BTBEntry *entry = findEntry(instPC, tid);
return entry != nullptr;
}
// @todo Create some sort of return struct that has both whether or not the
// address is valid, and also the address. For now will just use addr = 0 to
// represent invalid entry.
const PCStateBase *
SimpleBTB::lookup(ThreadID tid, Addr instPC, BranchType type)
{
stats.lookups[type]++;
BTBEntry *entry = findEntry(instPC, tid);
if (entry) {
return entry->target.get();
}
stats.misses[type]++;
return nullptr;
}
const StaticInstPtr
SimpleBTB::getInst(ThreadID tid, Addr instPC)
{
BTBEntry *entry = findEntry(instPC, tid);
if (entry) {
return entry->inst;
}
return nullptr;
}
void
SimpleBTB::update(ThreadID tid, Addr instPC,
const PCStateBase &target,
BranchType type, StaticInstPtr inst)
{
unsigned btb_idx = getIndex(instPC, tid);
assert(btb_idx < numEntries);
stats.updates[type]++;
btb[btb_idx].tid = tid;
btb[btb_idx].valid = true;
set(btb[btb_idx].target, target);
btb[btb_idx].tag = getTag(instPC);
btb[btb_idx].inst = inst;
}
} // namespace branch_prediction
} // namespace gem5

136
src/cpu/pred/simple_btb.hh Normal file
View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* 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.
*/
#ifndef __CPU_PRED_SIMPLE_BTB_HH__
#define __CPU_PRED_SIMPLE_BTB_HH__
#include "base/logging.hh"
#include "base/types.hh"
#include "cpu/pred/btb.hh"
#include "params/SimpleBTB.hh"
namespace gem5
{
namespace branch_prediction
{
class SimpleBTB : public BranchTargetBuffer
{
public:
SimpleBTB(const SimpleBTBParams &params);
void memInvalidate() override;
bool valid(ThreadID tid, Addr instPC) override;
const PCStateBase *lookup(ThreadID tid, Addr instPC,
BranchType type = BranchType::NoBranch) override;
void update(ThreadID tid, Addr instPC, const PCStateBase &target_pc,
BranchType type = BranchType::NoBranch,
StaticInstPtr inst = nullptr) override;
const StaticInstPtr getInst(ThreadID tid, Addr instPC) override;
private:
struct BTBEntry
{
/** The entry's tag. */
Addr tag = 0;
/** The entry's target. */
std::unique_ptr<PCStateBase> target;
/** The entry's thread id. */
ThreadID tid;
/** Whether or not the entry is valid. */
bool valid = false;
/** Pointer to the static branch instruction at this address */
StaticInstPtr inst = nullptr;
};
/** Returns the index into the BTB, based on the branch's PC.
* @param inst_PC The branch to look up.
* @return Returns the index into the BTB.
*/
inline unsigned getIndex(Addr instPC, ThreadID tid);
/** Returns the tag bits of a given address.
* @param inst_PC The branch's address.
* @return Returns the tag bits.
*/
inline Addr getTag(Addr instPC);
/** Internal call to find an address in the BTB
* @param instPC The branch's address.
* @return Returns a pointer to the BTB entry if found, nullptr otherwise.
*/
BTBEntry *findEntry(Addr instPC, ThreadID tid);
/** The actual BTB. */
std::vector<BTBEntry> btb;
/** The number of entries in the BTB. */
unsigned numEntries;
/** The index mask. */
unsigned idxMask;
/** The number of tag bits per entry. */
unsigned tagBits;
/** The tag mask. */
unsigned tagMask;
/** Number of bits to shift PC when calculating index. */
unsigned instShiftAmt;
/** Number of bits to shift PC when calculating tag. */
unsigned tagShiftAmt;
/** Log2 NumThreads used for hashing threadid */
unsigned log2NumThreads;
};
} // namespace branch_prediction
} // namespace gem5
#endif // __CPU_PRED_SIMPLE_BTB_HH__

View File

@@ -95,7 +95,7 @@ class U74FUPool(MinorFUPool):
class U74BP(TournamentBP): class U74BP(TournamentBP):
BTBEntries = 32 btb = SimpleBTB(numEntries=32)
RASSize = 12 RASSize = 12
localHistoryTableSize = 4096 # is 3.6 KiB but gem5 requires power of 2 localHistoryTableSize = 4096 # is 3.6 KiB but gem5 requires power of 2
localPredictorSize = 16384 localPredictorSize = 16384