提交 6b0d407e 编写于 作者: A Allen

Merge branch 'master' of github.com:RISCVERS/XiangShan into fixBankedL3

......@@ -52,14 +52,22 @@ EMU_VSRC_DIR = $(abspath ./src/test/vsrc)
EMU_CXXFILES = $(shell find $(EMU_CSRC_DIR) -name "*.cpp")
EMU_VFILES = $(shell find $(EMU_VSRC_DIR) -name "*.v" -or -name "*.sv")
EMU_CXXFLAGS = -std=c++11 -static -Wall -I$(EMU_CSRC_DIR)
EMU_CXXFLAGS += -std=c++11 -static -Wall -I$(EMU_CSRC_DIR)
EMU_CXXFLAGS += -DVERILATOR -Wno-maybe-uninitialized
EMU_LDFLAGS = -lpthread -lSDL2 -ldl
EMU_THREADS = 1
ifeq ($(EMU_THREADS), 1)
VTHREAD_FLAGS = --threads 1
else
VTHREAD_FLAGS = --threads $(EMU_THREADS) --threads-dpi none
# Verilator trace support
VEXTRA_FLAGS = --trace
# Verilator multi-thread support
EMU_THREADS ?= 1
VEXTRA_FLAGS += --threads $(EMU_THREADS) --threads-dpi none
# Verilator savable
EMU_SNAPSHOT ?= 0
ifeq ($(EMU_SNAPSHOT),1)
VEXTRA_FLAGS += --savable
EMU_CXXFLAGS += -DVM_SAVABLE
endif
# --trace
......@@ -68,10 +76,8 @@ VERILATOR_FLAGS = --top-module $(SIM_TOP) \
+define+PRINTF_COND=1 \
+define+RANDOMIZE_REG_INIT \
+define+RANDOMIZE_MEM_INIT \
$(VTHREAD_FLAGS) \
--trace \
$(VEXTRA_FLAGS) \
--assert \
--savable \
--stats-vars \
--output-split 5000 \
--output-split-cfuncs 5000 \
......@@ -97,7 +103,7 @@ $(EMU): $(EMU_MK) $(EMU_DEPS) $(EMU_HEADERS) $(REF_SO)
ifeq ($(REMOTE),localhost)
CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))
else
ssh -tt $(REMOTE) 'CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) -j80 VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))'
ssh -tt $(REMOTE) 'CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) -j200 VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))'
endif
SEED ?= $(shell shuf -i 1-10000 -n 1)
......@@ -108,7 +114,6 @@ SEED ?= $(shell shuf -i 1-10000 -n 1)
B ?= 0
E ?= -1
SNAPSHOT ?=
ENABLESNAPSHOT ?= 0
# enable this runtime option if you want to generate a vcd file
# use 'emu -h' to see more details
......@@ -121,10 +126,6 @@ SNAPSHOT_OPTION = --load-snapshot=$(SNAPSHOT)
endif
ifeq ($(ENABLESNAPSHOT),1)
EMU_CXXFLAGS += -D__ENABLESNAPSHOT__
endif
EMU_FLAGS = -s $(SEED) -b $(B) -e $(E) $(SNAPSHOT_OPTION) $(WAVEFORM)
emu: $(EMU)
......
#!/bin/bash
log_dir=$1
tage_w_sc_w=$(grep "scUpdate" $log_dir | grep "sc(1), tage(1)" -c)
tage_w_sc_r=$(grep "scUpdate" $log_dir | grep "sc(0), tage(1)" -c)
tage_r_sc_w=$(grep "scUpdate" $log_dir | grep "sc(1), tage(0)" -c)
tage_r_sc_r=$(grep "scUpdate" $log_dir | grep "sc(0), tage(0)" -c)
echo $tage_r_sc_w tage right but mispredicted by sc
echo $tage_w_sc_r tage wrong and rectified by sc
echo `expr $tage_w_sc_w + $tage_r_sc_r` branches remain unchanged, in which $tage_w_sc_w are wrong
......@@ -10,6 +10,7 @@ import xiangshan.mem.{LqPtr, SqPtr}
import xiangshan.frontend.PreDecodeInfo
import xiangshan.frontend.HasBPUParameter
import xiangshan.frontend.HasTageParameter
import scala.math.max
// Fetch FetchWidth x 32-bit insts from Icache
class FetchPacket extends XSBundle {
......@@ -37,12 +38,26 @@ object ValidUndirectioned {
}
}
class SCMeta(val useSC: Boolean) extends XSBundle with HasTageParameter {
def maxVal = 8 * ((1 << TageCtrBits) - 1) + SCTableInfo.map{case (_,cb,_) => (1 << cb) - 1}.reduce(_+_)
def minVal = -(8 * (1 << TageCtrBits) + SCTableInfo.map{case (_,cb,_) => 1 << cb}.reduce(_+_))
def sumCtrBits = max(log2Ceil(-minVal), log2Ceil(maxVal+1)) + 1
val tageTaken = if (useSC) Bool() else UInt(0.W)
val scUsed = if (useSC) Bool() else UInt(0.W)
val scPred = if (useSC) Bool() else UInt(0.W)
// Suppose ctrbits of all tables are identical
val ctrs = if (useSC) Vec(SCNTables, SInt(SCCtrBits.W)) else Vec(SCNTables, SInt(0.W))
val sumAbs = if (useSC) UInt(sumCtrBits.W) else UInt(0.W)
}
class TageMeta extends XSBundle with HasTageParameter {
val provider = ValidUndirectioned(UInt(log2Ceil(TageNTables).W))
val altDiffers = Bool()
val providerU = UInt(2.W)
val providerCtr = UInt(3.W)
val allocate = ValidUndirectioned(UInt(log2Ceil(TageNTables).W))
val taken = Bool()
val scMeta = new SCMeta(EnableSC)
}
class BranchPrediction extends XSBundle {
......
......@@ -37,6 +37,7 @@ case class XSCoreParameters
EnableRAS: Boolean = true,
EnableLB: Boolean = true,
EnableLoop: Boolean = true,
EnableSC: Boolean = false,
HistoryLength: Int = 64,
BtbSize: Int = 2048,
JbtacSize: Int = 1024,
......@@ -121,6 +122,7 @@ trait HasXSParameter {
val EnableRAS = core.EnableRAS
val EnableLB = core.EnableLB
val EnableLoop = core.EnableLoop
val EnableSC = core.EnableSC
val HistoryLength = core.HistoryLength
val BtbSize = core.BtbSize
// val BtbWays = 4
......
......@@ -11,7 +11,7 @@ trait HasBPUParameter extends HasXSParameter {
val BPUDebug = false
val EnableCFICommitLog = true
val EnbaleCFIPredLog = true
val EnableBPUTimeRecord = true
val EnableBPUTimeRecord = EnableCFICommitLog || EnbaleCFIPredLog
}
class TableAddr(val idxBits: Int, val banks: Int) extends XSBundle {
......@@ -63,7 +63,42 @@ class PredictorResponse extends XSBundle {
val loop = new LoopResp
}
abstract class BasePredictor extends XSModule with HasBPUParameter{
trait PredictorUtils {
// circular shifting
def circularShiftLeft(source: UInt, len: Int, shamt: UInt): UInt = {
val res = Wire(UInt(len.W))
val higher = source << shamt
val lower = source >> (len.U - shamt)
res := higher | lower
res
}
def circularShiftRight(source: UInt, len: Int, shamt: UInt): UInt = {
val res = Wire(UInt(len.W))
val higher = source << (len.U - shamt)
val lower = source >> shamt
res := higher | lower
res
}
// To be verified
def satUpdate(old: UInt, len: Int, taken: Bool): UInt = {
val oldSatTaken = old === ((1 << len)-1).U
val oldSatNotTaken = old === 0.U
Mux(oldSatTaken && taken, ((1 << len)-1).U,
Mux(oldSatNotTaken && !taken, 0.U,
Mux(taken, old + 1.U, old - 1.U)))
}
def signedSatUpdate(old: SInt, len: Int, taken: Bool): SInt = {
val oldSatTaken = old === ((1 << (len-1))-1).S
val oldSatNotTaken = old === (-(1 << (len-1))).S
Mux(oldSatTaken && taken, ((1 << (len-1))-1).S,
Mux(oldSatNotTaken && !taken, (-(1 << (len-1))).S,
Mux(taken, old + 1.S, old - 1.S)))
}
}
abstract class BasePredictor extends XSModule with HasBPUParameter with PredictorUtils {
val metaLen = 0
// An implementation MUST extend the IO bundle with a response
......@@ -85,23 +120,6 @@ abstract class BasePredictor extends XSModule with HasBPUParameter{
val io = new DefaultBasePredictorIO
val debug = false
// circular shifting
def circularShiftLeft(source: UInt, len: Int, shamt: UInt): UInt = {
val res = Wire(UInt(len.W))
val higher = source << shamt
val lower = source >> (len.U - shamt)
res := higher | lower
res
}
def circularShiftRight(source: UInt, len: Int, shamt: UInt): UInt = {
val res = Wire(UInt(len.W))
val higher = source << (len.U - shamt)
val lower = source >> shamt
res := higher | lower
res
}
}
class BPUStageIO extends XSBundle {
......@@ -237,6 +255,9 @@ class BPUStage1 extends BPUStage {
io.out.bits.resp <> io.in.bits.resp
io.out.bits.brInfo := io.in.bits.brInfo
// we do not need to compare target in stage1
io.pred.bits.redirect := taken
if (BPUDebug) {
XSDebug(io.pred.fire(), "outPred using ubtb resp: hits:%b, takens:%b, notTakens:%b, isRVC:%b\n",
ubtbResp.hits.asUInt, ubtbResp.takens.asUInt, ~ubtbResp.takens.asUInt & brMask.asUInt, ubtbResp.is_RVC.asUInt)
......@@ -571,7 +592,7 @@ class BPU extends BaseBPU {
s1.io.in.valid := io.in.valid
s1.io.in.bits.pc := io.in.bits.pc
s1.io.in.bits.mask := io.in.bits.inMask
s1.io.in.bits.target := npc(io.in.bits.pc, PopCount(io.in.bits.inMask)) // Deault target npc
s1.io.in.bits.target := DontCare
s1.io.in.bits.resp <> s1_resp_in
s1.io.in.bits.brInfo <> s1_brInfo_in
s1.io.in.bits.saveHalfRVI := false.B
......
......@@ -29,15 +29,6 @@ class BIM extends BasePredictor with BimParams{
}
override val io = IO(new BIMIO)
// Update logic
// 1 calculate new 2-bit saturated counter value
def satUpdate(old: UInt, len: Int, taken: Bool): UInt = {
val oldSatTaken = old === ((1 << len)-1).U
val oldSatNotTaken = old === 0.U
Mux(oldSatTaken && taken, ((1 << len)-1).U,
Mux(oldSatNotTaken && !taken, 0.U,
Mux(taken, old + 1.U, old - 1.U)))
}
val bimAddr = new TableAddr(log2Up(BimSize), BimBanks)
......
......@@ -84,10 +84,13 @@ class IFU extends XSModule with HasIFUConst
shiftPtr := false.B
newPtr := if1_histPtr
val if1_GHInfo = Wire(new GlobalHistoryInfo())
if1_GHInfo := 0.U.asTypeOf(new GlobalHistoryInfo)
def wrapGHInfo(bp: BranchPrediction) = {
val ghi = Wire(new GlobalHistoryInfo())
ghi.sawNTBr := bp.hasNotTakenBrs
ghi.takenOnBr := bp.takenOnBr
ghi.saveHalfRVI := bp.saveHalfRVI
ghi
}
//********************** IF2 ****************************//
val if2_valid = RegEnable(next = if1_valid, init = false.B, enable = if1_fire)
......@@ -95,7 +98,6 @@ class IFU extends XSModule with HasIFUConst
val if2_fire = if2_valid && if3_ready && !if2_flush
val if2_pc = RegEnable(next = if1_npc, init = resetVector.U, enable = if1_fire)
val if2_snpc = snpc(if2_pc)
val if2_GHInfo = RegEnable(if1_GHInfo, if1_fire)
val if2_predHistPtr = RegEnable(ptr, enable=if1_fire)
if2_ready := if2_fire || !if2_valid || if2_flush
when (if2_flush) { if2_valid := if1_fire }
......@@ -118,17 +120,14 @@ class IFU extends XSModule with HasIFUConst
if1_npc := if2_bp.target
}
val if2_realGHInfo = Wire(new GlobalHistoryInfo())
if2_realGHInfo.sawNTBr := if2_bp.hasNotTakenBrs
if2_realGHInfo.takenOnBr := if2_bp.takenOnBr
if2_realGHInfo.saveHalfRVI := if2_bp.saveHalfRVI
val if2_GHInfo = wrapGHInfo(if2_bp)
when (if2_fire && if2_realGHInfo.shifted) {
when (if2_fire && if2_GHInfo.shifted) {
shiftPtr := true.B
newPtr := if2_newPtr
}
when (if2_realGHInfo.shifted && if2_newPtr >= ptr) {
hist(if2_newPtr-ptr) := if2_realGHInfo.takenOnBr.asUInt
when (if2_GHInfo.shifted && if2_newPtr >= ptr) {
hist(if2_newPtr-ptr) := if2_GHInfo.takenOnBr.asUInt
}
......@@ -138,7 +137,6 @@ class IFU extends XSModule with HasIFUConst
val if4_ready = WireInit(false.B)
val if3_fire = if3_valid && if4_ready && (inLoop || io.icacheResp.valid) && !if3_flush
val if3_pc = RegEnable(if2_pc, if2_fire)
val if3_GHInfo = RegEnable(if2_realGHInfo, if2_fire)
val if3_predHistPtr = RegEnable(if2_predHistPtr, enable=if2_fire)
if3_ready := if3_fire || !if3_valid || if3_flush
when (if3_flush) { if3_valid := false.B }
......@@ -147,10 +145,7 @@ class IFU extends XSModule with HasIFUConst
val if3_bp = bpu.io.out(1).bits
val if3_realGHInfo = Wire(new GlobalHistoryInfo())
if3_realGHInfo.sawNTBr := if3_bp.hasNotTakenBrs
if3_realGHInfo.takenOnBr := if3_bp.takenOnBr
if3_realGHInfo.saveHalfRVI := if3_bp.saveHalfRVI
val if3_GHInfo = wrapGHInfo(if3_bp)
class PrevHalfInstr extends Bundle {
val valid = Bool()
......@@ -189,7 +184,7 @@ class IFU extends XSModule with HasIFUConst
when (if3_redirect) {
when (!(if3_hasPrevHalfInstr && prevHalfInstr.taken)) {
if1_npc := if3_bp.target
when (if3_realGHInfo.shifted){
when (if3_GHInfo.shifted){
shiftPtr := true.B
newPtr := if3_newPtr
}
......@@ -197,8 +192,8 @@ class IFU extends XSModule with HasIFUConst
}
// when it does not redirect, we still need to modify hist(wire)
when(if3_realGHInfo.shifted && if3_newPtr >= ptr) {
hist(if3_newPtr-ptr) := if3_realGHInfo.takenOnBr
when(if3_GHInfo.shifted && if3_newPtr >= ptr) {
hist(if3_newPtr-ptr) := if3_GHInfo.takenOnBr
}
when (if3_hasPrevHalfInstr && prevHalfInstr.ghInfo.shifted && prevHalfInstr.newPtr >= ptr) {
hist(prevHalfInstr.newPtr-ptr) := prevHalfInstr.ghInfo.takenOnBr
......@@ -212,7 +207,6 @@ class IFU extends XSModule with HasIFUConst
val if4_fire = if4_valid && io.fetchPacket.ready
val if4_pc = RegEnable(if3_pc, if3_fire)
val if4_GHInfo = RegEnable(if3_realGHInfo, if3_fire)
val if4_predHistPtr = RegEnable(if3_predHistPtr, enable=if3_fire)
if4_ready := (if4_fire || !if4_valid || if4_flush) && GTimer() > 500.U
when (if4_flush) { if4_valid := false.B }
......@@ -222,11 +216,7 @@ class IFU extends XSModule with HasIFUConst
val if4_bp = Wire(new BranchPrediction)
if4_bp := bpu.io.out(2).bits
val if4_realGHInfo = Wire(new GlobalHistoryInfo())
if4_realGHInfo.sawNTBr := if4_bp.hasNotTakenBrs
if4_realGHInfo.takenOnBr := if4_bp.takenOnBr
if4_realGHInfo.saveHalfRVI := if4_bp.saveHalfRVI
val if4_GHInfo = wrapGHInfo(if4_bp)
val if4_cfi_jal = if4_pd.instrs(if4_bp.jmpIdx)
val if4_cfi_jal_tgt = if4_pd.pc(if4_bp.jmpIdx) + Mux(if4_pd.pd(if4_bp.jmpIdx).isRVC,
......@@ -239,7 +229,7 @@ class IFU extends XSModule with HasIFUConst
when (bpu.io.out(2).valid && if4_fire && if4_bp.saveHalfRVI) {
if4_prevHalfInstr.valid := true.B
if4_prevHalfInstr.taken := if4_bp.taken
if4_prevHalfInstr.ghInfo := if4_realGHInfo
if4_prevHalfInstr.ghInfo := if4_GHInfo
// Make sure shifted can work
if4_prevHalfInstr.ghInfo.saveHalfRVI := false.B
if4_prevHalfInstr.newPtr := if4_newPtr
......@@ -260,14 +250,6 @@ class IFU extends XSModule with HasIFUConst
if1_npc := if4_bp.target
}
}
// }.elsewhen (bpu.io.out(2).valid && if4_fire/* && !if4_bp.redirect*/) {
// // We redirect the pipeline to the next fetch packet,
// // which contains the last half of the RVI instruction
// when (if4_bp.saveHalfRVI && if4_bp.taken) {
// if4_redirect := true.B
// if1_npc := snpc(if4_pc)
// }
// }
// This should cover the if4 redirect to snpc when saveHalfRVI
when (if3_redirect) {
......@@ -280,20 +262,10 @@ class IFU extends XSModule with HasIFUConst
when (bpu.io.out(2).valid && if4_fire && if4_bp.redirect) {
shiftPtr := true.B
newPtr := if4_newPtr
// }.elsewhen (bpu.io.out(2).valid && if4_fire/* && !if4_bp.redirect*/) {
// // only if we hasn't seen not taken branches and
// // see a not taken branch in if4 should we tell
// // if3 and if4 to update histptr
// // We do not shift global history pointer unless we have the full
// // RVI instruction
// when (if4_newSawNTBrs && !if4_bp.takenOnBr) {
// shiftPtr := true.B
// // newPtr := if4_realGHInfo.newPtr
// }
}
when (if4_realGHInfo.shifted && if4_newPtr >= ptr) {
hist(if4_newPtr-ptr) := if4_realGHInfo.takenOnBr
when (if4_GHInfo.shifted && if4_newPtr >= ptr) {
hist(if4_newPtr-ptr) := if4_GHInfo.takenOnBr
}
when (if3_redirect) {
......@@ -306,8 +278,8 @@ class IFU extends XSModule with HasIFUConst
}
// modify GHR at the end of a prediction lifetime
when (if4_fire && if4_realGHInfo.shifted) {
extHist(if4_newPtr) := if4_realGHInfo.takenOnBr
when (if4_fire && if4_GHInfo.shifted) {
extHist(if4_newPtr) := if4_GHInfo.takenOnBr
}
// This is a histPtr which is only modified when a prediction
......@@ -315,17 +287,17 @@ class IFU extends XSModule with HasIFUConst
val finalPredHistPtr = RegInit(0.U(log2Up(ExtHistoryLength).W))
if4_histPtr := finalPredHistPtr
if4_newPtr := if3_histPtr
when (if4_fire && if4_realGHInfo.shifted) {
when (if4_fire && if4_GHInfo.shifted) {
finalPredHistPtr := if4_newPtr
}
if3_histPtr := Mux(if4_realGHInfo.shifted && if4_valid && !if4_flush, if4_histPtr - 1.U, if4_histPtr)
if3_histPtr := Mux(if4_GHInfo.shifted && if4_valid && !if4_flush, if4_histPtr - 1.U, if4_histPtr)
if3_newPtr := if2_histPtr
if2_histPtr := Mux(if3_realGHInfo.shifted && if3_valid && !if3_flush, if3_histPtr - 1.U, if3_histPtr)
if2_histPtr := Mux(if3_GHInfo.shifted && if3_valid && !if3_flush, if3_histPtr - 1.U, if3_histPtr)
if2_newPtr := if1_histPtr
if1_histPtr := Mux(if2_realGHInfo.shifted && if2_valid && !if2_flush, if2_histPtr - 1.U, if2_histPtr)
if1_histPtr := Mux(if2_GHInfo.shifted && if2_valid && !if2_flush, if2_histPtr - 1.U, if2_histPtr)
......@@ -473,16 +445,15 @@ class IFU extends XSModule with HasIFUConst
XSDebug("[IF1] v=%d fire=%d flush=%d pc=%x ptr=%d mask=%b\n", if1_valid, if1_fire, if1_flush, if1_npc, ptr, mask(if1_npc))
XSDebug("[IF2] v=%d r=%d fire=%d redirect=%d flush=%d pc=%x ptr=%d snpc=%x\n", if2_valid, if2_ready, if2_fire, if2_redirect, if2_flush, if2_pc, if2_histPtr, if2_snpc)
XSDebug("[IF3] v=%d r=%d fire=%d redirect=%d flush=%d pc=%x ptr=%d crossPageIPF=%d sawNTBrs=%d\n", if3_valid, if3_ready, if3_fire, if3_redirect, if3_flush, if3_pc, if3_histPtr, crossPageIPF, if3_realGHInfo.sawNTBr)
XSDebug("[IF4] v=%d r=%d fire=%d redirect=%d flush=%d pc=%x ptr=%d crossPageIPF=%d sawNTBrs=%d\n", if4_valid, if4_ready, if4_fire, if4_redirect, if4_flush, if4_pc, if4_histPtr, if4_crossPageIPF, if4_realGHInfo.sawNTBr)
XSDebug("[IF3] v=%d r=%d fire=%d redirect=%d flush=%d pc=%x ptr=%d crossPageIPF=%d sawNTBrs=%d\n", if3_valid, if3_ready, if3_fire, if3_redirect, if3_flush, if3_pc, if3_histPtr, crossPageIPF, if3_GHInfo.sawNTBr)
XSDebug("[IF4] v=%d r=%d fire=%d redirect=%d flush=%d pc=%x ptr=%d crossPageIPF=%d sawNTBrs=%d\n", if4_valid, if4_ready, if4_fire, if4_redirect, if4_flush, if4_pc, if4_histPtr, if4_crossPageIPF, if4_GHInfo.sawNTBr)
XSDebug("[IF1][icacheReq] v=%d r=%d addr=%x\n", io.icacheReq.valid, io.icacheReq.ready, io.icacheReq.bits.addr)
XSDebug("[IF1][ghr] headPtr=%d shiftPtr=%d newPtr=%d ptr=%d\n", if1_histPtr, shiftPtr, newPtr, ptr)
XSDebug("[IF1][ghr] hist=%b\n", hist.asUInt)
XSDebug("[IF1][ghr] extHist=%b\n\n", extHist.asUInt)
XSDebug("[IF2][bp] redirect=%d taken=%d jmpIdx=%d hasNTBrs=%d target=%x saveHalfRVI=%d\n\n", if2_bp.redirect, if2_bp.taken, if2_bp.jmpIdx, if2_bp.hasNotTakenBrs, if2_bp.target, if2_bp.saveHalfRVI)
// XSDebug("[IF2][GHInfo]: %s\n", if2_realGHInfo)
if2_realGHInfo.debug
if2_GHInfo.debug
XSDebug("[IF3][icacheResp] v=%d r=%d pc=%x mask=%b\n", io.icacheResp.valid, io.icacheResp.ready, io.icacheResp.bits.pc, io.icacheResp.bits.mask)
XSDebug("[IF3][bp] redirect=%d taken=%d jmpIdx=%d hasNTBrs=%d target=%x saveHalfRVI=%d\n", if3_bp.redirect, if3_bp.taken, if3_bp.jmpIdx, if3_bp.hasNotTakenBrs, if3_bp.target, if3_bp.saveHalfRVI)
......@@ -492,16 +463,14 @@ class IFU extends XSModule with HasIFUConst
prevHalfInstr.valid, prevHalfInstr.taken, prevHalfInstr.fetchpc, prevHalfInstr.idx, prevHalfInstr.pc, prevHalfInstr.target, prevHalfInstr.instr, prevHalfInstr.ipf)
XSDebug("[IF3][if3_prevHalfInstr] v=%d taken=%d fetchpc=%x idx=%d pc=%x tgt=%x instr=%x ipf=%d\n\n",
if3_prevHalfInstr.valid, if3_prevHalfInstr.taken, if3_prevHalfInstr.fetchpc, if3_prevHalfInstr.idx, if3_prevHalfInstr.pc, if3_prevHalfInstr.target, if3_prevHalfInstr.instr, if3_prevHalfInstr.ipf)
// XSDebug("[IF3][GHInfo]: %s\n", if3_realGHInfo)
if3_realGHInfo.debug
if3_GHInfo.debug
XSDebug("[IF4][predecode] mask=%b\n", if4_pd.mask)
XSDebug("[IF4][bp] redirect=%d taken=%d jmpIdx=%d hasNTBrs=%d target=%x saveHalfRVI=%d\n", if4_bp.redirect, if4_bp.taken, if4_bp.jmpIdx, if4_bp.hasNotTakenBrs, if4_bp.target, if4_bp.saveHalfRVI)
XSDebug(if4_pd.pd(if4_bp.jmpIdx).isJal && if4_bp.taken, "[IF4] cfi is jal! instr=%x target=%x\n", if4_cfi_jal, if4_cfi_jal_tgt)
XSDebug("[IF4][if4_prevHalfInstr] v=%d taken=%d fetchpc=%x idx=%d pc=%x tgt=%x instr=%x ipf=%d\n",
if4_prevHalfInstr.valid, if4_prevHalfInstr.taken, if4_prevHalfInstr.fetchpc, if4_prevHalfInstr.idx, if4_prevHalfInstr.pc, if4_prevHalfInstr.target, if4_prevHalfInstr.instr, if4_prevHalfInstr.ipf)
// XSDebug("[IF4][GHInfo]: %s\n", if4_realGHInfo)
if4_realGHInfo.debug
if4_GHInfo.debug
XSDebug(io.fetchPacket.fire(), "[IF4][fetchPacket] v=%d r=%d mask=%b ipf=%d crossPageIPF=%d\n",
io.fetchPacket.valid, io.fetchPacket.ready, io.fetchPacket.bits.mask, io.fetchPacket.bits.ipf, io.fetchPacket.bits.crossPageIPFFix)
for (i <- 0 until PredictWidth) {
......
......@@ -77,7 +77,48 @@ class LTBColumn extends LTBModule {
val repair = Input(Bool()) // roll back specCnts in the other 15 LTBs
})
val ltb = Reg(Vec(nRows, new LoopEntry))
class LTBMem extends LTBModule {
val io = IO(new Bundle {
val rIdx = Input(UInt(idxLen.W))
val rdata = Output(new LoopEntry)
val urIdx = Input(UInt(idxLen.W))
val urdata = Output(new LoopEntry)
val wen = Input(Bool())
val wIdx = Input(UInt(idxLen.W))
val wdata = Input(new LoopEntry)
val swen = Input(Bool())
val swIdx = Input(UInt(idxLen.W))
val swdata = Input(new LoopEntry)
val copyCnt = Input(Vec(nRows, Bool()))
})
// val mem = RegInit(0.U.asTypeOf(Vec(nRows, new LoopEntry)))
val mem = Mem(nRows, new LoopEntry)
io.rdata := mem(io.rIdx)
io.urdata := mem(io.urIdx)
val wdata = WireInit(io.wdata)
val swdata = WireInit(io.swdata)
for (i <- 0 until nRows) {
val copyValid = io.copyCnt(i)
when (copyValid && io.swIdx === i.U && io.swen) {
swdata.specCnt := mem(i).nSpecCnt
}
val wd = WireInit(mem(i)) // default for copycnt
val wen = WireInit(io.copyCnt(i) || io.wen && io.wIdx === i.U || io.swen && io.swIdx === i.U)
when (!copyValid) {
when (io.swen) {
wd := swdata
}.elsewhen (io.wen) {
wd := wdata
}
}
when (wen) {
mem.write(i.U, wd)
}
}
}
// val ltb = Reg(Vec(nRows, new LoopEntry))
val ltb = Module(new LTBMem).io
val ltbAddr = new TableAddr(idxLen + 4, PredictWidth)
val updateIdx = ltbAddr.getBankIdx(io.update.bits.pc)
val updateTag = ltbAddr.getTag(io.update.bits.pc)(tagLen - 1, 0)
......@@ -92,7 +133,8 @@ class LTBColumn extends LTBModule {
val if4_idx = io.req.idx
val if4_tag = io.req.tag
val if4_pc = io.req.pc // only for debug
val if4_entry = WireInit(ltb(if4_idx))
ltb.rIdx := if4_idx
val if4_entry = WireInit(ltb.rdata)
val valid = RegInit(false.B)
when (io.if4_fire) { valid := false.B }
......@@ -104,11 +146,16 @@ class LTBColumn extends LTBModule {
io.resp.exit := if4_tag === if4_entry.tag && (if4_entry.specCnt + 1.U) === if4_entry.tripCnt && valid && if4_entry.isConf
// when resolving a branch
val entry = ltb(updateIdx)
ltb.urIdx := updateIdx
val entry = ltb.urdata
val tagMatch = entry.tag === updateTag
val cntMatch = entry.tripCnt === io.update.bits.meta
val wEntry = WireInit(entry)
ltb.wIdx := updateIdx
ltb.wdata := wEntry
ltb.wen := false.B
when (io.update.valid && !doingReset) {
// When a branch resolves and is found to not be in the LTB,
// it is inserted into the LTB if determined to be a loop-branch and if it is mispredicted by the default predictor.
......@@ -121,7 +168,8 @@ class LTBColumn extends LTBModule {
wEntry.nSpecCnt := Mux(io.update.bits.taken, 1.U, 0.U)
wEntry.brTag := updateBrTag
wEntry.unusable := false.B
ltb(updateIdx) := wEntry
// ltb(updateIdx) := wEntry
ltb.wen := true.B
}.elsewhen (tagMatch) {
// During resolution, a taken branch found in the LTB has its nSpecCnt incremented by one.
when (io.update.bits.taken) {
......@@ -142,40 +190,44 @@ class LTBColumn extends LTBModule {
wEntry.brTag := updateBrTag
wEntry.unusable := io.update.bits.misPred && (io.update.bits.meta > entry.tripCnt)
}
ltb(updateIdx) := wEntry
// ltb(updateIdx) := wEntry
ltb.wen := true.B
}
}
// speculatively update specCnt
ltb.swen := valid && if4_entry.tag === if4_tag || doingReset
ltb.swIdx := Mux(doingReset, resetIdx, if4_idx)
val swEntry = WireInit(if4_entry)
ltb.swdata := Mux(doingReset, 0.U.asTypeOf(new LoopEntry), swEntry)
when (io.if4_fire && if4_entry.tag === if4_tag && io.outMask) {
when ((if4_entry.specCnt + 1.U) === if4_entry.tripCnt) {
ltb(if4_idx).age := 7.U
ltb(if4_idx).specCnt := 0.U
when ((if4_entry.specCnt + 1.U) === if4_entry.tripCnt/* && if4_entry.isConf*/) {
swEntry.age := 7.U
swEntry.specCnt := 0.U
}.otherwise {
ltb(if4_idx).age := Mux(if4_entry.age === 7.U, 7.U, if4_entry.age + 1.U)
ltb(if4_idx).specCnt := if4_entry.specCnt + 1.U
swEntry.age := Mux(if4_entry.age === 7.U, 7.U, if4_entry.age + 1.U)
swEntry.specCnt := if4_entry.specCnt + 1.U
}
}
// Reseting
when (doingReset) {
ltb(resetIdx) := 0.U.asTypeOf(new LoopEntry)
}
// when (doingReset) {
// ltb(resetIdx) := 0.U.asTypeOf(new LoopEntry)
// }
// when a branch misprediction occurs, all of the nSpecCnts copy their values into the specCnts
for (i <- 0 until nRows) {
when (io.update.valid && io.update.bits.misPred && i.U =/= updateIdx || io.repair) {
ltb(i).specCnt := ltb(i).nSpecCnt
}
ltb.copyCnt(i) := io.update.valid && io.update.bits.misPred && i.U =/= updateIdx || io.repair
}
// bypass for if4_entry.specCnt
when (io.update.valid && !doingReset && valid && updateIdx === if4_idx) {
when (!tagMatch && io.update.bits.misPred || tagMatch) {
if4_entry.specCnt := wEntry.specCnt
swEntry.specCnt := wEntry.specCnt
}
}
when (io.repair && !doingReset && valid) {
if4_entry.specCnt := if4_entry.nSpecCnt
swEntry.specCnt := if4_entry.nSpecCnt
}
if (BPUDebug && debug) {
......
......@@ -32,12 +32,95 @@ class RAS extends BasePredictor
val branchInfo = Output(new RASBranchInfo)
}
def rasEntry() = new Bundle {
class RASEntry() extends XSBundle {
val retAddr = UInt(VAddrBits.W)
val ctr = UInt(8.W) // layer of nested call functions
}
def rasEntry() = new RASEntry
object RASEntry {
def apply(retAddr: UInt, ctr: UInt): RASEntry = {
val e = Wire(rasEntry())
e.retAddr := retAddr
e.ctr := ctr
e
}
}
override val io = IO(new RASIO)
class RASStack(val rasSize: Int) extends XSModule {
val io = IO(new Bundle {
val push_valid = Input(Bool())
val pop_valid = Input(Bool())
val new_addr = Input(UInt(VAddrBits.W))
val top_addr = Output(UInt(VAddrBits.W))
val is_empty = Output(Bool())
val is_full = Output(Bool())
val copy_valid = Input(Bool())
val copy_in_mem = Input(Vec(rasSize, rasEntry()))
val copy_in_sp = Input(UInt(log2Up(rasSize).W))
val copy_out_mem = Output(Vec(rasSize, rasEntry()))
val copy_out_sp = Output(UInt(log2Up(rasSize).W))
})
class Stack(val size: Int) extends XSModule {
val io = IO(new Bundle {
val rIdx = Input(UInt(log2Up(size).W))
val rdata = Output(rasEntry())
val wen = Input(Bool())
val wIdx = Input(UInt(log2Up(size).W))
val wdata = Input(rasEntry())
val copyen = Input(Bool())
val copy_in = Input(Vec(size, rasEntry()))
val copy_out = Output(Vec(size, rasEntry()))
})
val mem = Reg(Vec(size, rasEntry()))
when (io.wen) {
mem(io.wIdx) := io.wdata
}
io.rdata := mem(io.rIdx)
(0 until size).foreach { i => io.copy_out(i) := mem(i) }
when (io.copyen) {
(0 until size).foreach {i => mem(i) := io.copy_in(i) }
}
}
val sp = RegInit(0.U(log2Up(rasSize).W))
val stack = Module(new Stack(rasSize)).io
stack.rIdx := sp - 1.U
val top_entry = stack.rdata
val top_addr = top_entry.retAddr
val top_ctr = top_entry.ctr
val alloc_new = io.new_addr =/= top_addr
stack.wen := io.push_valid || io.pop_valid && top_ctr =/= 1.U
stack.wIdx := Mux(io.pop_valid && top_ctr =/= 1.U, sp - 1.U, Mux(alloc_new, sp, sp - 1.U))
stack.wdata := Mux(io.pop_valid && top_ctr =/= 1.U,
RASEntry(top_addr, top_ctr - 1.U),
Mux(alloc_new, RASEntry(io.new_addr, 1.U), RASEntry(top_addr, top_ctr + 1.U)))
when (io.push_valid && alloc_new) {
sp := sp + 1.U
}
when (io.pop_valid && top_ctr === 1.U) {
sp := Mux(sp === 0.U, 0.U, sp - 1.U)
}
io.copy_out_mem := stack.copy_out
io.copy_out_sp := sp
stack.copyen := io.copy_valid
stack.copy_in := io.copy_in_mem
when (io.copy_valid) {
sp := io.copy_in_sp
}
io.top_addr := top_addr
io.is_empty := sp === 0.U
io.is_full := sp === (RasSize - 1).U
}
// val ras_0 = Reg(Vec(RasSize, rasEntry())) //RegInit(0.U)asTypeOf(Vec(RasSize,rasEntry)) cause comb loop
// val ras_1 = Reg(Vec(RasSize, rasEntry()))
// val sp_0 = RegInit(0.U(log2Up(RasSize).W))
......@@ -48,121 +131,83 @@ class RAS extends BasePredictor
// val commit_ras = Mux(choose_bit, ras_0, ras_1)
// val commit_sp = Mux(choose_bit,sp_0,sp_1)
val spec_ras = Reg(Vec(RasSize, rasEntry()))
val spec_sp = RegInit(0.U(log2Up(RasSize).W))
val commit_ras = Reg(Vec(RasSize, rasEntry()))
val commit_sp = RegInit(0.U(log2Up(RasSize).W))
// val spec_ras = Reg(Vec(RasSize, rasEntry()))
// val spec_sp = RegInit(0.U(log2Up(RasSize).W))
// val commit_ras = Reg(Vec(RasSize, rasEntry()))
// val commit_sp = RegInit(0.U(log2Up(RasSize).W))
val spec_ras = Module(new RASStack(RasSize)).io
val spec_is_empty = spec_sp === 0.U
val spec_is_full = spec_sp === (RasSize - 1).U
val spec_push = WireInit(false.B)
val spec_pop = WireInit(false.B)
val spec_new_addr = WireInit(io.pc.bits + (io.callIdx.bits << 1.U) + Mux(io.isRVC,2.U,Mux(io.isLastHalfRVI, 2.U, 4.U)))
spec_ras.push_valid := spec_push
spec_ras.pop_valid := spec_pop
spec_ras.new_addr := spec_new_addr
val spec_is_empty = spec_ras.is_empty
val spec_is_full = spec_ras.is_full
val spec_top_addr = spec_ras.top_addr
spec_push := !spec_is_full && io.callIdx.valid && io.pc.valid
spec_pop := !spec_is_empty && io.is_ret && io.pc.valid
val commit_ras = Module(new RASStack(RasSize)).io
val commit_push = WireInit(false.B)
val commit_pop = WireInit(false.B)
val commit_new_addr = Mux(io.recover.bits.pd.isRVC,io.recover.bits.pc + 2.U,io.recover.bits.pc + 4.U)
commit_ras.push_valid := commit_push
commit_ras.pop_valid := commit_pop
commit_ras.new_addr := commit_new_addr
val commit_is_empty = commit_ras.is_empty
val commit_is_full = commit_ras.is_full
val commit_top_addr = commit_ras.top_addr
commit_push := !commit_is_full && io.recover.valid && io.recover.bits.pd.isCall
commit_pop := !commit_is_empty && io.recover.valid && io.recover.bits.pd.isRet
val spec_ras_top_entry = spec_ras(spec_sp-1.U)
val spec_ras_top_addr = spec_ras_top_entry.retAddr
val spec_ras_top_ctr = spec_ras_top_entry.ctr
//no need to pass the ras branchInfo
io.branchInfo.rasSp := DontCare
io.branchInfo.rasTopCtr := DontCare
io.branchInfo.rasToqAddr := DontCare
io.out.valid := !spec_is_empty && io.is_ret
io.out.bits.target := spec_top_addr
io.out.bits.specEmpty := spec_is_empty
// update spec RAS
// speculative update RAS
val spec_push = !spec_is_full && io.callIdx.valid && io.pc.valid
val spec_pop = !spec_is_empty && io.is_ret && io.pc.valid
val spec_new_addr = io.pc.bits + (io.callIdx.bits << 1.U) + Mux(io.isRVC,2.U,Mux(io.isLastHalfRVI, 2.U, 4.U))
val spec_ras_write = WireInit(0.U.asTypeOf(rasEntry()))
val sepc_alloc_new = spec_new_addr =/= spec_ras_top_addr
when (spec_push) {
//push
spec_ras_write.ctr := 1.U
spec_ras_write.retAddr := spec_new_addr
when(sepc_alloc_new){
spec_sp := spec_sp + 1.U
spec_ras(spec_sp) := spec_ras_write
}.otherwise{
spec_ras_top_ctr := spec_ras_top_ctr + 1.U
}
}
when (spec_pop) {
//pop
when (spec_ras_top_ctr === 1.U) {
spec_sp := Mux(spec_sp === 0.U, 0.U, spec_sp - 1.U)
}.otherwise {
spec_ras_top_ctr := spec_ras_top_ctr - 1.U
}
}
io.out.bits.target := spec_ras_top_addr
// TODO: back-up stack for ras
// use checkpoint to recover RAS
val commit_is_empty = commit_sp === 0.U
val commit_is_full = commit_sp === (RasSize - 1).U
val commit_ras_top_entry = commit_ras(commit_sp-1.U)
val commit_ras_top_addr = commit_ras_top_entry.retAddr
val commit_ras_top_ctr = commit_ras_top_entry.ctr
//update commit ras
val commit_push = !commit_is_full && io.recover.valid && io.recover.bits.pd.isCall
val commit_pop = !commit_is_empty && io.recover.valid && io.recover.bits.pd.isRet
val commit_new_addr = Mux(io.recover.bits.pd.isRVC,io.recover.bits.pc + 2.U,io.recover.bits.pc + 4.U)
val commit_ras_write = WireInit(0.U.asTypeOf(rasEntry()))
val commit_alloc_new = commit_new_addr =/= commit_ras_top_addr
when (commit_push) {
//push
commit_ras_write.ctr := 1.U
commit_ras_write.retAddr := commit_new_addr
when(commit_alloc_new){
commit_sp := commit_sp + 1.U
commit_ras(commit_sp) := commit_ras_write
}.otherwise{
commit_ras_top_ctr := commit_ras_top_ctr + 1.U
}
}
when (commit_pop) {
//pop
when (commit_ras_top_ctr === 1.U) {
commit_sp := Mux(commit_sp === 0.U, 0.U, commit_sp - 1.U)
}.otherwise {
commit_ras_top_ctr := commit_ras_top_ctr - 1.U
}
}
val copy_valid = io.recover.valid && io.recover.bits.isMisPred
val copy_next = RegNext(copy_valid)
when(copy_next)
{
for(i <- 0 until RasSize)
{
spec_ras(i) := commit_ras(i)
spec_sp := commit_sp
}
}
spec_ras.copy_valid := copy_next
spec_ras.copy_in_mem := commit_ras.copy_out_mem
spec_ras.copy_in_sp := commit_ras.copy_out_sp
commit_ras.copy_valid := DontCare
commit_ras.copy_in_mem := DontCare
commit_ras.copy_in_sp := DontCare
if (BPUDebug && debug) {
XSDebug("----------------RAS(spec)----------------\n")
XSDebug(" index addr ctr \n")
for(i <- 0 until RasSize){
XSDebug(" (%d) 0x%x %d",i.U,spec_ras(i).retAddr,spec_ras(i).ctr)
when(i.U === spec_sp){XSDebug(false,true.B," <----sp")}
XSDebug(false,true.B,"\n")
}
XSDebug("----------------RAS(commit)----------------\n")
XSDebug(" index addr ctr \n")
for(i <- 0 until RasSize){
XSDebug(" (%d) 0x%x %d",i.U,commit_ras(i).retAddr,commit_ras(i).ctr)
when(i.U === commit_sp){XSDebug(false,true.B," <----sp")}
XSDebug(false,true.B,"\n")
}
//no need to pass the ras branchInfo
io.branchInfo.rasSp := DontCare
io.branchInfo.rasTopCtr := DontCare
io.branchInfo.rasToqAddr := DontCare
XSDebug(spec_push, "(spec_ras)push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n",spec_ras_write.retAddr,spec_ras_write.ctr,sepc_alloc_new,spec_sp.asUInt)
XSDebug(spec_pop, "(spec_ras)pop outValid:%d outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
XSDebug(commit_push, "(commit_ras)push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n",commit_ras_write.retAddr,commit_ras_write.ctr,sepc_alloc_new,commit_sp.asUInt)
XSDebug(commit_pop, "(commit_ras)pop outValid:%d outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
XSDebug("copyValid:%d copyNext:%d \n",copy_valid,copy_next)
if (BPUDebug && debug) {
// XSDebug("----------------RAS(spec)----------------\n")
// XSDebug(" index addr ctr \n")
// for(i <- 0 until RasSize){
// XSDebug(" (%d) 0x%x %d",i.U,spec_ras(i).retAddr,spec_ras(i).ctr)
// when(i.U === spec_sp){XSDebug(false,true.B," <----sp")}
// XSDebug(false,true.B,"\n")
// }
// XSDebug("----------------RAS(commit)----------------\n")
// XSDebug(" index addr ctr \n")
// for(i <- 0 until RasSize){
// XSDebug(" (%d) 0x%x %d",i.U,commit_ras(i).retAddr,commit_ras(i).ctr)
// when(i.U === commit_sp){XSDebug(false,true.B," <----sp")}
// XSDebug(false,true.B,"\n")
// }
// XSDebug(spec_push, "(spec_ras)push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n",spec_ras_write.retAddr,spec_ras_write.ctr,sepc_alloc_new,spec_sp.asUInt)
// XSDebug(spec_pop, "(spec_ras)pop outValid:%d outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
// XSDebug(commit_push, "(commit_ras)push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n",commit_ras_write.retAddr,commit_ras_write.ctr,sepc_alloc_new,commit_sp.asUInt)
// XSDebug(commit_pop, "(commit_ras)pop outValid:%d outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
// XSDebug("copyValid:%d copyNext:%d \n",copy_valid,copy_next)
}
......
package xiangshan.frontend
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import scala.math.min
class SCReq extends TageReq
class SCResp(val ctrBits: Int = 6) extends TageBundle {
val ctr = Vec(2, SInt(ctrBits.W))
}
class SCUpdate(val ctrBits: Int = 6) extends TageBundle {
val pc = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(TageBanks).W)
val hist = UInt(HistoryLength.W)
val mask = Vec(TageBanks, Bool())
val oldCtr = SInt(ctrBits.W)
val tagePred = Bool()
val taken = Bool()
}
class SCTableIO extends TageBundle {
val req = Input(Valid(new SCReq))
val resp = Output(Vec(TageBanks, new SCResp))
val update = Input(new SCUpdate)
}
abstract class BaseSCTable(val r: Int = 1024, val cb: Int = 6, val h: Int = 0) extends TageModule {
val io = IO(new SCTableIO)
def getCenteredValue(ctr: SInt): SInt = (ctr << 1).asSInt + 1.S
}
class FakeSCTable extends BaseSCTable {
io.resp := 0.U.asTypeOf(Vec(TageBanks, new SCResp))
}
class SCTable(val nRows: Int, val ctrBits: Int, val histLen: Int) extends BaseSCTable(nRows, ctrBits, histLen) {
val table = List.fill(TageBanks) {
List.fill(2) {
Module(new SRAMTemplate(SInt(ctrBits.W), set=nRows, shouldReset=false, holdRead=true, singlePort=false))
}
}
def compute_folded_hist(hist: UInt, l: Int) = {
if (histLen > 0) {
val nChunks = (histLen + l - 1) / l
val hist_chunks = (0 until nChunks) map {i =>
hist(min((i+1)*l, histLen)-1, i*l)
}
hist_chunks.reduce(_^_)
}
else 0.U
}
def getIdx(hist: UInt, pc: UInt) = {
(compute_folded_hist(hist, log2Ceil(nRows)) ^ (pc >> 1.U))(log2Ceil(nRows)-1,0)
}
def ctrUpdate(ctr: SInt, cond: Bool): SInt = signedSatUpdate(ctr, ctrBits, cond)
val doing_reset = RegInit(true.B)
val reset_idx = RegInit(0.U(log2Ceil(nRows).W))
reset_idx := reset_idx + doing_reset
when (reset_idx === (nRows-1).U) { doing_reset := false.B }
val idx = getIdx(io.req.bits.hist, io.req.bits.pc)
val idxLatch = RegEnable(idx, enable=io.req.valid)
val table_r = WireInit(0.U.asTypeOf(Vec(TageBanks,Vec(2, SInt(ctrBits.W)))))
val baseBank = io.req.bits.pc(log2Up(TageBanks), 1)
val baseBankLatch = RegEnable(baseBank, enable=io.req.valid)
val bankIdxInOrder = VecInit((0 until TageBanks).map(b => (baseBankLatch +& b.U)(log2Up(TageBanks)-1, 0)))
val realMask = circularShiftLeft(io.req.bits.mask, TageBanks, baseBank)
val maskLatch = RegEnable(io.req.bits.mask, enable=io.req.valid)
val update_idx = getIdx(io.update.hist, io.update.pc - (io.update.fetchIdx << 1))
val update_wdata = ctrUpdate(io.update.oldCtr, io.update.taken)
for (b <- 0 until TageBanks) {
for (i <- 0 to 1) {
table(b)(i).reset := reset.asBool
table(b)(i).io.r.req.valid := io.req.valid && realMask(b)
table(b)(i).io.r.req.bits.setIdx := idx
table_r(b)(i) := table(b)(i).io.r.resp.data(0)
table(b)(i).io.w.req.valid := (io.update.mask(b) && i.U === io.update.tagePred.asUInt) || doing_reset
table(b)(i).io.w.req.bits.setIdx := Mux(doing_reset, reset_idx, update_idx)
table(b)(i).io.w.req.bits.data := Mux(doing_reset, 0.S, update_wdata)
}
}
(0 until TageBanks).map(b => {
io.resp(b).ctr := table_r(bankIdxInOrder(b))
})
if (BPUDebug && debug) {
val u = io.update
val b = PriorityEncoder(u.mask)
XSDebug(io.req.valid, p"scTableReq: pc=0x${io.req.bits.pc}%x, idx=${idx}%d, hist=${io.req.bits.hist}%x, baseBank=${baseBank}%d, mask=${io.req.bits.mask}%b, realMask=${realMask}%b\n")
for (i <- 0 until TageBanks) {
XSDebug(RegNext(io.req.valid), p"scTableResp[${i.U}]: idx=${idxLatch}%d, ctr:${io.resp(i).ctr}\n")
}
XSDebug(io.update.mask.reduce(_||_), p"update Table: pc:${u.pc}%x, fetchIdx:${u.fetchIdx}%d, hist:${u.hist}%x, bank:${b}%d, tageTaken:${u.tagePred}%d, taken:${u.taken}%d, oldCtr:${u.oldCtr}%d\n")
}
}
class SCThreshold(val ctrBits: Int = 5) extends TageBundle {
val ctr = UInt(ctrBits.W)
def satPos(ctr: UInt = this.ctr) = ctr === ((1.U << ctrBits) - 1.U)
def satNeg(ctr: UInt = this.ctr) = ctr === 0.U
def neutralVal = (1.U << (ctrBits - 1))
val thres = UInt(5.W)
def minThres = 5.U
def maxThres = 31.U
def update(cause: Bool): SCThreshold = {
val res = Wire(new SCThreshold(this.ctrBits))
val newCtr = satUpdate(this.ctr, this.ctrBits, cause)
val newThres = Mux(res.satPos(newCtr), this.thres + 1.U,
Mux(res.satNeg(newCtr), this.thres - 1.U,
this.thres))
res.thres := newThres
res.ctr := Mux(res.satPos(newCtr) || res.satNeg(newCtr), res.neutralVal, newCtr)
// XSDebug(true.B, p"scThres Update: cause${cause} newCtr ${newCtr} newThres ${newThres}\n")
res
}
}
object SCThreshold {
def apply(bits: Int) = {
val t = Wire(new SCThreshold(ctrBits=bits))
t.ctr := t.neutralVal
t.thres := t.minThres
t
}
}
\ No newline at end of file
......@@ -24,16 +24,21 @@ trait HasTageParameter extends HasXSParameter with HasBPUParameter{
val TageNTables = TableInfo.size
val UBitPeriod = 2048
val TageBanks = PredictWidth // FetchWidth
val TageCtrBits = 3
val SCHistLens = 0 :: TableInfo.map{ case (_,h,_) => h}.toList
val SCNTables = 6
val SCCtrBits = 6
val SCNRows = 1024
val SCTableInfo = Seq.fill(SCNTables)((SCNRows, SCCtrBits)) zip SCHistLens map {case ((n, cb), h) => (n, cb, h)}
val TotalBits = TableInfo.map {
case (s, h, t) => {
s * (1+t+3) * PredictWidth
s * (1+t+TageCtrBits) * PredictWidth
}
}.reduce(_+_)
}
abstract class TageBundle extends XSBundle with HasTageParameter
abstract class TageModule extends XSModule with HasTageParameter { val debug = false }
abstract class TageBundle extends XSBundle with HasTageParameter with PredictorUtils
abstract class TageModule extends XSModule with HasTageParameter with PredictorUtils { val debug = false }
......@@ -45,7 +50,7 @@ class TageReq extends TageBundle {
}
class TageResp extends TageBundle {
val ctr = UInt(3.W)
val ctr = UInt(TageCtrBits.W)
val u = UInt(2.W)
}
......@@ -57,7 +62,7 @@ class TageUpdate extends TageBundle {
val mask = Vec(TageBanks, Bool())
val taken = Vec(TageBanks, Bool())
val alloc = Vec(TageBanks, Bool())
val oldCtr = Vec(TageBanks, UInt(3.W))
val oldCtr = Vec(TageBanks, UInt(TageCtrBits.W))
// update u
val uMask = Vec(TageBanks, Bool())
val u = Vec(TageBanks, UInt(2.W))
......@@ -100,18 +105,7 @@ class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPerio
(idx, tag)
}
def inc_ctr(ctr: UInt, taken: Bool): UInt = {
Mux(!taken, Mux(ctr === 0.U, 0.U, ctr - 1.U),
Mux(ctr === 7.U, 7.U, ctr + 1.U))
}
// circular shifting
def circularShiftLeft(source: UInt, len: Int, shamt: UInt): UInt = {
val res = Wire(UInt(len.W))
val higher = source << shamt
val lower = source >> (len.U - shamt)
res := higher | lower
res
}
def inc_ctr(ctr: UInt, taken: Bool): UInt = satUpdate(ctr, TageCtrBits, taken)
val doing_reset = RegInit(true.B)
val reset_idx = RegInit(0.U(log2Ceil(nRows).W))
......@@ -121,10 +115,10 @@ class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPerio
class TageEntry() extends TageBundle {
val valid = Bool()
val tag = UInt(tagLen.W)
val ctr = UInt(3.W)
val ctr = UInt(TageCtrBits.W)
}
val tageEntrySz = 1 + tagLen + 3
val tageEntrySz = 1 + tagLen + TageCtrBits
// use real address to index
// val unhashed_idxes = VecInit((0 until TageBanks).map(b => ((io.req.bits.pc >> 1.U) + b.U) >> log2Up(TageBanks).U))
......@@ -156,15 +150,13 @@ class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPerio
(0 until TageBanks).map(
b => {
hi_us(b).reset := reset.asBool
lo_us(b).reset := reset.asBool
table(b).reset := reset.asBool
hi_us(b).io.r.req.valid := io.req.valid && realMask(b)
lo_us(b).io.r.req.valid := io.req.valid && realMask(b)
table(b).io.r.req.valid := io.req.valid && realMask(b)
lo_us(b).io.r.req.bits.setIdx := idx
hi_us(b).io.r.req.bits.setIdx := idx
table(b).io.r.req.bits.setIdx := idx
Seq(hi_us, lo_us, table).map(
t => {
t(b).reset := reset.asBool
t(b).io.r.req.valid := io.req.valid && realMask(b)
t(b).io.r.req.bits.setIdx := idx
}
)
hi_us_r(b) := hi_us(b).io.r.resp.data(0)
lo_us_r(b) := lo_us(b).io.r.resp.data(0)
......@@ -217,7 +209,7 @@ class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPerio
val wrbypass_tags = Reg(Vec(wrBypassEntries, UInt(tagLen.W)))
val wrbypass_idxs = Reg(Vec(wrBypassEntries, UInt(log2Ceil(nRows).W)))
val wrbypass_ctrs = Reg(Vec(wrBypassEntries, Vec(TageBanks, UInt(3.W))))
val wrbypass_ctrs = Reg(Vec(wrBypassEntries, Vec(TageBanks, UInt(TageCtrBits.W))))
val wrbypass_ctr_valids = Reg(Vec(wrBypassEntries, Vec(TageBanks, Bool())))
val wrbypass_enq_idx = RegInit(0.U(log2Ceil(wrBypassEntries).W))
......@@ -368,10 +360,27 @@ class Tage extends BaseTage {
}
}
val scTables = SCTableInfo.map {
case (nRows, ctrBits, histLen) => {
val t = if (EnableSC) Module(new SCTable(nRows/TageBanks, ctrBits, histLen)) else Module(new FakeSCTable)
val req = t.io.req
req.valid := io.pc.valid && !io.flush
req.bits.pc := io.pc.bits
req.bits.hist := io.hist
req.bits.mask := io.inMask
t
}
}
val scThreshold = RegInit(SCThreshold(5))
val useThreshold = WireInit(scThreshold.thres)
val updateThreshold = WireInit((useThreshold << 3) + 21.U)
// override val debug = true
// Keep the table responses to process in s3
val resps = VecInit(tables.map(t => RegEnable(t.io.resp, enable=io.s3Fire)))
val scResps = VecInit(scTables.map(t => RegEnable(t.io.resp, enable=io.s3Fire)))
// val flushLatch = RegNext(io.flush)
val s2_bim = RegEnable(io.bim, enable=io.pc.valid) // actually it is s2Fire
......@@ -387,24 +396,37 @@ class Tage extends BaseTage {
val updateValid = io.update.valid
val updateHist = io.update.bits.hist
val updateIsBr = u.pd.isBr
val updateMeta = u.brInfo.tageMeta
val updateMisPred = u.isMisPred && u.pd.isBr
val updateMisPred = u.isMisPred && updateIsBr
val updateMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(TageBanks, Bool()))))
val updateUMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(TageBanks, Bool()))))
val updateTaken = Wire(Vec(TageNTables, Vec(TageBanks, Bool())))
val updateAlloc = Wire(Vec(TageNTables, Vec(TageBanks, Bool())))
val updateOldCtr = Wire(Vec(TageNTables, Vec(TageBanks, UInt(3.W))))
val updateOldCtr = Wire(Vec(TageNTables, Vec(TageBanks, UInt(TageCtrBits.W))))
val updateU = Wire(Vec(TageNTables, Vec(TageBanks, UInt(2.W))))
updateTaken := DontCare
updateAlloc := DontCare
updateOldCtr := DontCare
updateU := DontCare
val scUpdateMask = WireInit(0.U.asTypeOf(Vec(SCNTables, Vec(TageBanks, Bool()))))
val scUpdateTagePred = Wire(Bool())
val scUpdateTaken = Wire(Bool())
val scUpdateOldCtrs = Wire(Vec(SCNTables, SInt(SCCtrBits.W)))
scUpdateTagePred := DontCare
scUpdateTaken := DontCare
scUpdateOldCtrs := DontCare
val updateSCMeta = u.brInfo.tageMeta.scMeta
val updateTageMisPred = updateMeta.taken =/= u.taken && updateIsBr
val updateBank = u.pc(log2Ceil(TageBanks), 1)
// access tag tables and output meta info
for (w <- 0 until TageBanks) {
val tageTaken = WireInit(false.B)
var altPred = s3_bim.ctrs(w)(1)
val finalAltPred = WireInit(s3_bim.ctrs(w)(1))
var provided = false.B
......@@ -416,6 +438,7 @@ class Tage extends BaseTage {
val ctr = resps(i)(w).bits.ctr
when (hit) {
io.resp.takens(w) := Mux(ctr === 3.U || ctr === 4.U, altPred, ctr(2)) // Use altpred on weak taken
tageTaken := Mux(ctr === 3.U || ctr === 4.U, altPred, ctr(2))
finalAltPred := altPred
}
provided = provided || hit // Once hit then provide
......@@ -428,6 +451,7 @@ class Tage extends BaseTage {
io.meta(w).altDiffers := finalAltPred =/= io.resp.takens(w)
io.meta(w).providerU := resps(provider)(w).bits.u
io.meta(w).providerCtr := resps(provider)(w).bits.ctr
io.meta(w).taken := tageTaken
// Create a mask fo tables which did not hit our query, and also contain useless entries
// and also uses a longer history than the provider
......@@ -441,10 +465,53 @@ class Tage extends BaseTage {
io.meta(w).allocate.valid := allocatableSlots =/= 0.U
io.meta(w).allocate.bits := allocEntry
val scMeta = io.meta(w).scMeta
scMeta := DontCare
val scTableSums = VecInit(
(0 to 1) map { i => {
// val providerCtr = resps(provider)(w).bits.ctr.zext()
// val pvdrCtrCentered = (((providerCtr - 4.S) << 1) + 1.S) << 3
// sum += pvdrCtrCentered
if (EnableSC) {
(0 until SCNTables) map { j =>
scTables(j).getCenteredValue(scResps(j)(w).ctr(i))
} reduce (_+_) // TODO: rewrite with adder tree
}
else 0.S
}
}
)
if (EnableSC) {
scMeta.tageTaken := tageTaken
scMeta.scUsed := provided
scMeta.scPred := tageTaken
scMeta.sumAbs := 0.U
when (provided) {
val providerCtr = resps(provider)(w).bits.ctr.zext()
val pvdrCtrCentered = ((((providerCtr - 4.S) << 1).asSInt + 1.S) << 3).asSInt
val totalSum = scTableSums(tageTaken.asUInt) + pvdrCtrCentered
val sumAbs = totalSum.abs().asUInt
val sumBelowThreshold = totalSum.abs.asUInt < useThreshold
val scPred = totalSum >= 0.S
scMeta.sumAbs := sumAbs
scMeta.ctrs := VecInit(scResps.map(r => r(w).ctr(tageTaken.asUInt)))
for (i <- 0 until SCNTables) {
XSDebug(RegNext(io.s3Fire), p"SCTable(${i.U})(${w.U}): ctr:(${scResps(i)(w).ctr(0)},${scResps(i)(w).ctr(1)})\n")
}
XSDebug(RegNext(io.s3Fire), p"SC(${w.U}): pvdCtr(${providerCtr}), pvdCentred(${pvdrCtrCentered}), totalSum(${totalSum}), abs(${sumAbs}) useThres(${useThreshold}), scPred(${scPred})\n")
// Use prediction from Statistical Corrector
when (!sumBelowThreshold) {
XSDebug(RegNext(io.s3Fire), p"SC(${w.U}) overriden pred to ${scPred}\n")
scMeta.scPred := scPred
io.resp.takens(w) := scPred
}
}
}
val isUpdateTaken = updateValid && updateBank === w.U &&
u.taken && u.pd.isBr
when (u.pd.isBr && updateValid && updateBank === w.U) {
u.taken && updateIsBr
when (updateIsBr && updateValid && updateBank === w.U) {
when (updateMeta.provider.valid) {
val provider = updateMeta.provider.bits
......@@ -462,7 +529,7 @@ class Tage extends BaseTage {
}
}
when (updateValid && updateMisPred) {
when (updateValid && updateTageMisPred) {
val idx = updateBank
val allocate = updateMeta.allocate
when (allocate.valid) {
......@@ -483,6 +550,28 @@ class Tage extends BaseTage {
}
}
if (EnableSC) {
when (updateValid && updateSCMeta.scUsed.asBool && updateIsBr) {
val scPred = updateSCMeta.scPred
val tageTaken = updateSCMeta.tageTaken
val sumAbs = updateSCMeta.sumAbs.asUInt
val scOldCtrs = updateSCMeta.ctrs
when (scPred =/= tageTaken && sumAbs < useThreshold - 2.U) {
val newThres = scThreshold.update(scPred =/= u.taken)
scThreshold := newThres
XSDebug(p"scThres update: old d${useThreshold} --> new ${newThres.thres}\n")
}
when (scPred =/= u.taken || sumAbs < updateThreshold) {
scUpdateMask.foreach(t => t(updateBank) := true.B)
scUpdateTagePred := tageTaken
scUpdateTaken := u.taken
(scUpdateOldCtrs zip scOldCtrs).foreach{case (t, c) => t := c}
XSDebug(p"scUpdate: bank(${updateBank}), scPred(${scPred}), tageTaken(${tageTaken}), scSumAbs(${sumAbs}), mispred: sc(${updateMisPred}), tage(${updateTageMisPred})\n")
XSDebug(p"update: sc: ${updateSCMeta}\n")
}
}
}
for (i <- 0 until TageNTables) {
for (w <- 0 until TageBanks) {
tables(i).io.update.mask(w) := updateMask(i)(w)
......@@ -499,6 +588,17 @@ class Tage extends BaseTage {
tables(i).io.update.fetchIdx := u.brInfo.fetchIdx
}
for (i <- 0 until SCNTables) {
scTables(i).io.update.mask := scUpdateMask(i)
scTables(i).io.update.tagePred := scUpdateTagePred
scTables(i).io.update.taken := scUpdateTaken
scTables(i).io.update.oldCtr := scUpdateOldCtrs(i)
scTables(i).io.update.pc := u.pc
scTables(i).io.update.hist := updateHist
scTables(i).io.update.fetchIdx := u.brInfo.fetchIdx
}
if (BPUDebug && debug) {
val m = updateMeta
......@@ -508,9 +608,11 @@ class Tage extends BaseTage {
XSDebug(RegNext(io.s3Fire), "s3FireOnLastCycle: resp: pc=%x, hist=%x, hits=%b, takens=%b\n",
debug_pc_s3, debug_hist_s3, io.resp.hits.asUInt, io.resp.takens.asUInt)
for (i <- 0 until TageNTables) {
XSDebug(RegNext(io.s3Fire), "Table(%d): valids:%b, resp_ctrs:%b, resp_us:%b\n", i.U, VecInit(resps(i).map(_.valid)).asUInt, Cat(resps(i).map(_.bits.ctr)), Cat(resps(i).map(_.bits.u)))
XSDebug(RegNext(io.s3Fire), "TageTable(%d): valids:%b, resp_ctrs:%b, resp_us:%b\n", i.U, VecInit(resps(i).map(_.valid)).asUInt, Cat(resps(i).map(_.bits.ctr)), Cat(resps(i).map(_.bits.u)))
}
XSDebug(io.update.valid, "update: pc=%x, fetchpc=%x, cycle=%d, hist=%x, taken:%d, misPred:%d, histPtr:%d, bimctr:%d, pvdr(%d):%d, altDiff:%d, pvdrU:%d, pvdrCtr:%d, alloc(%d):%d\n",
u.pc, u.pc - (bri.fetchIdx << 1.U), bri.debug_tage_cycle, updateHist, u.taken, u.isMisPred, bri.histPtr, bri.bimCtr, m.provider.valid, m.provider.bits, m.altDiffers, m.providerU, m.providerCtr, m.allocate.valid, m.allocate.bits)
XSDebug(io.update.valid && updateIsBr, p"update: sc: ${updateSCMeta}\n")
XSDebug(true.B, p"scThres: use(${useThreshold}), update(${updateThreshold})\n")
}
}
\ No newline at end of file
......@@ -46,14 +46,6 @@ class MicroBTB extends BasePredictor
def getTag(pc: UInt) = (pc >> (log2Ceil(PredictWidth) + 1)).asUInt()
def getBank(pc: UInt) = pc(log2Ceil(PredictWidth) ,1)
def satUpdate(old: UInt, len: Int, taken: Bool): UInt = {
val oldSatTaken = old === ((1 << len)-1).U
val oldSatNotTaken = old === 0.U
Mux(oldSatTaken && taken, ((1 << len)-1).U,
Mux(oldSatNotTaken && !taken, 0.U,
Mux(taken, old + 1.U, old - 1.U)))
}
class MicroBTBMeta extends XSBundle
{
......@@ -69,8 +61,93 @@ class MicroBTB extends BasePredictor
val offset = SInt(offsetSize.W)
}
val uBTBMeta = RegInit((0.U).asTypeOf(Vec(nWays, Vec(PredictWidth, new MicroBTBMeta))))
val uBTB = Reg(Vec(nWays, Vec(PredictWidth, new MicroBTBEntry)))
// val uBTBMeta = RegInit((0.U).asTypeOf(Vec(nWays, Vec(PredictWidth, new MicroBTBMeta))))
// val uBTB = Reg(Vec(nWays, Vec(PredictWidth, new MicroBTBEntry)))
// class UBTBMem[T <: Data](gen: T, nWays: Int) extends XSModule {
// class UBTBBundleR[T <: Data](private val gen: T, val way: Int) extends Bundle {
// val data = Output(Vec(way, gen))
// }
// class UBTBReadBus[T <: Data](private val gen: T, val way: Int) {
// val resp = Output(new UBTBBundleR(gen, way))
// }
// class UBTBWriteBus[T <: Data](private val gen: T, val set: Int, val way: Int) extends Bundle {
// val req =
// }
// val io = IO(new Bundle {
// val wen = Input(Bool())
// val wWay = Input(UInt(log2Up(nWays).W))
// val wRow = Input(UInt(log2Up(PredictWidth).W))
// val wdata = Input(new T)
// val entries = Output(Vec(nWays, Vec(PredictWidth, gen)))
// })
// val mem = RegInit((0.U).asTypeOf(Vec(nWays, Vec(PredictWidth, new T))))
// io.entries := mem
// when (io.wen) {
// mem(wWay)(wRow) := wdata
// }
// }
class MetaOutput extends XSBundle {
val is_Br = Bool()
val is_RVC = Bool()
val pred = UInt(2.W)
}
class UBTBMetaBank(nWays: Int) extends XSModule {
val io = IO(new Bundle {
val wen = Input(Bool())
val wWay = Input(UInt(log2Up(nWays).W))
val wdata = Input(new MicroBTBMeta)
val rtag = Input(UInt(tagSize.W))
val rdata = Output(new MetaOutput)
val hit_ohs = Output(Vec(nWays, Bool()))
val allocatable_way = Valid(UInt(log2Up(nWays).W))
val rWay = Input(UInt(log2Up(nWays).W))
val rpred = Output(UInt(2.W))
})
val mem = Mem(nWays, new MicroBTBMeta)
val rentries = VecInit((0 until nWays) map (i => mem(i)))
val hit_ohs = VecInit(rentries map (e => e.valid && e.tag === io.rtag))
val hit_way = PriorityEncoder(hit_ohs)
val hit_entry = rentries(hit_way)
io.hit_ohs := hit_ohs
io.rdata.is_Br := hit_entry.is_Br
io.rdata.is_RVC := hit_entry.is_RVC
io.rdata.pred := hit_entry.pred
val entry_emptys = VecInit(rentries.map(e => !e.valid))
val allocatable = ParallelOR(entry_emptys)
io.allocatable_way.bits := PriorityEncoder(entry_emptys)
io.allocatable_way.valid := allocatable
io.rpred := rentries(io.rWay).pred
when (io.wen) {
mem.write(io.wWay, io.wdata)
}
}
class UBTBDataBank(nWays: Int) extends XSModule {
val io = IO(new Bundle {
val wen = Input(Bool())
val wWay = Input(UInt(log2Up(nWays).W))
val wdata = Input(new MicroBTBEntry)
val rWay = Input(UInt(log2Up(nWays).W))
val rdata = Output(new MicroBTBEntry)
})
val mem = Mem(nWays, new MicroBTBEntry)
val rentries = VecInit((0 until nWays) map (i => mem(i)))
io.rdata := rentries(io.rWay)
when (io.wen) {
mem.write(io.wWay, io.wdata)
}
}
val metaBanks = Seq.fill(PredictWidth)(Module(new UBTBMetaBank(nWays)))
val dataBanks = Seq.fill(PredictWidth)(Module(new UBTBDataBank(nWays)))
val metas = VecInit(metaBanks.map(_.io))
val datas = VecInit(dataBanks.map(_.io))
val uBTBMeta = VecInit(metas.map(m => m.rdata))
val uBTB = VecInit(datas.map(d => d.rdata))
//uBTB read
//tag is bank align
......@@ -92,23 +169,23 @@ class MicroBTB extends BasePredictor
val read_bank_inOrder = VecInit((0 until PredictWidth).map(b => (read_req_basebank + b.U)(log2Up(PredictWidth)-1,0) ))
val isInNextRow = VecInit((0 until PredictWidth).map(_.U < read_req_basebank))
val read_hit_ohs = read_bank_inOrder.map{ b =>
VecInit((0 until nWays) map {w =>
Mux(isInNextRow(b),read_req_tag + 1.U,read_req_tag) === uBTBMeta(w)(b).tag
})
}
(0 until PredictWidth).map{ b => metas(b).rtag := Mux(isInNextRow(b),read_req_tag + 1.U,read_req_tag) }
val read_hit_ohs = read_bank_inOrder.map{ b => metas(b).hit_ohs }
val read_hit_vec = VecInit(read_hit_ohs.map{oh => ParallelOR(oh).asBool})
val read_hit_ways = VecInit(read_hit_ohs.map{oh => PriorityEncoder(oh)})
val read_hit = ParallelOR(read_hit_vec).asBool
val read_hit_way = PriorityEncoder(ParallelOR(read_hit_ohs.map(_.asUInt)))
// val read_hit = ParallelOR(read_hit_vec).asBool
// val read_hit_way = PriorityEncoder(ParallelOR(read_hit_ohs.map(_.asUInt)))
val uBTBMeta_resp = VecInit((0 until PredictWidth).map(b => uBTBMeta(read_hit_ways(b))(read_bank_inOrder(b))))
val btb_resp = VecInit((0 until PredictWidth).map(b => uBTB(read_hit_ways(b))(read_bank_inOrder(b))))
(0 until PredictWidth).map(b => datas(b).rWay := read_hit_ways(PredictWidth.U - read_bank_inOrder(b)))
val uBTBMeta_resp = VecInit((0 until PredictWidth).map(b => metas(read_bank_inOrder(b)).rdata))
val btb_resp = VecInit((0 until PredictWidth).map(b => datas(read_bank_inOrder(b)).rdata))
for(i <- 0 until PredictWidth){
// do not need to decide whether to produce results\
read_resp(i).valid := uBTBMeta_resp(i).valid && read_hit_vec(i) && io.inMask(i)
read_resp(i).valid := read_hit_vec(i) && io.inMask(i)
read_resp(i).taken := read_resp(i).valid && uBTBMeta_resp(i).pred(1)
read_resp(i).is_Br := read_resp(i).valid && uBTBMeta_resp(i).is_Br
read_resp(i).target := ((io.pc.bits).asSInt + (i<<1).S + btb_resp(i).offset).asUInt
......@@ -130,12 +207,16 @@ class MicroBTB extends BasePredictor
way := Mux(all_valid,chunks.reduce(_^_),PriorityEncoder(~valids))
way
}
val alloc_ways = read_bank_inOrder.map{ b =>
alloc_way(VecInit(uBTBMeta.map(w => w(b).valid)).asUInt,
VecInit(uBTBMeta.map(w => w(b).tag)).asUInt,
Mux(isInNextRow(b).asBool,read_req_tag + 1.U,read_req_tag))
// val alloc_ways = read_bank_inOrder.map{ b =>
// alloc_way(VecInit(uBTBMeta.map(w => w(b).valid)).asUInt,
// VecInit(uBTBMeta.map(w => w(b).tag)).asUInt,
// Mux(isInNextRow(b).asBool,read_req_tag + 1.U,read_req_tag))
}
// }
val alloc_ways = read_bank_inOrder.map{ b =>
Mux(metas(b).allocatable_way.valid, metas(b).allocatable_way.bits, LFSR64()(log2Ceil(nWays)-1,0))}
(0 until PredictWidth).map(i => out_ubtb_br_info.writeWay(i) := Mux(read_hit_vec(i).asBool,read_hit_ways(i),alloc_ways(i)))
//response
......@@ -172,41 +253,65 @@ class MicroBTB extends BasePredictor
val entry_write_valid = io.update.valid && (u.isMisPred || !u.isMisPred && u.pd.isBr || jalFirstEncountered)//io.update.valid //&& update_is_BR_or_JAL
val meta_write_valid = io.update.valid && (u.isMisPred || !u.isMisPred && u.pd.isBr || jalFirstEncountered)//io.update.valid //&& update_is_BR_or_JAL
//write btb target when miss prediction
when(entry_write_valid)
{
uBTB(update_write_way)(update_bank).offset := update_taget_offset
// when(entry_write_valid)
// {
// uBTB(update_write_way)(update_bank).offset := update_taget_offset
// }
for (b <- 0 until PredictWidth) {
datas(b).wen := entry_write_valid && b.U === update_bank
datas(b).wWay := update_write_way
datas(b).wdata := update_taget_offset.asTypeOf(new MicroBTBEntry)
}
//write the uBTBMeta
when(meta_write_valid)
{
//commit update
uBTBMeta(update_write_way)(update_bank).is_Br := u.pd.brType === BrType.branch
uBTBMeta(update_write_way)(update_bank).is_RVC := u.pd.isRVC
//(0 until PredictWidth).foreach{b => uBTBMeta(update_write_way)(b).valid := false.B}
uBTBMeta(update_write_way)(update_bank).valid := true.B
uBTBMeta(update_write_way)(update_bank).tag := update_tag
uBTBMeta(update_write_way)(update_bank).pred :=
Mux(!update_hits,
Mux(update_taken,3.U,0.U),
satUpdate( uBTBMeta(update_write_way)(update_bank).pred,2,update_taken)
)
(0 until PredictWidth).map(i => metas(i).rWay := update_write_way)
val update_write_meta = Wire(new MicroBTBMeta)
update_write_meta.is_Br := u.pd.brType === BrType.branch
update_write_meta.is_RVC := u.pd.isRVC
update_write_meta.valid := true.B
update_write_meta.tag := update_tag
update_write_meta.pred := Mux(!update_hits,
Mux(update_taken,3.U,0.U),
satUpdate( metas(update_bank).rpred,2,update_taken)
)
for (b <- 0 until PredictWidth) {
metas(b).wen := meta_write_valid && b.U === update_bank
metas(b).wWay := update_write_way
metas(b).wdata := update_write_meta
}
// when(meta_write_valid)
// {
// //commit update
// uBTBMeta(update_write_way)(update_bank).is_Br := u.pd.brType === BrType.branch
// uBTBMeta(update_write_way)(update_bank).is_RVC := u.pd.isRVC
// //(0 until PredictWidth).foreach{b => uBTBMeta(update_write_way)(b).valid := false.B}
// uBTBMeta(update_write_way)(update_bank).valid := true.B
// uBTBMeta(update_write_way)(update_bank).tag := update_tag
// uBTBMeta(update_write_way)(update_bank).pred :=
// Mux(!update_hits,
// Mux(update_taken,3.U,0.U),
// satUpdate( uBTBMeta(update_write_way)(update_bank).pred,2,update_taken)
// )
// }
if (BPUDebug && debug) {
XSDebug(read_valid,"uBTB read req: pc:0x%x, tag:%x basebank:%d\n",io.pc.bits,read_req_tag,read_req_basebank)
XSDebug(read_valid,"uBTB read resp: read_hit_vec:%b, \n",read_hit_vec.asUInt)
for(i <- 0 until PredictWidth) {
XSDebug(read_valid,"bank(%d) hit:%d way:%d valid:%d is_RVC:%d taken:%d isBr:%d target:0x%x alloc_way:%d\n",
i.U,read_hit_vec(i),read_hit_ways(i),read_resp(i).valid,read_resp(i).is_RVC,read_resp(i).taken,read_resp(i).is_Br,read_resp(i).target,out_ubtb_br_info.writeWay(i))
}
// XSDebug(read_valid,"uBTB read req: pc:0x%x, tag:%x basebank:%d\n",io.pc.bits,read_req_tag,read_req_basebank)
// XSDebug(read_valid,"uBTB read resp: read_hit_vec:%b, \n",read_hit_vec.asUInt)
// for(i <- 0 until PredictWidth) {
// XSDebug(read_valid,"bank(%d) hit:%d way:%d valid:%d is_RVC:%d taken:%d isBr:%d target:0x%x alloc_way:%d\n",
// i.U,read_hit_vec(i),read_hit_ways(i),read_resp(i).valid,read_resp(i).is_RVC,read_resp(i).taken,read_resp(i).is_Br,read_resp(i).target,out_ubtb_br_info.writeWay(i))
// }
XSDebug(meta_write_valid,"uBTB update: update | pc:0x%x | update hits:%b | | update_write_way:%d | update_bank: %d| update_br_index:%d | update_tag:%x | upadate_offset 0x%x\n "
,update_br_pc,update_hits,update_write_way,update_bank,update_br_idx,update_tag,update_taget_offset(offsetSize-1,0))
XSDebug(meta_write_valid, "uBTB update: update_taken:%d | old_pred:%b | new_pred:%b\n",
update_taken, uBTBMeta(update_write_way)(update_bank).pred,
Mux(!update_hits,
Mux(update_taken,3.U,0.U),
satUpdate( uBTBMeta(update_write_way)(update_bank).pred,2,update_taken)))
// XSDebug(meta_write_valid,"uBTB update: update | pc:0x%x | update hits:%b | | update_write_way:%d | update_bank: %d| update_br_index:%d | update_tag:%x | upadate_offset 0x%x\n "
// ,update_br_pc,update_hits,update_write_way,update_bank,update_br_idx,update_tag,update_taget_offset(offsetSize-1,0))
// XSDebug(meta_write_valid, "uBTB update: update_taken:%d | old_pred:%b | new_pred:%b\n",
// update_taken, uBTBMeta(update_write_way)(update_bank).pred,
// Mux(!update_hits,
// Mux(update_taken,3.U,0.U),
// satUpdate( uBTBMeta(update_write_way)(update_bank).pred,2,update_taken)))
}
......
......@@ -107,7 +107,7 @@ Emulator::Emulator(int argc, const char *argv[]):
enable_waveform = false;
#endif
#ifdef __ENABLESNAPSHOT__
#ifdef VM_SAVABLE
if (args.snapshot_path != NULL) {
printf("loading from snapshot `%s`...\n", args.snapshot_path);
snapshot_load(args.snapshot_path);
......@@ -122,7 +122,7 @@ Emulator::Emulator(int argc, const char *argv[]):
}
Emulator::~Emulator() {
#ifdef __ENABLESNAPSHOT__
#ifdef VM_SAVABLE
snapshot_slot[0].save();
snapshot_slot[1].save();
printf("Please remove unused snapshots manually\n");
......@@ -281,7 +281,7 @@ uint64_t Emulator::execute(uint64_t n) {
poll_event();
lasttime_poll = t;
}
#ifdef __ENABLESNAPSHOT__
#ifdef VM_SAVABLE
static int snapshot_count = 0;
if (trapCode != STATE_GOODTRAP && t - lasttime_snapshot > 1000 * SNAPSHOT_INTERVAL) {
// save snapshot every 10s
......@@ -314,7 +314,7 @@ inline char* Emulator::timestamp_filename(time_t t, char *buf) {
return buf + len;
}
#ifdef __ENABLESNAPSHOT__
#ifdef VM_SAVABLE
inline char* Emulator::snapshot_filename(time_t t) {
static char buf[1024];
char *p = timestamp_filename(t, buf);
......@@ -355,7 +355,7 @@ void Emulator::display_trapinfo() {
instrCnt, cycleCnt, ipc);
}
#ifdef __ENABLESNAPSHOT__
#ifdef VM_SAVABLE
void Emulator::snapshot_save(const char *filename) {
static int last_slot = 0;
VerilatedSaveMem &stream = snapshot_slot[last_slot];
......@@ -435,4 +435,4 @@ void Emulator::snapshot_load(const char *filename) {
if(fp)
fseek(fp, sdcard_offset, SEEK_SET);
}
#endif
\ No newline at end of file
#endif
......@@ -29,7 +29,9 @@ class Emulator {
VXSSimTop *dut_ptr;
VerilatedVcdC* tfp;
bool enable_waveform;
#ifdef VM_SAVABLE
VerilatedSaveMem snapshot_slot[2];
#endif
EmuArgs args;
enum {
......
#include "snapshot.h"
#ifdef VM_SAVABLE
void VerilatedSaveMem::flush() {
long flush_size = m_cp - m_bufp;
assert(buf_size - size > flush_size);
......@@ -19,3 +20,4 @@ void VerilatedSaveMem::save() {
size = 0;
printf("save snapshot to %s...\n", m_filename.c_str());
}
#endif
#ifndef SNAPSHOT_H
#define SNAPSHOT_H
#ifdef VM_SAVABLE
#include "VXSSimTop.h"
#include <verilated_save.h>
......@@ -28,3 +32,6 @@ public:
void flush();
void save();
};
#endif
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册