未验证 提交 2c87aa6f 编写于 作者: L ljw 提交者: GitHub

Merge pull request #510 from RISCVERS/ftq

Ftq: save pc and branch infos by fetch packet
......@@ -22,7 +22,7 @@ case class Parameters
object Parameters {
val dualCoreParameters = Parameters(socParameters = SoCParameters(NumCores = 2))
val simParameters = Parameters(envParameters = EnviromentParameters(FPGAPlatform = false)) // sim only, disable log
val debugParameters = Parameters(envParameters = simParameters.envParameters.copy(EnableDebug = true)) // open log
val debugParameters = Parameters(envParameters = simParameters.envParameters.copy(EnableDebug = true, EnablePerfDebug = true)) // open log
val simDualCoreParameters = Parameters(socParameters = SoCParameters(NumCores = 2), envParameters = EnviromentParameters(FPGAPlatform = true, DualCoreDifftest = true))
val debugDualCoreParameters = Parameters(socParameters = SoCParameters(NumCores = 2), envParameters = simParameters.envParameters.copy(EnableDebug = true))
......
......@@ -102,37 +102,23 @@ object XSWarn extends LogHelper(XSLogLevel.WARN)
object XSError extends LogHelper(XSLogLevel.ERROR)
object XSPerf {
def apply(perfName: String, perfCnt: UInt)(implicit name: String) = {
val reset = true
val print_per_cycle = false
val print_gap_bits = 15
def apply(perfName: String, perfCnt: UInt, acc: Boolean = false, intervalBits: Int = 15)(implicit name: String) = {
val counter = RegInit(0.U(64.W))
val next_counter = WireInit(0.U(64.W))
val logTimestamp = WireInit(0.U(64.W))
val enableDebug = Parameters.get.envParameters.EnableDebug
val logEnable = WireInit(false.B)
next_counter := counter + perfCnt
counter := next_counter
if (enableDebug) {
ExcitingUtils.addSink(logEnable, "DISPLAY_LOG_ENABLE")
if(!print_per_cycle) {
ExcitingUtils.addSink(logTimestamp, "logTimestamp")
next_counter := counter + perfCnt
when(logEnable && logTimestamp(print_gap_bits-1, 0) === 0.U) { // TODO: Need print when program exit?
if(reset) {
next_counter := perfCnt
XSLog(XSLogLevel.PERF)(true, true.B, p"$perfName, $counter\n")
}else{
XSLog(XSLogLevel.PERF)(true, true.B, p"$perfName, $next_counter\n")
}
}
counter := next_counter
}else{
when(logEnable) {
ExcitingUtils.addSink(logTimestamp, "logTimestamp")
val printCond =
if(intervalBits == 0) true.B
else (logTimestamp(intervalBits - 1, 0) === 0.U)
when(printCond) { // TODO: Need print when program exit?
if(acc) {
XSLog(XSLogLevel.PERF)(true, true.B, p"$perfName, $next_counter\n")
}else{
XSLog(XSLogLevel.PERF)(true, true.B, p"$perfName, $perfCnt\n")
}
}
......
......@@ -3,8 +3,6 @@ package xiangshan
import chisel3._
import chisel3.util._
import xiangshan.backend.SelImm
import xiangshan.backend.brq.BrqPtr
import xiangshan.backend.rename.FreeListPtr
import xiangshan.backend.roq.RoqPtr
import xiangshan.backend.decode.{ImmUnion, XDecode}
import xiangshan.mem.{LqPtr, SqPtr}
......@@ -13,10 +11,12 @@ import xiangshan.frontend.HasBPUParameter
import xiangshan.frontend.HasTageParameter
import xiangshan.frontend.HasIFUConst
import xiangshan.frontend.GlobalHistory
import xiangshan.frontend.RASEntry
import utils._
import scala.math.max
import Chisel.experimental.chiselName
import xiangshan.backend.ftq.FtqPtr
// Fetch FetchWidth x 32-bit insts from Icache
class FetchPacket extends XSBundle {
......@@ -25,18 +25,18 @@ class FetchPacket extends XSBundle {
val pdmask = UInt(PredictWidth.W)
// val pc = UInt(VAddrBits.W)
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pnpc = Vec(PredictWidth, UInt(VAddrBits.W))
val bpuMeta = Vec(PredictWidth, new BpuMeta)
val pd = Vec(PredictWidth, new PreDecodeInfo)
val ipf = Bool()
val acf = Bool()
val crossPageIPFFix = Bool()
val predTaken = Bool()
val pred_taken = UInt(PredictWidth.W)
val ftqPtr = new FtqPtr
}
class ValidUndirectioned[T <: Data](gen: T) extends Bundle {
val valid = Bool()
val bits = gen.cloneType.asInstanceOf[T]
override def cloneType = new ValidUndirectioned(gen).asInstanceOf[this.type]
}
......@@ -47,15 +47,18 @@ 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
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)
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)
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 {
......@@ -77,47 +80,32 @@ class BranchPrediction extends XSBundle with HasIFUConst {
val jalMask = UInt(PredictWidth.W)
val targets = Vec(PredictWidth, UInt(VAddrBits.W))
// marks the last 2 bytes of this fetch packet
// val endsAtTheEndOfFirstBank = Bool()
// val endsAtTheEndOfLastBank = Bool()
// half RVI could only start at the end of a packet
val hasHalfRVI = Bool()
def brNotTakens = (~takens & brMask)
// assumes that only one of the two conditions could be true
def lastHalfRVIMask = Cat(hasHalfRVI.asUInt, 0.U((PredictWidth-1).W))
def lastHalfRVIClearMask = ~lastHalfRVIMask
// is taken from half RVI
def lastHalfRVITaken = takens(PredictWidth-1) && hasHalfRVI
def lastHalfRVIIdx = (PredictWidth-1).U
// should not be used if not lastHalfRVITaken
def lastHalfRVITarget = targets(PredictWidth-1)
def realTakens = takens & lastHalfRVIClearMask
def realBrMask = brMask & lastHalfRVIClearMask
def realJalMask = jalMask & lastHalfRVIClearMask
def brNotTakens = (~takens & realBrMask)
def sawNotTakenBr = VecInit((0 until PredictWidth).map(i =>
(if (i == 0) false.B else ParallelORR(brNotTakens(i-1,0)))))
// def hasNotTakenBrs = (brNotTakens & LowerMaskFromLowest(realTakens)).orR
def unmaskedJmpIdx = ParallelPriorityEncoder(takens)
(if (i == 0) false.B else ParallelORR(brNotTakens(i - 1, 0)))))
// if not taken before the half RVI inst
def saveHalfRVI = hasHalfRVI && !(ParallelORR(takens(PredictWidth-2,0)))
def saveHalfRVI = hasHalfRVI && !(ParallelORR(takens(PredictWidth - 2, 0)))
// could get PredictWidth-1 when only the first bank is valid
def jmpIdx = ParallelPriorityEncoder(realTakens)
def jmpIdx = ParallelPriorityEncoder(takens)
// only used when taken
def target = {
val generator = new PriorityMuxGenerator[UInt]
generator.register(realTakens.asBools, targets, List.fill(PredictWidth)(None))
generator.register(takens.asBools, targets, List.fill(PredictWidth)(None))
generator()
}
def taken = ParallelORR(realTakens)
def takenOnBr = taken && ParallelPriorityMux(realTakens, realBrMask.asBools)
def hasNotTakenBrs = Mux(taken, ParallelPriorityMux(realTakens, sawNotTakenBr), ParallelORR(brNotTakens))
def taken = ParallelORR(takens)
def takenOnBr = taken && ParallelPriorityMux(takens, brMask.asBools)
def hasNotTakenBrs = Mux(taken, ParallelPriorityMux(takens, sawNotTakenBr), ParallelORR(brNotTakens))
}
class PredictorAnswer extends XSBundle {
......@@ -130,22 +118,12 @@ class BpuMeta extends XSBundle with HasBPUParameter {
val ubtbWriteWay = UInt(log2Up(UBtbWays).W)
val ubtbHits = Bool()
val btbWriteWay = UInt(log2Up(BtbWays).W)
val btbHitJal = Bool()
val bimCtr = UInt(2.W)
val tageMeta = new TageMeta
val rasSp = UInt(log2Up(RasSize).W)
val rasTopCtr = UInt(8.W)
val rasToqAddr = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(PredictWidth).W)
val specCnt = UInt(10.W)
// for global history
val predTaken = Bool()
val hist = new GlobalHistory
val predHist = new GlobalHistory
val sawNotTakenBranch = Bool()
val debug_ubtb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val debug_btb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val debug_btb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val debug_tage_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val predictor = if (BPUDebug) UInt(log2Up(4).W) else UInt(0.W) // Mark which component this prediction comes from {ubtb, btb, tage, loopPredictor}
......@@ -164,6 +142,7 @@ class BpuMeta extends XSBundle with HasBPUParameter {
// this.asUInt
// }
def size = 0.U.asTypeOf(this).getWidth
def fromUInt(x: UInt) = x.asTypeOf(this)
}
......@@ -177,19 +156,19 @@ class Predecode extends XSBundle with HasIFUConst {
class CfiUpdateInfo extends XSBundle with HasBPUParameter {
// from backend
val pc = UInt(VAddrBits.W)
val pnpc = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(PredictWidth).W)
// frontend -> backend -> frontend
val pd = new PreDecodeInfo
val bpuMeta = new BpuMeta
val rasSp = UInt(log2Up(RasSize).W)
val rasEntry = new RASEntry
val hist = new GlobalHistory
val predHist = new GlobalHistory
val specCnt = UInt(10.W)
// need pipeline update
val sawNotTakenBranch = Bool()
val predTaken = Bool()
val target = UInt(VAddrBits.W)
val brTarget = UInt(VAddrBits.W)
val taken = Bool()
val isMisPred = Bool()
val brTag = new BrqPtr
val isReplay = Bool()
}
// Dequeue DecodeWidth insts from Ibuffer
......@@ -198,15 +177,53 @@ class CtrlFlow extends XSBundle {
val pc = UInt(VAddrBits.W)
val exceptionVec = ExceptionVec()
val intrVec = Vec(12, Bool())
val brUpdate = new CfiUpdateInfo
val pd = new PreDecodeInfo
val pred_taken = Bool()
val crossPageIPFFix = Bool()
val ftqPtr = new FtqPtr
val ftqOffset = UInt(log2Up(PredictWidth).W)
}
class FtqEntry extends XSBundle {
// fetch pc, pc of each inst could be generated by concatenation
val ftqPC = UInt((VAddrBits.W))
val hasLastPrev = Bool()
// prediction metas
val hist = new GlobalHistory
val predHist = new GlobalHistory
val rasSp = UInt(log2Ceil(RasSize).W)
val rasTop = new RASEntry()
val specCnt = Vec(PredictWidth, UInt(10.W))
val metas = Vec(PredictWidth, new BpuMeta)
val cfiIsCall, cfiIsRet, cfiIsRVC = Bool()
val rvc_mask = Vec(PredictWidth, Bool())
val br_mask = Vec(PredictWidth, Bool())
val cfiIndex = ValidUndirectioned(UInt(log2Up(PredictWidth).W))
val valids = Vec(PredictWidth, Bool())
// backend update
val mispred = Vec(PredictWidth, Bool())
val target = UInt(VAddrBits.W)
def takens = VecInit((0 until PredictWidth).map(i => cfiIndex.valid && cfiIndex.bits === i.U))
override def toPrintable: Printable = {
p"ftqPC: ${Hexadecimal(ftqPC)} hasLastPrec:$hasLastPrev " +
p"rasSp:$rasSp specCnt:$specCnt brmask:${Binary(Cat(br_mask))} rvcmask:${Binary(Cat(rvc_mask))} " +
p"valids:${Binary(valids.asUInt())} cfi valid: ${cfiIndex.valid} " +
p"cfi index: ${cfiIndex.bits} isCall:$cfiIsCall isRet:$cfiIsRet isRvc:$cfiIsRVC " +
p"mispred:${Binary(Cat(mispred))} target:${Hexadecimal(target)}\n"
}
}
class FPUCtrlSignals extends XSBundle {
val isAddSub = Bool() // swap23
val typeTagIn = UInt(2.W)
val typeTagOut = UInt(2.W)
val typeTagIn = UInt(2.W)
val typeTagOut = UInt(2.W)
val fromInt = Bool()
val wflags = Bool()
val fpWen = Bool()
......@@ -229,9 +246,9 @@ class CtrlSignals extends XSBundle {
val rfWen = Bool()
val fpWen = Bool()
val isXSTrap = Bool()
val noSpecExec = Bool() // wait forward
val blockBackward = Bool() // block backward
val flushPipe = Bool() // This inst will flush all the pipe when commit, like exception but can commit
val noSpecExec = Bool() // wait forward
val blockBackward = Bool() // block backward
val flushPipe = Bool() // This inst will flush all the pipe when commit, like exception but can commit
val isRVF = Bool()
val selImm = SelImm()
val imm = UInt(ImmUnion.maxLen.W)
......@@ -241,9 +258,9 @@ class CtrlSignals extends XSBundle {
def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
val decoder = freechips.rocketchip.rocket.DecodeLogic(inst, XDecode.decodeDefault, table)
val signals =
Seq(src1Type, src2Type, src3Type, fuType, fuOpType, rfWen, fpWen,
isXSTrap, noSpecExec, blockBackward, flushPipe, isRVF, selImm)
signals zip decoder map { case(s, d) => s := d }
Seq(src1Type, src2Type, src3Type, fuType, fuOpType, rfWen, fpWen,
isXSTrap, noSpecExec, blockBackward, flushPipe, isRVF, selImm)
signals zip decoder map { case (s, d) => s := d }
commitType := DontCare
this
}
......@@ -252,7 +269,6 @@ class CtrlSignals extends XSBundle {
class CfCtrl extends XSBundle {
val cf = new CtrlFlow
val ctrl = new CtrlSignals
val brTag = new BrqPtr
}
class PerfDebugInfo extends XSBundle {
......@@ -283,15 +299,16 @@ class MicroOp extends CfCtrl {
class Redirect extends XSBundle {
val roqIdx = new RoqPtr
val ftqIdx = new FtqPtr
val ftqOffset = UInt(log2Up(PredictWidth).W)
val level = RedirectLevel()
val interrupt = Bool()
val pc = UInt(VAddrBits.W)
val target = UInt(VAddrBits.W)
val brTag = new BrqPtr
val cfiUpdate = new CfiUpdateInfo
def isUnconditional() = RedirectLevel.isUnconditional(level)
// def isUnconditional() = RedirectLevel.isUnconditional(level)
def flushItself() = RedirectLevel.flushItself(level)
def isException() = RedirectLevel.isException(level)
// def isException() = RedirectLevel.isException(level)
}
class Dp1ToDp2IO extends XSBundle {
......@@ -307,23 +324,22 @@ class ReplayPregReq extends XSBundle {
val preg = UInt(PhyRegIdxWidth.W)
}
class DebugBundle extends XSBundle{
class DebugBundle extends XSBundle {
val isMMIO = Bool()
val isPerfCnt = Bool()
}
class ExuInput extends XSBundle {
val uop = new MicroOp
val src1, src2, src3 = UInt((XLEN+1).W)
val src1, src2, src3 = UInt((XLEN + 1).W)
}
class ExuOutput extends XSBundle {
val uop = new MicroOp
val data = UInt((XLEN+1).W)
val fflags = UInt(5.W)
val data = UInt((XLEN + 1).W)
val fflags = UInt(5.W)
val redirectValid = Bool()
val redirect = new Redirect
val brUpdate = new CfiUpdateInfo
val debug = new DebugBundle
}
......@@ -350,6 +366,8 @@ class RoqCommitInfo extends XSBundle {
val commitType = CommitType()
val pdest = UInt(PhyRegIdxWidth.W)
val old_pdest = UInt(PhyRegIdxWidth.W)
val ftqIdx = new FtqPtr
val ftqOffset = UInt(log2Up(PredictWidth).W)
// these should be optimized for synthesis verilog
val pc = UInt(VAddrBits.W)
......@@ -361,6 +379,7 @@ class RoqCommitIO extends XSBundle {
val info = Vec(CommitWidth, Output(new RoqCommitInfo))
def hasWalkInstr = isWalk && valid.asUInt.orR
def hasCommitInstr = !isWalk && valid.asUInt.orR
}
......@@ -372,17 +391,19 @@ class TlbFeedback extends XSBundle {
class FrontendToBackendIO extends XSBundle {
// to backend end
val cfVec = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
val fetchInfo = DecoupledIO(new FtqEntry)
// from backend
val redirect = Flipped(ValidIO(UInt(VAddrBits.W)))
// val cfiUpdateInfo = Flipped(ValidIO(new CfiUpdateInfo))
val cfiUpdateInfo = Flipped(ValidIO(new CfiUpdateInfo))
val redirect_cfiUpdate = Flipped(ValidIO(new Redirect))
val commit_cfiUpdate = Flipped(ValidIO(new FtqEntry))
val ftqEnqPtr = Input(new FtqPtr)
val ftqLeftOne = Input(Bool())
}
class TlbCsrBundle extends XSBundle {
val satp = new Bundle {
val mode = UInt(4.W) // TODO: may change number to parameter
val asid = UInt(16.W)
val ppn = UInt(44.W) // just use PAddrBits - 3 - vpnnLen
val ppn = UInt(44.W) // just use PAddrBits - 3 - vpnnLen
}
val priv = new Bundle {
val mxr = Bool()
......@@ -392,8 +413,8 @@ class TlbCsrBundle extends XSBundle {
}
override def toPrintable: Printable = {
p"Satp mode:0x${Hexadecimal(satp.mode)} asid:0x${Hexadecimal(satp.asid)} ppn:0x${Hexadecimal(satp.ppn)} " +
p"Priv mxr:${priv.mxr} sum:${priv.sum} imode:${priv.imode} dmode:${priv.dmode}"
p"Satp mode:0x${Hexadecimal(satp.mode)} asid:0x${Hexadecimal(satp.asid)} ppn:0x${Hexadecimal(satp.ppn)} " +
p"Priv mxr:${priv.mxr} sum:${priv.sum} imode:${priv.imode} dmode:${priv.dmode}"
}
}
......
......@@ -48,8 +48,10 @@ case class XSCoreParameters
EnableBPD: Boolean = true,
EnableRAS: Boolean = true,
EnableLB: Boolean = false,
EnableLoop: Boolean = true,
EnableLoop: Boolean = false,
EnableSC: Boolean = false,
EnableJal: Boolean = false,
EnableUBTB: Boolean = true,
HistoryLength: Int = 64,
BtbSize: Int = 2048,
JbtacSize: Int = 1024,
......@@ -65,6 +67,7 @@ case class XSCoreParameters
RenameWidth: Int = 6,
CommitWidth: Int = 6,
BrqSize: Int = 32,
FtqSize: Int = 48,
IssQueSize: Int = 12,
NRPhyRegs: Int = 160,
NRIntReadPorts: Int = 14,
......@@ -156,6 +159,7 @@ trait HasXSParameter {
val RenameWidth = core.RenameWidth
val CommitWidth = core.CommitWidth
val BrqSize = core.BrqSize
val FtqSize = core.FtqSize
val IssQueSize = core.IssQueSize
val BrTagWidth = log2Up(BrqSize)
val NRPhyRegs = core.NRPhyRegs
......@@ -184,6 +188,9 @@ trait HasXSParameter {
val NumPerfCounters = core.NumPerfCounters
val NrExtIntr = core.NrExtIntr
val instBytes = if (HasCExtension) 2 else 4
val instOffsetBits = log2Ceil(instBytes)
val icacheParameters = ICacheParameters(
tagECC = Some("parity"),
dataECC = Some("parity"),
......@@ -456,8 +463,8 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer)
integerBlock.io.csrio.fflags <> ctrlBlock.io.roqio.toCSR.fflags
integerBlock.io.csrio.dirty_fs <> ctrlBlock.io.roqio.toCSR.dirty_fs
integerBlock.io.csrio.exception <> ctrlBlock.io.roqio.exception
integerBlock.io.csrio.isInterrupt <> ctrlBlock.io.roqio.isInterrupt
integerBlock.io.csrio.trapTarget <> ctrlBlock.io.roqio.toCSR.trapTarget
integerBlock.io.csrio.isXRet <> ctrlBlock.io.roqio.toCSR.isXRet
integerBlock.io.csrio.interrupt <> ctrlBlock.io.roqio.toCSR.intrBitSet
integerBlock.io.csrio.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
integerBlock.io.csrio.externalInterrupt <> io.externalInterrupt
......@@ -469,9 +476,9 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer)
floatBlock.io.frm <> integerBlock.io.csrio.frm
memBlock.io.lsqio.roq <> ctrlBlock.io.roqio.lsq
memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.roqio.exception.bits.lqIdx
memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.roqio.exception.bits.sqIdx
memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.roqio.exception.bits.ctrl.commitType)
memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.roqio.exception.bits.uop.lqIdx
memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.roqio.exception.bits.uop.sqIdx
memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.roqio.exception.bits.uop.ctrl.commitType)
ptw.io.tlb(0) <> memBlock.io.ptw
ptw.io.tlb(1) <> frontend.io.ptw
......
......@@ -4,23 +4,25 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.backend.decode.DecodeStage
import xiangshan.backend.decode.{DecodeStage, ImmUnion}
import xiangshan.backend.rename.{BusyTable, Rename}
import xiangshan.backend.brq.{Brq, BrqPcRead}
import xiangshan.backend.dispatch.Dispatch
import xiangshan.backend.exu._
import xiangshan.backend.exu.Exu.exuConfigs
import xiangshan.backend.ftq.{Ftq, FtqRead, GetPcByFtq}
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.roq.{Roq, RoqCSRIO, RoqLsqIO, RoqPtr}
import xiangshan.backend.roq.{Roq, RoqCSRIO, RoqLsqIO, RoqPtr, RoqExceptionInfo}
import xiangshan.mem.LsqEnqIO
class CtrlToIntBlockIO extends XSBundle {
val enqIqCtrl = Vec(exuParameters.IntExuCnt, DecoupledIO(new MicroOp))
val readRf = Vec(NRIntReadPorts, Output(UInt(PhyRegIdxWidth.W)))
val jumpPc = Output(UInt(VAddrBits.W))
val jalr_target = Output(UInt(VAddrBits.W))
// int block only uses port 0~7
val readPortIndex = Vec(exuParameters.IntExuCnt, Output(UInt(log2Ceil(8 / 2).W))) // TODO parameterize 8 here
val redirect = ValidIO(new Redirect)
val flush = Output(Bool())
}
class CtrlToFpBlockIO extends XSBundle {
......@@ -29,12 +31,134 @@ class CtrlToFpBlockIO extends XSBundle {
// fp block uses port 0~11
val readPortIndex = Vec(exuParameters.FpExuCnt, Output(UInt(log2Ceil((NRFpReadPorts - exuParameters.StuCnt) / 3).W)))
val redirect = ValidIO(new Redirect)
val flush = Output(Bool())
}
class CtrlToLsBlockIO extends XSBundle {
val enqIqCtrl = Vec(exuParameters.LsExuCnt, DecoupledIO(new MicroOp))
val enqLsq = Flipped(new LsqEnqIO)
val redirect = ValidIO(new Redirect)
val flush = Output(Bool())
}
class RedirectGenerator extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new Bundle() {
val loadRelay = Flipped(ValidIO(new Redirect))
val exuMispredict = Vec(exuParameters.JmpCnt + exuParameters.AluCnt, Flipped(ValidIO(new ExuOutput)))
val flush = Input(Bool())
val stage2FtqRead = new FtqRead
val stage2Redirect = ValidIO(new Redirect)
val stage3Redirect = ValidIO(new Redirect)
})
/*
LoadQueue Jump ALU0 ALU1 ALU2 ALU3 exception Stage1
| | | | | | |
|============= reg & compare =====| | ========
| |
| |
| | Stage2
| |
redirect (flush backend) |
| |
=== reg === | ========
| |
|----- mux (exception first) -----| Stage3
|
redirect (send to frontend)
*/
def selectOlderRedirect(x: Valid[Redirect], y: Valid[Redirect]): Valid[Redirect] = {
Mux(x.valid,
Mux(y.valid,
Mux(isAfter(x.bits.roqIdx, y.bits.roqIdx), y, x),
x
),
y
)
}
def selectOlderExuOutWithFlag(x: Valid[ExuOutput], y: Valid[ExuOutput]): (Valid[ExuOutput], Bool) = {
val yIsOlder = Mux(x.valid,
Mux(y.valid,
Mux(isAfter(x.bits.redirect.roqIdx, y.bits.redirect.roqIdx), true.B, false.B),
false.B
),
true.B
)
val sel = Mux(yIsOlder, y, x)
(sel, yIsOlder)
}
def selectOlderExuOut(x: Valid[ExuOutput], y: Valid[ExuOutput]): Valid[ExuOutput] = {
selectOlderExuOutWithFlag(x, y)._1
}
val jumpOut = io.exuMispredict.head
val oldestAluOut = ParallelOperation(io.exuMispredict.tail, selectOlderExuOut)
val (oldestExuOut, jumpIsOlder) = selectOlderExuOutWithFlag(oldestAluOut, jumpOut) // select between jump and alu
val oldestMispredict = selectOlderRedirect(io.loadRelay, {
val redirect = Wire(Valid(new Redirect))
redirect.valid := oldestExuOut.valid
redirect.bits := oldestExuOut.bits.redirect
redirect
})
XSDebug(oldestExuOut.valid, p"exuMispredict: ${Binary(Cat(io.exuMispredict.map(_.valid)))}\n")
val s1_isJump = RegNext(jumpIsOlder, init = false.B)
val s1_jumpTarget = RegEnable(jumpOut.bits.redirect.cfiUpdate.target, jumpOut.valid)
val s1_imm12_reg = RegEnable(oldestExuOut.bits.uop.ctrl.imm(11, 0), oldestExuOut.valid)
val s1_pd = RegEnable(oldestExuOut.bits.uop.cf.pd, oldestExuOut.valid)
val s1_redirect_bits_reg = Reg(new Redirect)
val s1_redirect_valid_reg = RegInit(false.B)
// stage1 -> stage2
when(oldestMispredict.valid && !oldestMispredict.bits.roqIdx.needFlush(io.stage2Redirect, io.flush)){
s1_redirect_bits_reg := oldestMispredict.bits
s1_redirect_valid_reg := true.B
}.otherwise({
s1_redirect_valid_reg := false.B
})
io.stage2Redirect.valid := s1_redirect_valid_reg
io.stage2Redirect.bits := s1_redirect_bits_reg
io.stage2Redirect.bits.cfiUpdate := DontCare
// at stage2, we read ftq to get pc
io.stage2FtqRead.ptr := s1_redirect_bits_reg.ftqIdx
// stage3, calculate redirect target
val s2_isJump = RegNext(s1_isJump)
val s2_jumpTarget = RegEnable(s1_jumpTarget, s1_redirect_valid_reg)
val s2_imm12_reg = RegEnable(s1_imm12_reg, s1_redirect_valid_reg)
val s2_pd = RegEnable(s1_pd, s1_redirect_valid_reg)
val s2_redirect_bits_reg = RegEnable(s1_redirect_bits_reg, enable = s1_redirect_valid_reg)
val s2_redirect_valid_reg = RegNext(s1_redirect_valid_reg && !io.flush, init = false.B)
val ftqRead = io.stage2FtqRead.entry
val pc = GetPcByFtq(ftqRead.ftqPC, s2_redirect_bits_reg.ftqOffset, ftqRead.hasLastPrev)
val brTarget = pc + SignExt(ImmUnion.B.toImm32(s2_imm12_reg), XLEN)
val snpc = pc + Mux(s2_pd.isRVC, 2.U, 4.U)
val isReplay = RedirectLevel.flushItself(s2_redirect_bits_reg.level)
val target = Mux(isReplay,
pc, // repaly from itself
Mux(s2_redirect_bits_reg.cfiUpdate.taken,
Mux(s2_isJump, s2_jumpTarget, brTarget),
snpc
)
)
io.stage3Redirect.valid := s2_redirect_valid_reg
io.stage3Redirect.bits := s2_redirect_bits_reg
val stage3CfiUpdate = io.stage3Redirect.bits.cfiUpdate
stage3CfiUpdate.pc := pc
stage3CfiUpdate.pd := s2_pd
stage3CfiUpdate.rasSp := ftqRead.rasSp
stage3CfiUpdate.rasEntry := ftqRead.rasTop
stage3CfiUpdate.hist := ftqRead.hist
stage3CfiUpdate.predHist := ftqRead.predHist
stage3CfiUpdate.specCnt := ftqRead.specCnt(s2_redirect_bits_reg.ftqOffset)
stage3CfiUpdate.predTaken := s2_redirect_bits_reg.cfiUpdate.predTaken
stage3CfiUpdate.sawNotTakenBranch := VecInit((0 until PredictWidth).map{ i =>
if(i == 0) false.B else Cat(ftqRead.br_mask.take(i)).orR()
})(s2_redirect_bits_reg.ftqOffset)
stage3CfiUpdate.target := target
stage3CfiUpdate.taken := s2_redirect_bits_reg.cfiUpdate.taken
stage3CfiUpdate.isMisPred := s2_redirect_bits_reg.cfiUpdate.isMisPred
}
class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
......@@ -49,8 +173,7 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
val roqio = new Bundle {
// to int block
val toCSR = new RoqCSRIO
val exception = ValidIO(new MicroOp)
val isInterrupt = Output(Bool())
val exception = ValidIO(new RoqExceptionInfo)
// to mem block
val lsq = new RoqLsqIO
}
......@@ -72,57 +195,92 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
})
difftestIO <> DontCare
val ftq = Module(new Ftq)
val trapIO = IO(new TrapIO())
trapIO <> DontCare
val decode = Module(new DecodeStage)
val brq = Module(new Brq)
val rename = Module(new Rename)
val dispatch = Module(new Dispatch)
val intBusyTable = Module(new BusyTable(NRIntReadPorts, NRIntWritePorts))
val fpBusyTable = Module(new BusyTable(NRFpReadPorts, NRFpWritePorts))
val redirectGen = Module(new RedirectGenerator)
val roqWbSize = NRIntWritePorts + NRFpWritePorts + exuParameters.StuCnt + 1
val roqWbSize = NRIntWritePorts + NRFpWritePorts + exuParameters.StuCnt
val roq = Module(new Roq(roqWbSize))
// When replay and mis-prediction have the same roqIdx,
// mis-prediction should have higher priority, since mis-prediction flushes the load instruction.
// Thus, only when mis-prediction roqIdx is after replay roqIdx, replay should be valid.
val brqIsAfterLsq = isAfter(brq.io.redirectOut.bits.roqIdx, io.fromLsBlock.replay.bits.roqIdx)
val redirectArb = Mux(io.fromLsBlock.replay.valid && (!brq.io.redirectOut.valid || brqIsAfterLsq),
io.fromLsBlock.replay.bits, brq.io.redirectOut.bits)
val redirectValid = roq.io.redirectOut.valid || brq.io.redirectOut.valid || io.fromLsBlock.replay.valid
val redirect = Mux(roq.io.redirectOut.valid, roq.io.redirectOut.bits, redirectArb)
val backendRedirect = redirectGen.io.stage2Redirect
val frontendRedirect = redirectGen.io.stage3Redirect
val flush = roq.io.flushOut.valid
io.frontend.redirect.valid := RegNext(redirectValid)
io.frontend.redirect.bits := RegNext(Mux(roq.io.redirectOut.valid, roq.io.redirectOut.bits.target, redirectArb.target))
io.frontend.cfiUpdateInfo <> brq.io.cfiInfo
redirectGen.io.exuMispredict.zip(io.fromIntBlock.exuRedirect).map({case (x, y) =>
x.valid := y.valid && y.bits.redirect.cfiUpdate.isMisPred
x.bits := y.bits
})
redirectGen.io.loadRelay := io.fromLsBlock.replay
redirectGen.io.flush := flush
ftq.io.enq <> io.frontend.fetchInfo
for(i <- 0 until CommitWidth){
ftq.io.roq_commits(i).valid := roq.io.commits.valid(i) && !roq.io.commits.isWalk
ftq.io.roq_commits(i).bits := roq.io.commits.info(i)
}
ftq.io.redirect <> backendRedirect
ftq.io.flush := flush
ftq.io.flushIdx := roq.io.flushOut.bits.ftqIdx
ftq.io.flushOffset := roq.io.flushOut.bits.ftqOffset
ftq.io.frontendRedirect <> frontendRedirect
ftq.io.exuWriteback <> io.fromIntBlock.exuRedirect
ftq.io.ftqRead(1) <> redirectGen.io.stage2FtqRead
ftq.io.ftqRead(2).ptr := roq.io.flushOut.bits.ftqIdx
val flushPC = GetPcByFtq(
ftq.io.ftqRead(2).entry.ftqPC,
RegEnable(roq.io.flushOut.bits.ftqOffset, roq.io.flushOut.valid),
ftq.io.ftqRead(2).entry.hasLastPrev
)
val flushRedirect = Wire(Valid(new Redirect))
flushRedirect.valid := RegNext(flush)
flushRedirect.bits := DontCare
flushRedirect.bits.ftqIdx := RegEnable(roq.io.flushOut.bits.ftqIdx, flush)
flushRedirect.bits.interrupt := true.B
flushRedirect.bits.cfiUpdate.target := Mux(io.roqio.toCSR.isXRet || roq.io.exception.valid,
io.roqio.toCSR.trapTarget,
flushPC + 4.U // flush pipe
)
io.frontend.redirect_cfiUpdate := Mux(flushRedirect.valid, flushRedirect, frontendRedirect)
io.frontend.commit_cfiUpdate := ftq.io.commit_ftqEntry
io.frontend.ftqEnqPtr := ftq.io.enqPtr
io.frontend.ftqLeftOne := ftq.io.leftOne
decode.io.in <> io.frontend.cfVec
decode.io.enqBrq <> brq.io.enq
brq.io.redirect.valid <> redirectValid
brq.io.redirect.bits <> redirect
brq.io.bcommit <> roq.io.bcommit
brq.io.exuRedirectWb <> io.fromIntBlock.exuRedirect
brq.io.pcReadReq.brqIdx := dispatch.io.enqIQCtrl(0).bits.brTag // jump
io.toIntBlock.jumpPc := brq.io.pcReadReq.pc
val jumpInst = dispatch.io.enqIQCtrl(0).bits
val ftqOffsetReg = Reg(UInt(log2Up(PredictWidth).W))
ftqOffsetReg := jumpInst.cf.ftqOffset
ftq.io.ftqRead(0).ptr := jumpInst.cf.ftqPtr // jump
io.toIntBlock.jumpPc := GetPcByFtq(
ftq.io.ftqRead(0).entry.ftqPC, ftqOffsetReg, ftq.io.ftqRead(0).entry.hasLastPrev
)
io.toIntBlock.jalr_target := ftq.io.ftqRead(0).entry.target
// pipeline between decode and dispatch
val lastCycleRedirect = RegNext(redirectValid)
for (i <- 0 until RenameWidth) {
PipelineConnect(decode.io.out(i), rename.io.in(i), rename.io.in(i).ready, redirectValid || lastCycleRedirect)
PipelineConnect(decode.io.out(i), rename.io.in(i), rename.io.in(i).ready,
backendRedirect.valid || flush || io.frontend.redirect_cfiUpdate.valid)
}
rename.io.redirect.valid <> redirectValid
rename.io.redirect.bits <> redirect
rename.io.redirect <> backendRedirect
rename.io.flush := flush
rename.io.roqCommits <> roq.io.commits
rename.io.out <> dispatch.io.fromRename
rename.io.renameBypass <> dispatch.io.renameBypass
dispatch.io.redirect.valid <> redirectValid
dispatch.io.redirect.bits <> redirect
dispatch.io.redirect <> backendRedirect
dispatch.io.flush := flush
dispatch.io.enqRoq <> roq.io.enq
dispatch.io.enqLsq <> io.toLsBlock.enqLsq
dispatch.io.readIntRf <> io.toIntBlock.readRf
......@@ -138,7 +296,6 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
// dispatch.io.enqIQData <> io.toIntBlock.enqIqData ++ io.toFpBlock.enqIqData ++ io.toLsBlock.enqIqData
val flush = redirectValid && RedirectLevel.isUnconditional(redirect.level)
fpBusyTable.io.flush := flush
intBusyTable.io.flush := flush
for((wb, setPhyRegRdy) <- io.fromIntBlock.wbRegs.zip(intBusyTable.io.wbPregs)){
......@@ -152,37 +309,35 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
intBusyTable.io.read <> dispatch.io.readIntState
fpBusyTable.io.read <> dispatch.io.readFpState
roq.io.redirect.valid := brq.io.redirectOut.valid || io.fromLsBlock.replay.valid
roq.io.redirect.bits <> redirectArb
roq.io.exeWbResults.take(roqWbSize-1).zip(
roq.io.redirect <> backendRedirect
roq.io.exeWbResults.zip(
io.fromIntBlock.wbRegs ++ io.fromFpBlock.wbRegs ++ io.fromLsBlock.stOut
).foreach{
case(x, y) =>
x.bits := y.bits
x.valid := y.valid && !y.bits.redirectValid
x.valid := y.valid
}
roq.io.exeWbResults.last := brq.io.out
// TODO: is 'backendRedirect' necesscary?
io.toIntBlock.redirect <> backendRedirect
io.toIntBlock.flush <> flush
io.toFpBlock.redirect <> backendRedirect
io.toFpBlock.flush <> flush
io.toLsBlock.redirect <> backendRedirect
io.toLsBlock.flush <> flush
if (env.DualCoreDifftest) {
difftestIO.fromRoq <> roq.difftestIO
trapIO <> roq.trapIO
}
io.toIntBlock.redirect.valid := redirectValid
io.toIntBlock.redirect.bits := redirect
io.toFpBlock.redirect.valid := redirectValid
io.toFpBlock.redirect.bits := redirect
io.toLsBlock.redirect.valid := redirectValid
io.toLsBlock.redirect.bits := redirect
dispatch.io.readPortIndex.intIndex <> io.toIntBlock.readPortIndex
dispatch.io.readPortIndex.fpIndex <> io.toFpBlock.readPortIndex
// roq to int block
io.roqio.toCSR <> roq.io.csr
io.roqio.exception.valid := roq.io.redirectOut.valid && roq.io.redirectOut.bits.isException()
io.roqio.exception.bits := roq.io.exception
io.roqio.isInterrupt := roq.io.redirectOut.bits.interrupt
io.roqio.exception := roq.io.exception
io.roqio.exception.bits.uop.cf.pc := flushPC
// roq to mem block
io.roqio.lsq <> roq.io.lsq
}
......@@ -37,6 +37,7 @@ class FloatBlock
})
val redirect = io.fromCtrlBlock.redirect
val flush = io.fromCtrlBlock.flush
val fpRf = Module(new Regfile(
numReadPorts = NRFpReadPorts,
......@@ -86,6 +87,7 @@ class FloatBlock
rsCtrl.io.data <> rsData.io.ctrl
rsCtrl.io.redirect <> redirect // TODO: remove it
rsCtrl.io.flush <> flush // TODO: remove it
rsCtrl.io.numExist <> io.toCtrlBlock.numExist(i)
rsCtrl.io.enqCtrl <> io.fromCtrlBlock.enqIqCtrl(i)
......@@ -98,6 +100,7 @@ class FloatBlock
rsData.io.srcRegValue(1) := src2Value(readPortIndex(i))
if (cfg.fpSrcCnt > 2) rsData.io.srcRegValue(2) := src3Value(readPortIndex(i))
rsData.io.redirect <> redirect
rsData.io.flush <> flush
rsData.io.writeBackedData <> writeBackData
for ((x, y) <- rsData.io.extraListenPorts.zip(extraListenPorts)) {
......@@ -106,6 +109,7 @@ class FloatBlock
}
exeUnits(i).io.redirect <> redirect
exeUnits(i).io.flush <> flush
exeUnits(i).io.fromFp <> rsData.io.deq
rsData.io.feedback := DontCare
......
......@@ -8,6 +8,7 @@ import xiangshan.backend.exu._
import xiangshan.backend.fu.FenceToSbuffer
import xiangshan.backend.issue.{ReservationStationCtrl, ReservationStationData}
import xiangshan.backend.regfile.Regfile
import xiangshan.backend.roq.RoqExceptionInfo
class WakeUpBundle(numFast: Int, numSlow: Int) extends XSBundle {
val fastUops = Vec(numFast, Flipped(ValidIO(new MicroOp)))
......@@ -75,9 +76,9 @@ class IntegerBlock
val fflags = Flipped(Valid(UInt(5.W))) // from roq
val dirty_fs = Input(Bool()) // from roq
val frm = Output(UInt(3.W)) // to float
val exception = Flipped(ValidIO(new MicroOp)) // from roq
val isInterrupt = Input(Bool()) // from roq
val exception = Flipped(ValidIO(new RoqExceptionInfo))
val trapTarget = Output(UInt(VAddrBits.W)) // to roq
val isXRet = Output(Bool())
val interrupt = Output(Bool()) // to roq
val memExceptionVAddr = Input(UInt(VAddrBits.W)) // from lsq
val externalInterrupt = new ExternalInterruptIO // from outside
......@@ -119,6 +120,7 @@ class IntegerBlock
difftestIO <> DontCare
val redirect = io.fromCtrlBlock.redirect
val flush = io.fromCtrlBlock.flush
val intRf = Module(new Regfile(
numReadPorts = NRIntReadPorts,
......@@ -168,6 +170,7 @@ class IntegerBlock
rsCtrl.io.data <> rsData.io.ctrl
rsCtrl.io.redirect <> redirect // TODO: remove it
rsCtrl.io.flush <> flush // TODO: remove it
rsCtrl.io.numExist <> io.toCtrlBlock.numExist(i)
rsCtrl.io.enqCtrl <> io.fromCtrlBlock.enqIqCtrl(i)
......@@ -176,8 +179,12 @@ class IntegerBlock
val src2Value = VecInit((0 until 4).map(i => intRf.io.readPorts(i * 2 + 1).data))
rsData.io.srcRegValue(0) := src1Value(readPortIndex(i))
if (cfg.intSrcCnt > 1) rsData.io.srcRegValue(1) := src2Value(readPortIndex(i))
if (cfg == Exu.jumpExeUnitCfg) rsData.io.jumpPc := io.fromCtrlBlock.jumpPc
if (cfg == Exu.jumpExeUnitCfg) {
rsData.io.jumpPc := io.fromCtrlBlock.jumpPc
rsData.io.jalr_target := io.fromCtrlBlock.jalr_target
}
rsData.io.redirect <> redirect
rsData.io.flush <> flush
rsData.io.writeBackedData <> writeBackData
for ((x, y) <- rsData.io.extraListenPorts.zip(extraListenPorts)) {
......@@ -186,6 +193,7 @@ class IntegerBlock
}
exeUnits(i).io.redirect <> redirect
exeUnits(i).io.flush <> flush
exeUnits(i).io.fromInt <> rsData.io.deq
rsData.io.feedback := DontCare
......
......@@ -155,6 +155,7 @@ class MemBlockImp
rsCtrl.io.data <> rsData.io.ctrl
rsCtrl.io.redirect <> redirect // TODO: remove it
rsCtrl.io.flush <> io.fromCtrlBlock.flush // TODO: remove it
rsCtrl.io.numExist <> io.toCtrlBlock.numExist(i)
rsCtrl.io.enqCtrl <> io.fromCtrlBlock.enqIqCtrl(i)
......@@ -165,6 +166,7 @@ class MemBlockImp
rsData.io.srcRegValue(1) := Mux(src2IsFp, io.fromFpBlock.readFpRf(i - exuParameters.LduCnt).data, io.fromIntBlock.readIntRf(readPortIndex(i) + 1).data)
}
rsData.io.redirect <> redirect
rsData.io.flush <> io.fromCtrlBlock.flush
rsData.io.writeBackedData <> writeBackData
for ((x, y) <- rsData.io.extraListenPorts.zip(extraListenPorts)) {
......@@ -217,6 +219,7 @@ class MemBlockImp
// LoadUnit
for (i <- 0 until exuParameters.LduCnt) {
loadUnits(i).io.redirect <> io.fromCtrlBlock.redirect
loadUnits(i).io.flush <> io.fromCtrlBlock.flush
loadUnits(i).io.tlbFeedback <> reservationStations(i).io.feedback
loadUnits(i).io.dtlb <> dtlb.io.requestor(i)
// get input form dispatch
......@@ -240,6 +243,7 @@ class MemBlockImp
val dtlbReq = dtlb.io.requestor(exuParameters.LduCnt + i)
stu.io.redirect <> io.fromCtrlBlock.redirect
stu.io.flush <> io.fromCtrlBlock.flush
stu.io.tlbFeedback <> rs.io.feedback
stu.io.dtlb <> dtlbReq
stu.io.stin <> rs.io.deq
......@@ -262,6 +266,7 @@ class MemBlockImp
lsq.io.roq <> io.lsqio.roq
lsq.io.enq <> io.fromCtrlBlock.enqLsq
lsq.io.brqRedirect <> io.fromCtrlBlock.redirect
lsq.io.flush <> io.fromCtrlBlock.flush
io.toCtrlBlock.replay <> lsq.io.rollback
lsq.io.dcache <> dcache.io.lsu.lsq
lsq.io.uncache <> uncache.io.lsq
......@@ -314,6 +319,7 @@ class MemBlockImp
atomicsUnit.io.in.valid := st0_atomics || st1_atomics
atomicsUnit.io.in.bits := Mux(st0_atomics, reservationStations(atomic_rs0).io.deq.bits, reservationStations(atomic_rs1).io.deq.bits)
atomicsUnit.io.redirect <> io.fromCtrlBlock.redirect
atomicsUnit.io.flush <> io.fromCtrlBlock.flush
atomicsUnit.io.dtlb.resp.valid := false.B
atomicsUnit.io.dtlb.resp.bits := DontCare
......
package xiangshan.backend.brq
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.ExcitingUtils._
import xiangshan.backend.JumpOpType
import xiangshan.backend.decode.ImmUnion
class BrqPtr extends CircularQueuePtr(BrqPtr.BrqSize) with HasCircularQueuePtrHelper {
// this.age < that.age
final def < (that: BrqPtr): Bool = {
Mux(this.flag === that.flag,
this.value > that.value,
this.value < that.value
)
}
def needBrFlush(redirect: Valid[Redirect]): Bool = {
isAfter(this, redirect.bits.brTag) || (redirect.bits.flushItself() && redirect.bits.brTag === this)
}
def needFlush(redirect: Valid[Redirect]): Bool = {
redirect.bits.isUnconditional() || needBrFlush(redirect)
}
override def toPrintable: Printable = p"f:$flag v:$value"
}
object BrqPtr extends HasXSParameter {
def apply(f: Bool, v: UInt): BrqPtr = {
val ptr = Wire(new BrqPtr)
ptr.flag := f
ptr.value := v
ptr
}
}
class BrqEnqIO extends XSBundle {
val needAlloc = Vec(RenameWidth, Input(Bool()))
val req = Vec(RenameWidth, Flipped(DecoupledIO(new CtrlFlow)))
val resp = Vec(RenameWidth, Output(new BrqPtr))
}
class BrqPcRead extends XSBundle {
val brqIdx = Input(new BrqPtr)
val pc = Output(UInt(VAddrBits.W))
}
class BrqIO extends XSBundle{
val redirect = Input(ValidIO(new Redirect))
// receive branch/jump calculated target
val exuRedirectWb = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput)))
// from decode, branch insts enq
val enq = new BrqEnqIO
// to roq
val out = ValidIO(new ExuOutput)
// misprediction, flush pipeline
val redirectOut = Output(Valid(new Redirect))
val cfiInfo = ValidIO(new CfiUpdateInfo)
// commit cnt of branch instr
val bcommit = Input(UInt(BrTagWidth.W))
// read pc for jump unit
val pcReadReq = new BrqPcRead
}
class Brq extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new BrqIO)
class BrqEntry extends Bundle {
val ptrFlag = Bool()
val exuOut = new ExuOutput
}
val s_idle :: s_wb :: s_auipc_wb :: Nil = Enum(3)
class DecodeEnqBrqData extends Bundle {
val cfiUpdateInfo = new CfiUpdateInfo
// we use this to calculate branch target
val imm12 = UInt(12.W)
}
// data and state
val decodeData = Module(new SyncDataModuleTemplate(new DecodeEnqBrqData, BrqSize, 3, DecodeWidth))
val writebackData = Module(new SyncDataModuleTemplate(new ExuOutput, BrqSize, 2, exuParameters.AluCnt + exuParameters.JmpCnt))
val ptrFlagVec = Reg(Vec(BrqSize, Bool()))
val stateQueue = RegInit(VecInit(Seq.fill(BrqSize)(s_idle)))
// queue pointers
val headPtr, tailPtr = RegInit(BrqPtr(false.B, 0.U))
val writebackPtr = RegInit(BrqPtr(false.B, 0.U))
val writebackPtr_next = WireInit(writebackPtr)
writebackPtr := writebackPtr_next
val headIdx = headPtr.value
val writebackIdx = writebackPtr.value
/**
* commit (dequeue): after ROB commits branch instructions, move headPtr forward
*/
headPtr := headPtr + io.bcommit
/**
* write back
*/
val wbState = stateQueue(writebackIdx)
val wbValid = wbState === s_wb
val wbIsAuipc = wbState === s_auipc_wb
val wbEntry = Wire(new ExuOutput)
val wbIsMisPred = wbEntry.redirect.target =/= wbEntry.brUpdate.pnpc
io.redirectOut.valid := wbValid && wbIsMisPred
io.redirectOut.bits := wbEntry.redirect
io.redirectOut.bits.level := RedirectLevel.flushAfter
io.redirectOut.bits.brTag := BrqPtr(ptrFlagVec(writebackIdx), writebackIdx)
io.out.valid := wbValid || wbIsAuipc
io.out.bits := wbEntry
when (io.out.valid) {
stateQueue(writebackIdx) := s_idle
writebackPtr_next := writebackPtr + 1.U
}
val brUpdateReadIdx = Mux(io.redirect.bits.flushItself(), io.redirect.bits.brTag - 1.U, io.redirect.bits.brTag)
val brUpdateReadEntry = Wire(new CfiUpdateInfo)
io.cfiInfo.valid := RegNext(io.redirect.valid || wbValid)
io.cfiInfo.bits := brUpdateReadEntry
io.cfiInfo.bits.target := RegNext(Mux(io.redirect.bits.flushItself(),
io.redirect.bits.target,
wbEntry.brUpdate.target
))
io.cfiInfo.bits.brTarget := io.cfiInfo.bits.target
io.cfiInfo.bits.brTag := RegNext(brUpdateReadIdx)
io.cfiInfo.bits.isReplay := RegNext(io.redirect.bits.flushItself())
io.cfiInfo.bits.isMisPred := RegNext(wbIsMisPred)
XSInfo(io.out.valid,
p"commit branch to roq, mispred:${io.redirectOut.valid} pc=${Hexadecimal(io.out.bits.uop.cf.pc)}\n"
)
/**
* branch insts enq
*/
// note that redirect sent to IFU is delayed for one clock cycle
// thus, brq should not allow enqueue in the next cycle after redirect
val lastCycleRedirect = RegNext(io.redirect.valid)
val validEntries = distanceBetween(tailPtr, headPtr)
val enqBrTag = VecInit((0 until DecodeWidth).map(i => tailPtr + PopCount(io.enq.needAlloc.take(i))))
io.enq.resp := enqBrTag
for (i <- 0 until DecodeWidth) {
val idx = enqBrTag(i).value
io.enq.req(i).ready := validEntries <= (BrqSize - (i + 1)).U && !lastCycleRedirect
when (io.enq.req(i).fire()) {
ptrFlagVec(idx) := enqBrTag(i).flag
stateQueue(idx) := s_idle
}
}
val enqCnt = PopCount(io.enq.req.map(_.fire()))
tailPtr := tailPtr + enqCnt
/**
* exu write back
*/
for ((exuWb, i) <- io.exuRedirectWb.zipWithIndex) {
when (exuWb.valid) {
val wbIdx = exuWb.bits.redirect.brTag.value
XSInfo(
p"exu write back: brTag:${exuWb.bits.redirect.brTag}" +
p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} " +
// p"pnpc=${Hexadecimal(brQueue(wbIdx).exuOut.brUpdate.pnpc)} " +
p"target=${Hexadecimal(exuWb.bits.redirect.target)}\n"
)
assert(stateQueue(wbIdx) === s_idle)
if(i == 0){ // jump
stateQueue(wbIdx) := Mux(JumpOpType.jumpOpisAuipc(exuWb.bits.uop.ctrl.fuOpType),
s_auipc_wb,
s_wb
)
} else { // alu
stateQueue(wbIdx) := s_wb
}
}
}
// when redirect is valid, we need to update the states and pointers
when (io.redirect.valid) {
// For unconditional redirect, flush all entries
when (io.redirect.bits.isUnconditional()) {
stateQueue.foreach(_ := s_idle)
headPtr := BrqPtr(false.B, 0.U)
tailPtr := BrqPtr(false.B, 0.U)
writebackPtr_next := BrqPtr(false.B, 0.U)
}.otherwise {
// conditional check: branch mis-prediction and memory dependence violation
stateQueue.zipWithIndex.foreach({ case(s, i) =>
val ptr = BrqPtr(ptrFlagVec(i), i.U)
when (ptr.needBrFlush(io.redirect)) {
s := s_idle
}
})
tailPtr := io.redirect.bits.brTag + Mux(io.redirect.bits.flushItself(), 0.U, 1.U)
when (io.redirect.bits.flushItself() && writebackPtr.needBrFlush(io.redirect)) {
writebackPtr_next := io.redirect.bits.brTag
}
}
}
def mergeWbEntry(dec: DecodeEnqBrqData, wb: ExuOutput) : ExuOutput = {
val mergeData = Wire(new ExuOutput)
// only writeback necessary information
mergeData.uop := wb.uop
mergeData.data := wb.data
mergeData.fflags := wb.fflags
mergeData.redirectValid := wb.redirectValid
// calculate target pc
val pc = dec.cfiUpdateInfo.pc
val offset = SignExt(ImmUnion.B.toImm32(dec.imm12), VAddrBits)
val snpc = pc + Mux(dec.cfiUpdateInfo.pd.isRVC, 2.U, 4.U)
val bnpc = pc + offset
val branch_pc = Mux(wb.brUpdate.taken, bnpc, snpc)
val redirectTarget = Mux(dec.cfiUpdateInfo.pd.isBr, branch_pc, wb.redirect.target)
mergeData.redirect := wb.redirect
mergeData.redirect.target := redirectTarget
mergeData.debug := wb.debug
mergeData.brUpdate := dec.cfiUpdateInfo
mergeData.brUpdate.target := redirectTarget
mergeData.brUpdate.brTarget := redirectTarget
mergeData.brUpdate.taken := wb.brUpdate.taken
mergeData.brUpdate.bpuMeta.predictor:= wb.brUpdate.bpuMeta.predictor
mergeData
}
def mergeBrUpdateEntry(dec: DecodeEnqBrqData, wb: ExuOutput): CfiUpdateInfo = {
val mergeData = WireInit(dec.cfiUpdateInfo)
mergeData.taken := wb.brUpdate.taken
mergeData
}
decodeData.io.raddr(0) := writebackPtr_next.value
decodeData.io.raddr(1) := brUpdateReadIdx.value
decodeData.io.raddr(2) := io.pcReadReq.brqIdx.value
decodeData.io.wen := VecInit(io.enq.req.map(_.fire()))
decodeData.io.waddr := VecInit(enqBrTag.map(_.value))
decodeData.io.wdata.zip(io.enq.req).foreach{ case (wdata, req) =>
wdata.cfiUpdateInfo := req.bits.brUpdate
wdata.cfiUpdateInfo.pc := req.bits.pc
wdata.imm12 := ImmUnion.B.minBitsFromInstr(req.bits.instr)
}
writebackData.io.raddr(0) := writebackPtr_next.value
writebackData.io.raddr(1) := brUpdateReadIdx.value
writebackData.io.wen := VecInit(io.exuRedirectWb.map(_.valid))
writebackData.io.waddr := VecInit(io.exuRedirectWb.map(_.bits.redirect.brTag.value))
writebackData.io.wdata := VecInit(io.exuRedirectWb.map(_.bits))
wbEntry := mergeWbEntry(decodeData.io.rdata(0), writebackData.io.rdata(0))
brUpdateReadEntry := mergeBrUpdateEntry(decodeData.io.rdata(1), writebackData.io.rdata(1))
io.pcReadReq.pc := decodeData.io.rdata(2).cfiUpdateInfo.pc
// Debug info
val debug_roq_redirect = io.redirect.valid && io.redirect.bits.isUnconditional()
val debug_brq_redirect = io.redirectOut.valid
val debug_normal_mode = !(debug_roq_redirect || debug_brq_redirect)
for(i <- 0 until DecodeWidth){
XSDebug(
debug_normal_mode,
p"enq v:${io.enq.req(i).valid} rdy:${io.enq.req(i).ready} pc:${Hexadecimal(io.enq.req(i).bits.pc)}" +
p" brTag:${io.enq.resp(i)}\n"
)
}
XSInfo(debug_roq_redirect, "roq redirect, flush brq\n")
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirectOut.bits.target)}\n")
XSDebug(io.cfiInfo.valid, "inOrderValid: pc=%x\n", io.cfiInfo.bits.pc)
XSDebug(p"headIdx:$headIdx writebackIdx:$writebackIdx\n")
XSDebug(p"headPtr:$headPtr tailPtr:$tailPtr\n")
XSDebug("")
stateQueue.reverse.map(s =>{
XSDebug(false, s === s_idle, "-")
XSDebug(false, s === s_wb, "w")
})
XSDebug(false, true.B, "\n")
val fire = io.out.fire()
val predRight = fire && !wbIsMisPred
val predWrong = fire && wbIsMisPred
// val isBType = wbEntry.brUpdate.btbType===BTBtype.B
val isBType = wbEntry.brUpdate.pd.isBr
// val isJType = wbEntry.brUpdate.btbType===BTBtype.J
val isJType = wbEntry.brUpdate.pd.isJal
// val isIType = wbEntry.brUpdate.btbType===BTBtype.I
val isIType = wbEntry.brUpdate.pd.isJalr
// val isRType = wbEntry.brUpdate.btbType===BTBtype.R
val isRType = wbEntry.brUpdate.pd.isRet
val mbpInstr = fire
val mbpRight = predRight
val mbpWrong = predWrong
val mbpBRight = predRight && isBType
val mbpBWrong = predWrong && isBType
val mbpJRight = predRight && isJType
val mbpJWrong = predWrong && isJType
val mbpIRight = predRight && isIType
val mbpIWrong = predWrong && isIType
val mbpRRight = predRight && isRType
val mbpRWrong = predWrong && isRType
if(!env.FPGAPlatform && env.EnablePerfDebug) {
val predictor = io.cfiInfo.bits.bpuMeta.predictor
val cfiCountValid = io.cfiInfo.valid && !io.cfiInfo.bits.isReplay
val ubtbAns = io.cfiInfo.bits.bpuMeta.ubtbAns
val btbAns = io.cfiInfo.bits.bpuMeta.btbAns
val tageAns = io.cfiInfo.bits.bpuMeta.tageAns
val rasAns = io.cfiInfo.bits.bpuMeta.rasAns
val loopAns = io.cfiInfo.bits.bpuMeta.loopAns
// Pipeline stage counter
val s1Right = cfiCountValid && !io.cfiInfo.bits.isMisPred && predictor === 0.U
val s1Wrong = cfiCountValid && io.cfiInfo.bits.isMisPred && predictor === 0.U
val s2Right = cfiCountValid && !io.cfiInfo.bits.isMisPred && predictor === 1.U
val s2Wrong = cfiCountValid && io.cfiInfo.bits.isMisPred && predictor === 1.U
val s3Right = cfiCountValid && !io.cfiInfo.bits.isMisPred && predictor === 2.U
val s3Wrong = cfiCountValid && io.cfiInfo.bits.isMisPred && predictor === 2.U
// Predictor counter
// val ubtbRight = cfiCountValid && ubtbAns.hit && io.cfiInfo.bits.target === ubtbAns.target && io.cfiInfo.bits.taken === ubtbAns.taken
// val ubtbWrong = cfiCountValid && ubtbAns.hit && (io.cfiInfo.bits.target =/= ubtbAns.target || io.cfiInfo.bits.taken =/= ubtbAns.taken)
val ubtbRight = cfiCountValid && ubtbAns.hit && Mux(ubtbAns.taken,
io.cfiInfo.bits.target === ubtbAns.target && io.cfiInfo.bits.taken === ubtbAns.taken, // taken
io.cfiInfo.bits.taken === ubtbAns.taken) // noTaken
val ubtbWrong = cfiCountValid && ubtbAns.hit && Mux(ubtbAns.taken,
io.cfiInfo.bits.target =/= ubtbAns.target || io.cfiInfo.bits.taken =/= ubtbAns.taken, // taken
io.cfiInfo.bits.taken =/= ubtbAns.taken) // noTaken
val takenAndRight = ubtbAns.taken && ubtbRight
val takenButWrong = ubtbAns.taken && ubtbWrong
// val btbRight = cfiCountValid && btbAns.hit && io.cfiInfo.bits.target === btbAns.target && io.cfiInfo.bits.taken === btbAns.taken
// val btbWrong = cfiCountValid && btbAns.hit && (io.cfiInfo.bits.target =/= btbAns.target || io.cfiInfo.bits.taken =/= btbAns.taken)
val btbRight = cfiCountValid && btbAns.hit && Mux(btbAns.taken,
io.cfiInfo.bits.target === btbAns.target && io.cfiInfo.bits.taken === btbAns.taken, // taken
io.cfiInfo.bits.taken === btbAns.taken) // noTaken
val btbWrong = cfiCountValid && btbAns.hit && Mux(btbAns.taken,
io.cfiInfo.bits.target =/= btbAns.target || io.cfiInfo.bits.taken =/= btbAns.taken, // taken
io.cfiInfo.bits.taken =/= btbAns.taken) // noTaken
val tageRight = cfiCountValid && io.cfiInfo.bits.pd.brType =/= "b10".U && io.cfiInfo.bits.taken === tageAns.taken // DontCare jal
val tageWrong = cfiCountValid && io.cfiInfo.bits.pd.brType =/= "b10".U && io.cfiInfo.bits.taken =/= tageAns.taken // DontCare jal
val rasRight = cfiCountValid && io.cfiInfo.bits.pd.isRet && rasAns.hit && io.cfiInfo.bits.target === rasAns.target
val rasWrong = cfiCountValid && io.cfiInfo.bits.pd.isRet && rasAns.hit && io.cfiInfo.bits.target =/= rasAns.target
val loopRight = cfiCountValid && loopAns.hit && io.cfiInfo.bits.taken === loopAns.taken
val loopWrong = cfiCountValid && loopAns.hit && io.cfiInfo.bits.taken =/= loopAns.taken
ExcitingUtils.addSource(mbpInstr, "perfCntCondBpInstr", Perf)
ExcitingUtils.addSource(mbpRight, "perfCntCondBpRight", Perf)
ExcitingUtils.addSource(mbpWrong, "perfCntCondBpWrong", Perf)
ExcitingUtils.addSource(mbpBRight, "perfCntCondBpBRight", Perf)
ExcitingUtils.addSource(mbpBWrong, "perfCntCondBpBWrong", Perf)
ExcitingUtils.addSource(mbpJRight, "perfCntCondBpJRight", Perf)
ExcitingUtils.addSource(mbpJWrong, "perfCntCondBpJWrong", Perf)
ExcitingUtils.addSource(mbpIRight, "perfCntCondBpIRight", Perf)
ExcitingUtils.addSource(mbpIWrong, "perfCntCondBpIWrong", Perf)
ExcitingUtils.addSource(mbpRRight, "perfCntCondBpRRight", Perf)
ExcitingUtils.addSource(mbpRWrong, "perfCntCondBpRWrong", Perf)
ExcitingUtils.addSource(s1Right, "perfCntS1Right", Perf)
ExcitingUtils.addSource(s1Wrong, "perfCntS1Wrong", Perf)
ExcitingUtils.addSource(s2Right, "perfCntS2Right", Perf)
ExcitingUtils.addSource(s2Wrong, "perfCntS2Wrong", Perf)
ExcitingUtils.addSource(s3Right, "perfCntS3Right", Perf)
ExcitingUtils.addSource(s3Wrong, "perfCntS3Wrong", Perf)
ExcitingUtils.addSource(ubtbRight, "perfCntubtbRight", Perf)
ExcitingUtils.addSource(ubtbWrong, "perfCntubtbWrong", Perf)
ExcitingUtils.addSource(btbRight, "perfCntbtbRight", Perf)
ExcitingUtils.addSource(btbWrong, "perfCntbtbWrong", Perf)
ExcitingUtils.addSource(tageRight, "perfCnttageRight", Perf)
ExcitingUtils.addSource(tageWrong, "perfCnttageWrong", Perf)
ExcitingUtils.addSource(rasRight, "perfCntrasRight", Perf)
ExcitingUtils.addSource(rasWrong, "perfCntrasWrong", Perf)
ExcitingUtils.addSource(loopRight, "perfCntloopRight", Perf)
ExcitingUtils.addSource(loopWrong, "perfCntloopWrong", Perf)
ExcitingUtils.addSource(takenAndRight, "perfCntTakenAndRight", Perf)
ExcitingUtils.addSource(takenButWrong, "perfCntTakenButWrong", Perf)
}
val utilization = Mux(headPtr.flag === tailPtr.flag, tailPtr.value - headPtr.value, BrqSize.U + tailPtr.value - headPtr.value)
XSPerf("utilization", utilization)
XSPerf("mbpInstr", PopCount(mbpInstr))
XSPerf("mbpRight", PopCount(mbpRight))
XSPerf("mbpWrong", PopCount(mbpWrong))
XSPerf("mbpBRight", PopCount(mbpBRight))
XSPerf("mbpBWrong", PopCount(mbpBWrong))
XSPerf("mbpJRight", PopCount(mbpJRight))
XSPerf("mbpJWrong", PopCount(mbpJWrong))
XSPerf("mbpIRight", PopCount(mbpIRight))
XSPerf("mbpIWrong", PopCount(mbpIWrong))
XSPerf("mbpRRight", PopCount(mbpRRight))
XSPerf("mbpRWrong", PopCount(mbpRWrong))
}
......@@ -3,15 +3,10 @@ package xiangshan.backend.decode
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.brq.BrqEnqIO
import utils._
import xiangshan.backend.decode.Instructions.{AUIPC, MRET, SRET}
class DecodeStage extends XSModule {
val io = IO(new Bundle() {
// enq Brq
val enqBrq = Flipped(new BrqEnqIO)
// from Ibuffer
val in = Vec(DecodeWidth, Flipped(DecoupledIO(new CtrlFlow)))
......@@ -20,36 +15,10 @@ class DecodeStage extends XSModule {
})
val decoders = Seq.fill(DecodeWidth)(Module(new DecodeUnit))
// Handshake ---------------------
// 1. if current instruction is valid, then:
// First, assert toBrq(i).valid if (in.valid and out.ready and isBr) and present toBrq(i).bits
// Second, check toBrq(i).ready and connect it to io.out(i).valid
// 2. To Decode Buffer:
// First, assert in(i).ready if out(i).ready
// Second, assert out(i).valid iff in(i).valid and instruction is valid (not implemented) and toBrq(i).ready
for (i <- 0 until DecodeWidth) {
decoders(i).io.enq.ctrl_flow <> io.in(i).bits
val isMret = io.in(i).bits.instr === MRET
val isSret = io.in(i).bits.instr === SRET
val isAuiPc = io.in(i).bits.instr === AUIPC
val thisBrqValid = !io.in(i).bits.brUpdate.pd.notCFI || isMret || isSret || isAuiPc
io.enqBrq.needAlloc(i) := thisBrqValid
io.enqBrq.req(i).valid := io.in(i).valid && thisBrqValid && io.out(i).ready
io.enqBrq.req(i).bits := io.in(i).bits
io.enqBrq.req(i).bits.instr := decoders(i).io.deq.cf_ctrl.cf.instr
io.out(i).valid := io.in(i).valid && io.enqBrq.req(i).ready
io.out(i).valid := io.in(i).valid
io.out(i).bits := decoders(i).io.deq.cf_ctrl
io.out(i).bits.brTag := io.enqBrq.resp(i)
io.in(i).ready := io.out(i).ready && io.enqBrq.req(i).ready
XSDebug(io.in(i).valid || io.out(i).valid || io.enqBrq.req(i).valid,
"i:%d In(%d %d) Out(%d %d) ToBrq(%d %d) pc:%x instr:%x\n",
i.U, io.in(i).valid, io.in(i).ready, io.out(i).valid, io.out(i).ready,
io.enqBrq.req(i).valid, io.enqBrq.req(i).ready, io.in(i).bits.pc, io.in(i).bits.instr)
io.in(i).ready := io.out(i).ready
}
}
......@@ -411,7 +411,6 @@ class DecodeUnit extends XSModule with DecodeUnitConstants {
// output
cf_ctrl.cf := ctrl_flow
cf_ctrl.brTag := DontCare
val cs = Wire(new CtrlSignals()).decode(ctrl_flow.instr, decode_table)
val fpDecoder = Module(new FPDecoder)
......
......@@ -24,6 +24,7 @@ class Dispatch extends XSModule {
val io = IO(new Bundle() {
// flush or replay
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
// from rename
val fromRename = Vec(RenameWidth, Flipped(DecoupledIO(new MicroOp)))
val renameBypass = Input(new RenameBypassInfo)
......@@ -57,7 +58,7 @@ class Dispatch extends XSModule {
// pipeline between rename and dispatch
// accepts all at once
val redirectValid = io.redirect.valid// && !io.redirect.bits.isReplay
val redirectValid = io.redirect.valid || io.flush
for (i <- 0 until RenameWidth) {
PipelineConnect(io.fromRename(i), dispatch1.io.fromRename(i), dispatch1.io.recv(i), redirectValid)
}
......@@ -75,8 +76,11 @@ class Dispatch extends XSModule {
// dispatch queue: queue uops and dispatch them to different reservation stations or issue queues
// it may cancel the uops
intDq.io.redirect <> io.redirect
intDq.io.flush <> io.flush
fpDq.io.redirect <> io.redirect
fpDq.io.flush <> io.flush
lsDq.io.redirect <> io.redirect
lsDq.io.flush <> io.flush
// Int dispatch queue to Int reservation stations
val intDispatch = Module(new Dispatch2Int)
......
......@@ -48,7 +48,7 @@ class Dispatch1 extends XSModule with HasExceptionNO {
val isInt = VecInit(io.fromRename.map(req => FuType.isIntExu(req.bits.ctrl.fuType)))
val isBranch = VecInit(io.fromRename.map(req =>
// cover auipc (a fake branch)
!req.bits.cf.brUpdate.pd.notCFI || FuType.isJumpExu(req.bits.ctrl.fuType)
!req.bits.cf.pd.notCFI || FuType.isJumpExu(req.bits.ctrl.fuType)
))
val isFp = VecInit(io.fromRename.map(req => FuType.isFpExu (req.bits.ctrl.fuType)))
val isMem = VecInit(io.fromRename.map(req => FuType.isMemExu(req.bits.ctrl.fuType)))
......
......@@ -17,6 +17,7 @@ class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle {
}
val deq = Vec(deqnum, DecoupledIO(new MicroOp))
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
override def cloneType: DispatchQueueIO.this.type =
new DispatchQueueIO(enqnum, deqnum).asInstanceOf[this.type]
}
......@@ -45,7 +46,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
val isTrueEmpty = ~Cat((0 until size).map(i => stateEntries(i) === s_valid)).orR
val canEnqueue = allowEnqueue
val canActualEnqueue = canEnqueue && !io.redirect.valid
val canActualEnqueue = canEnqueue && !(io.redirect.valid || io.flush)
/**
* Part 1: update states and uops when enqueue, dequeue, commit, redirect/replay
......@@ -77,7 +78,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
// dequeue: from s_valid to s_dispatched
for (i <- 0 until deqnum) {
when (io.deq(i).fire() && !io.redirect.valid) {
when (io.deq(i).fire() && !(io.redirect.valid || io.flush)) {
stateEntries(headPtr(i).value) := s_invalid
XSError(stateEntries(headPtr(i).value) =/= s_valid, "state of the dispatch entry is not s_valid\n")
......@@ -87,7 +88,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
// redirect: cancel uops currently in the queue
val needCancel = Wire(Vec(size, Bool()))
for (i <- 0 until size) {
needCancel(i) := stateEntries(i) =/= s_invalid && roqIdxEntries(i).needFlush(io.redirect)
needCancel(i) := stateEntries(i) =/= s_invalid && (roqIdxEntries(i).needFlush(io.redirect, io.flush) || io.flush)
when (needCancel(i)) {
stateEntries(i) := s_invalid
......@@ -118,7 +119,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
// agreement with reservation station: don't dequeue when redirect.valid
val nextHeadPtr = Wire(Vec(deqnum, new CircularQueuePtr(size)))
for (i <- 0 until deqnum) {
nextHeadPtr(i) := Mux(io.redirect.valid && io.redirect.bits.isUnconditional(),
nextHeadPtr(i) := Mux(io.flush,
i.U.asTypeOf(new CircularQueuePtr(size)),
Mux(io.redirect.valid, headPtr(i), headPtr(i) + numDeq))
headPtr(i) := nextHeadPtr(i)
......@@ -127,7 +128,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
// For branch mis-prediction or memory violation replay,
// we delay updating the indices for one clock cycle.
// For now, we simply use PopCount to count #instr cancelled.
val lastCycleMisprediction = RegNext(io.redirect.valid && !io.redirect.bits.isUnconditional())
val lastCycleMisprediction = RegNext(io.redirect.valid)
// find the last one's position, starting from headPtr and searching backwards
val validBitVec = VecInit((0 until size).map(i => stateEntries(i) === s_valid))
val loValidBitVec = Cat((0 until size).map(i => validBitVec(i) && headPtrMask(i)))
......@@ -140,8 +141,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
// enqueue
val numEnq = Mux(io.enq.canAccept, PopCount(io.enq.req.map(_.valid)), 0.U)
val exceptionValid = io.redirect.valid && io.redirect.bits.isUnconditional()
tailPtr(0) := Mux(exceptionValid,
tailPtr(0) := Mux(io.flush,
0.U.asTypeOf(new CircularQueuePtr(size)),
Mux(io.redirect.valid,
tailPtr(0),
......@@ -149,10 +149,10 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
Mux(isTrueEmpty, headPtr(0), walkedTailPtr),
tailPtr(0) + numEnq))
)
val lastCycleException = RegNext(exceptionValid)
val lastCycleException = RegNext(io.flush)
val lastLastCycleMisprediction = RegNext(lastCycleMisprediction)
for (i <- 1 until enqnum) {
tailPtr(i) := Mux(exceptionValid,
tailPtr(i) := Mux(io.flush,
i.U.asTypeOf(new CircularQueuePtr(size)),
Mux(io.redirect.valid,
tailPtr(i),
......@@ -163,7 +163,7 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
}
// update valid counter and allowEnqueue reg
validCounter := Mux(exceptionValid,
validCounter := Mux(io.flush,
0.U,
Mux(io.redirect.valid,
validCounter,
......
......@@ -15,7 +15,6 @@ class AluExeUnit extends Exu(aluExeUnitCfg)
io.toInt.bits.redirectValid := alu.redirectOutValid
io.toInt.bits.redirect := alu.redirectOut
io.toInt.bits.brUpdate := alu.brUpdate
XSDebug(io.fromInt.valid || io.redirect.valid,
p"fromInt(${io.fromInt.valid} ${io.fromInt.ready}) toInt(${io.toInt.valid} ${io.toInt.ready})" +
......
......@@ -82,6 +82,7 @@ abstract class Exu(val config: ExuConfig) extends XSModule {
val fromInt = if (config.readIntRf) Flipped(DecoupledIO(new ExuInput)) else null
val fromFp = if (config.readFpRf) Flipped(DecoupledIO(new ExuInput)) else null
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
val toInt = if (config.writeIntRf) DecoupledIO(new ExuOutput) else null
val toFp = if (config.writeFpRf) DecoupledIO(new ExuOutput) else null
})
......@@ -106,13 +107,14 @@ abstract class Exu(val config: ExuConfig) extends XSModule {
if (fuCfg.srcCnt > 0) {
fu.io.in.bits.src(0) := src1
}
if (fuCfg.srcCnt > 1) {
if (fuCfg.srcCnt > 1 || fuCfg == jmpCfg) { // jump is special for jalr target
fu.io.in.bits.src(1) := src2
}
if (fuCfg.srcCnt > 2) {
fu.io.in.bits.src(2) := src3
}
fu.io.redirectIn := io.redirect
fu.io.flushIn := io.flush
}
......@@ -187,7 +189,6 @@ abstract class Exu(val config: ExuConfig) extends XSModule {
}
def assignDontCares(out: ExuOutput) = {
out.brUpdate := DontCare
out.fflags := DontCare
out.debug <> DontCare
out.debug.isMMIO := false.B
......
......@@ -19,6 +19,7 @@ class FmacExeUnit extends Exu(fmacExeUnitCfg)
fma.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
fma.io.redirectIn := io.redirect
fma.io.flushIn := io.flush
fma.io.out.ready := io.toFp.ready
io.toFp.bits.data := box(fma.io.out.bits.data, fma.io.out.bits.uop.ctrl.fpu.typeTagOut)
......
......@@ -7,6 +7,7 @@ import xiangshan._
import xiangshan.backend.exu.Exu.jumpExeUnitCfg
import xiangshan.backend.fu.fpu.IntToFP
import xiangshan.backend.fu.{CSR, Fence, FenceToSbuffer, FunctionUnit, Jump}
import xiangshan.backend.roq.RoqExceptionInfo
class JumpExeUnit extends Exu(jumpExeUnitCfg)
{
......@@ -14,9 +15,9 @@ class JumpExeUnit extends Exu(jumpExeUnitCfg)
val fflags = Flipped(ValidIO(UInt(5.W)))
val dirty_fs = Input(Bool())
val frm = Output(UInt(3.W))
val exception = Flipped(ValidIO(new MicroOp))
val isInterrupt = Input(Bool())
val exception = Flipped(ValidIO(new RoqExceptionInfo))
val trapTarget = Output(UInt(VAddrBits.W))
val isXRet = Output(Bool())
val interrupt = Output(Bool())
val memExceptionVAddr = Input(UInt(VAddrBits.W))
val externalInterrupt = new ExternalInterruptIO
......@@ -76,8 +77,8 @@ class JumpExeUnit extends Exu(jumpExeUnitCfg)
csr.csrio.fpu.dirty_fs <> csrio.dirty_fs
csr.csrio.fpu.frm <> csrio.frm
csr.csrio.exception <> csrio.exception
csr.csrio.isInterrupt <> csrio.isInterrupt
csr.csrio.trapTarget <> csrio.trapTarget
csr.csrio.isXRet <> csrio.isXRet
csr.csrio.interrupt <> csrio.interrupt
csr.csrio.memExceptionVAddr <> csrio.memExceptionVAddr
csr.csrio.externalInterrupt <> csrio.externalInterrupt
......@@ -98,18 +99,7 @@ class JumpExeUnit extends Exu(jumpExeUnitCfg)
val isDouble = !uop.ctrl.isRVF
when(csr.io.out.valid){
io.toInt.bits.redirectValid := csr.csrio.redirectOut.valid
io.toInt.bits.redirect.brTag := uop.brTag
io.toInt.bits.redirect.level := RedirectLevel.flushAfter
io.toInt.bits.redirect.interrupt := DontCare
io.toInt.bits.redirect.roqIdx := uop.roqIdx
io.toInt.bits.redirect.target := csr.csrio.redirectOut.bits
io.toInt.bits.redirect.pc := uop.cf.pc
io.toInt.bits.debug.isPerfCnt := csr.csrio.isPerfCnt
}.elsewhen(jmp.io.out.valid){
io.toInt.bits.redirectValid := jmp.redirectOutValid
io.toInt.bits.redirect := jmp.redirectOut
io.toInt.bits.brUpdate := jmp.brUpdate
}
io.toInt.bits.redirectValid := jmp.redirectOutValid
io.toInt.bits.redirect := jmp.redirectOut
}
......@@ -65,12 +65,11 @@ class MulDivExeUnit extends Exu(mulDivExeUnitCfg) {
div.ctrl.isW := isW
div.ctrl.sign := isDivSign
XSDebug(io.fromInt.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d) brTag:%x\n",
XSDebug(io.fromInt.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d)\n",
io.fromInt.valid, io.fromInt.ready,
io.toInt.valid, io.toInt.ready,
io.redirect.valid,
io.redirect.bits.level,
io.redirect.bits.brTag.value
io.redirect.bits.level
)
XSDebug(io.fromInt.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.fromInt.bits.uop.cf.pc)
XSDebug(io.toInt.valid, "Out(%d %d) res:%x pc:%x\n",
......
package xiangshan.backend.ftq
import chisel3._
import chisel3.util._
import utils.{CircularQueuePtr, DataModuleTemplate, HasCircularQueuePtrHelper, SRAMTemplate, XSDebug, XSPerf}
import xiangshan._
import xiangshan.frontend.{GlobalHistory, RASEntry}
class FtqPtr extends CircularQueuePtr(FtqPtr.FtqSize) with HasCircularQueuePtrHelper
object FtqPtr extends HasXSParameter {
def apply(f: Bool, v: UInt): FtqPtr = {
val ptr = Wire(new FtqPtr)
ptr.flag := f
ptr.value := v
ptr
}
}
object GetPcByFtq extends HasXSParameter {
def apply(ftqPC: UInt, ftqOffset: UInt, hasLastPrev: Bool) = {
assert(ftqPC.getWidth == VAddrBits)
assert(ftqOffset.getWidth == log2Up(PredictWidth))
val idxBits = ftqPC.head(VAddrBits - ftqOffset.getWidth - instOffsetBits)
val selLastPacket = hasLastPrev && (ftqOffset === 0.U)
val packetIdx = Mux(selLastPacket, idxBits - 1.U, idxBits)
Cat(
packetIdx, // packet pc
Mux(selLastPacket, Fill(ftqOffset.getWidth, 1.U(1.W)), ftqOffset),
0.U(instOffsetBits.W)
)
}
}
class FtqNRSRAM[T <: Data](gen: T, numRead: Int) extends XSModule {
val io = IO(new Bundle() {
val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
val ren = Input(Vec(numRead, Bool()))
val rdata = Output(Vec(numRead, gen))
val waddr = Input(UInt(log2Up(FtqSize).W))
val wen = Input(Bool())
val wdata = Input(gen)
})
for(i <- 0 until numRead){
val sram = Module(new SRAMTemplate(gen, FtqSize))
sram.io.r.req.valid := io.ren(i)
sram.io.r.req.bits.setIdx := io.raddr(i)
io.rdata(i) := sram.io.r.resp.data(0)
sram.io.w.req.valid := io.wen
sram.io.w.req.bits.setIdx := io.waddr
sram.io.w.req.bits.data := io.wdata
}
}
class Ftq_4R_SRAMEntry extends XSBundle {
val ftqPC = UInt(VAddrBits.W)
val hasLastPrev = Bool()
}
// redirect and commit need read these infos
class Ftq_2R_SRAMEntry extends XSBundle {
val rasSp = UInt(log2Ceil(RasSize).W)
val rasEntry = new RASEntry
val hist = new GlobalHistory
val predHist = new GlobalHistory
val specCnt = Vec(PredictWidth, UInt(10.W))
val br_mask = Vec(PredictWidth, Bool())
}
class Ftq_1R_Commit_SRAMEntry extends XSBundle {
val metas = Vec(PredictWidth, new BpuMeta)
val rvc_mask = Vec(PredictWidth, Bool())
}
class FtqRead extends Bundle {
val ptr = Output(new FtqPtr)
val entry = Input(new FtqEntry)
}
class Ftq extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new Bundle() {
val enq = Flipped(DecoupledIO(new FtqEntry))
val leftOne = Output(Bool())
val enqPtr = Output(new FtqPtr)
// roq commit, read out fectch packet and deq
val roq_commits = Vec(CommitWidth, Flipped(ValidIO(new RoqCommitInfo)))
val commit_ftqEntry = ValidIO(new FtqEntry)
// redirect, reset enq ptr
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
val flushIdx = Input(new FtqPtr)
val flushOffset = Input(UInt(log2Up(PredictWidth).W))
// update mispredict target
val frontendRedirect = Flipped(ValidIO(new Redirect))
// exu write back, update info
val exuWriteback = Vec(exuParameters.JmpCnt + exuParameters.AluCnt, Flipped(ValidIO(new ExuOutput)))
// pc read reqs (0: jump/auipc 1: mispredict/load replay 2: exceptions)
val ftqRead = Vec(3, Flipped(new FtqRead))
})
val headPtr, tailPtr = RegInit(FtqPtr(false.B, 0.U))
val validEntries = distanceBetween(tailPtr, headPtr)
// enq
io.leftOne := validEntries === (FtqSize - 1).U
io.enq.ready := validEntries < FtqSize.U
io.enqPtr := tailPtr
val stage2Flush = io.redirect.valid || io.flush
val stage3Flush = RegNext(stage2Flush)
val real_fire = io.enq.fire() && !stage2Flush && !stage3Flush
val ftq_4r_sram = Module(new FtqNRSRAM(new Ftq_4R_SRAMEntry, 4))
ftq_4r_sram.io.wen := real_fire
ftq_4r_sram.io.waddr := tailPtr.value
ftq_4r_sram.io.wdata.ftqPC := io.enq.bits.ftqPC
ftq_4r_sram.io.wdata.hasLastPrev := io.enq.bits.hasLastPrev
val ftq_2r_sram = Module(new FtqNRSRAM(new Ftq_2R_SRAMEntry, 2))
ftq_2r_sram.io.wen := real_fire
ftq_2r_sram.io.waddr := tailPtr.value
ftq_2r_sram.io.wdata.rasSp := io.enq.bits.rasSp
ftq_2r_sram.io.wdata.rasEntry := io.enq.bits.rasTop
ftq_2r_sram.io.wdata.hist := io.enq.bits.hist
ftq_2r_sram.io.wdata.predHist := io.enq.bits.predHist
ftq_2r_sram.io.wdata.specCnt := io.enq.bits.specCnt
ftq_2r_sram.io.wdata.br_mask := io.enq.bits.br_mask
val pred_target_sram = Module(new FtqNRSRAM(UInt(VAddrBits.W), 1))
pred_target_sram.io.wen := real_fire
pred_target_sram.io.waddr := tailPtr.value
pred_target_sram.io.wdata := io.enq.bits.target
val ftq_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_Commit_SRAMEntry, 1))
ftq_1r_sram.io.wen := real_fire
ftq_1r_sram.io.waddr := tailPtr.value
ftq_1r_sram.io.wdata.metas := io.enq.bits.metas
ftq_1r_sram.io.wdata.rvc_mask := io.enq.bits.rvc_mask
// multi-write
val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W)))
val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Up(PredictWidth).W))))
val cfiIsCall, cfiIsRet, cfiIsRVC = Reg(Vec(FtqSize, Bool()))
val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
val s_invalid :: s_valid :: s_commited :: Nil = Enum(3)
val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
VecInit(Seq.fill(PredictWidth)(s_invalid))
}))
when(real_fire) {
val enqIdx = tailPtr.value
commitStateQueue(enqIdx) := VecInit(io.enq.bits.valids.map(v => Mux(v, s_valid, s_invalid)))
cfiIndex_vec(enqIdx) := io.enq.bits.cfiIndex
cfiIsCall(enqIdx) := io.enq.bits.cfiIsCall
cfiIsRet(enqIdx) := io.enq.bits.cfiIsRet
cfiIsRVC(enqIdx) := io.enq.bits.cfiIsRVC
mispredict_vec(enqIdx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
update_target(enqIdx) := io.enq.bits.target
}
tailPtr := tailPtr + real_fire
// exu write back, update some info
for ((wb, i) <- io.exuWriteback.zipWithIndex) {
val wbIdx = wb.bits.redirect.ftqIdx.value
val offset = wb.bits.redirect.ftqOffset
val cfiUpdate = wb.bits.redirect.cfiUpdate
when(wb.bits.redirectValid) {
mispredict_vec(wbIdx)(offset) := cfiUpdate.isMisPred
when(cfiUpdate.taken && offset < cfiIndex_vec(wbIdx).bits) {
cfiIndex_vec(wbIdx).bits := offset
cfiIsCall(wbIdx) := wb.bits.uop.cf.pd.isCall
cfiIsRet(wbIdx) := wb.bits.uop.cf.pd.isRet
cfiIsRVC(wbIdx) := wb.bits.uop.cf.pd.isRVC
}
when (offset === cfiIndex_vec(wbIdx).bits) {
cfiIndex_vec(wbIdx).valid := cfiUpdate.taken
}
}
}
// fix mispredict entry
val lastIsMispredict = RegNext(
io.redirect.valid && io.redirect.bits.level === RedirectLevel.flushAfter, init = false.B
)
when(io.frontendRedirect.valid && lastIsMispredict) {
update_target(io.frontendRedirect.bits.ftqIdx.value) := io.frontendRedirect.bits.cfiUpdate.target
}
// commit
for (c <- io.roq_commits) {
when(c.valid) {
commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := s_commited
}
}
val headClear = Cat(commitStateQueue(headPtr.value).map(s => s === s_invalid)).andR()
when(headClear && headPtr =/= tailPtr) {
headPtr := headPtr + 1.U
}
ftq_4r_sram.io.raddr(0) := headPtr.value
ftq_4r_sram.io.ren(0) := true.B
ftq_2r_sram.io.raddr(0) := headPtr.value
ftq_2r_sram.io.ren(0) := true.B
ftq_1r_sram.io.raddr(0) := headPtr.value
ftq_1r_sram.io.ren(0) := true.B
val commitEntry = Wire(new FtqEntry)
val commit_valids = VecInit(commitStateQueue(headPtr.value).map(s => s === s_commited))
// set state to invalid next cycle
commitStateQueue(headPtr.value).zip(commit_valids).foreach({ case (s, v) => when(v) {
s := s_invalid
}
})
// from 4r sram
commitEntry.ftqPC := ftq_4r_sram.io.rdata(0).ftqPC
commitEntry.hasLastPrev := ftq_4r_sram.io.rdata(0).hasLastPrev
// from 2r sram
commitEntry.rasSp := ftq_2r_sram.io.rdata(0).rasSp
commitEntry.rasTop := ftq_2r_sram.io.rdata(0).rasEntry
commitEntry.hist := ftq_2r_sram.io.rdata(0).hist
commitEntry.predHist := ftq_2r_sram.io.rdata(0).predHist
commitEntry.specCnt := ftq_2r_sram.io.rdata(0).specCnt
commitEntry.br_mask := ftq_2r_sram.io.rdata(0).br_mask
// from 1r sram
commitEntry.metas := ftq_1r_sram.io.rdata(0).metas
commitEntry.rvc_mask := ftq_1r_sram.io.rdata(0).rvc_mask
// from regs
commitEntry.valids := RegNext(commit_valids)
commitEntry.mispred := RegNext(mispredict_vec(headPtr.value))
commitEntry.cfiIndex := RegNext(cfiIndex_vec(headPtr.value))
commitEntry.cfiIsCall := RegNext(cfiIsCall(headPtr.value))
commitEntry.cfiIsRet := RegNext(cfiIsRet(headPtr.value))
commitEntry.cfiIsRVC := RegNext(cfiIsRVC(headPtr.value))
commitEntry.target := RegNext(update_target(headPtr.value))
io.commit_ftqEntry.valid := RegNext(Cat(commit_valids).orR()) //TODO: do we need this?
io.commit_ftqEntry.bits := commitEntry
// read logic
for ((req, i) <- io.ftqRead.zipWithIndex) {
req.entry := DontCare
ftq_4r_sram.io.raddr(1 + i) := req.ptr.value
ftq_4r_sram.io.ren(1 + i) := true.B
req.entry.ftqPC := ftq_4r_sram.io.rdata(1 + i).ftqPC
req.entry.hasLastPrev := ftq_4r_sram.io.rdata(1 + i).hasLastPrev
if(i == 0){ // jump, read npc
pred_target_sram.io.raddr(0) := req.ptr.value
pred_target_sram.io.ren(0) := true.B
req.entry.target := pred_target_sram.io.rdata(0)
}
if(i == 1){ // mispredict, read more info
ftq_2r_sram.io.raddr(1) := req.ptr.value
ftq_2r_sram.io.ren(1) := true.B
req.entry.rasTop := ftq_2r_sram.io.rdata(1).rasEntry
req.entry.hist := ftq_2r_sram.io.rdata(1).hist
req.entry.predHist := ftq_2r_sram.io.rdata(1).predHist
req.entry.specCnt := ftq_2r_sram.io.rdata(1).specCnt
req.entry.br_mask := ftq_2r_sram.io.rdata(1).br_mask
}
}
// redirect, reset ptr
when(io.flush || io.redirect.valid){
val idx = Mux(io.flush, io.flushIdx, io.redirect.bits.ftqIdx)
val next = io.redirect.bits.ftqIdx + 1.U
tailPtr := next
val offset = Mux(io.flush, io.flushOffset, io.redirect.bits.ftqOffset)
val notMisPredict = io.flush || (io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level))
commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
when(i.U > offset || (notMisPredict && i.U === offset)){
s := s_invalid
}
})
commitStateQueue(next.value).foreach(_ := s_invalid)
}
XSPerf("ftqEntries", validEntries)
XSPerf("ftqStallAcc", io.enq.valid && !io.enq.ready, acc = true)
XSPerf("mispredictRedirectAcc", io.redirect.valid && RedirectLevel.flushAfter === io.redirect.bits.level, acc = true)
XSPerf("replayRedirectAcc", io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level), acc = true)
XSDebug(io.commit_ftqEntry.valid, p"ftq commit: ${io.commit_ftqEntry.bits}")
XSDebug(io.enq.fire(), p"ftq enq: ${io.enq.bits}")
}
......@@ -58,7 +58,7 @@ class Alu extends FunctionUnit with HasRedirectOut {
)
val isBranch = ALUOpType.isBranch(func)
val isRVC = uop.cf.brUpdate.pd.isRVC
val isRVC = uop.cf.pd.isRVC
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = (pc + offset)(VAddrBits-1,0)
val snpc = Mux(isRVC, pc + 2.U, pc + 4.U)
......@@ -67,26 +67,13 @@ class Alu extends FunctionUnit with HasRedirectOut {
// Only brTag, level, roqIdx are needed
// other infos are stored in brq
redirectOut := DontCare
redirectOut.brTag := uop.brTag
redirectOut.level := RedirectLevel.flushAfter
redirectOut.roqIdx := uop.roqIdx
// redirectOut.pc := DontCare//uop.cf.pc
// redirectOut.target := DontCare//Mux(!taken && isBranch, snpc, target)
// redirectOut.interrupt := DontCare//DontCare
// Only taken really needed, do we need brTag ?
brUpdate := DontCare
brUpdate.taken := isBranch && taken
brUpdate.brTag := uop.brTag
// brUpdate := uop.cf.brUpdate
// // override brUpdate
// brUpdate.pc := uop.cf.pc
// brUpdate.target := Mux(!taken && isBranch, snpc, target)
// brUpdate.brTarget := target
// brUpdate.taken := isBranch && taken
// brUpdate.brTag := uop.brTag
redirectOut.ftqIdx := uop.cf.ftqPtr
redirectOut.ftqOffset := uop.cf.ftqOffset
redirectOut.cfiUpdate.isMisPred := (uop.cf.pred_taken ^ taken) && isBranch
redirectOut.cfiUpdate.taken := taken
redirectOut.cfiUpdate.predTaken := uop.cf.pred_taken
io.in.ready := io.out.ready
io.out.valid := valid
......
......@@ -7,7 +7,7 @@ import utils._
import xiangshan._
import xiangshan.backend._
import xiangshan.backend.fu.util._
import utils.XSDebug
import xiangshan.backend.roq.RoqExceptionInfo
object hartId extends (() => Int) {
var x = 0
......@@ -127,15 +127,14 @@ class CSR extends FunctionUnit with HasCSRConst
{
val csrio = IO(new Bundle {
// output (for func === CSROpType.jmp)
val redirectOut = ValidIO(UInt(VAddrBits.W))
val perf = new PerfCounterIO
val isPerfCnt = Output(Bool())
// to FPU
val fpu = Flipped(new FpuCsrIO)
// from rob
val exception = Flipped(ValidIO(new MicroOp))
val isInterrupt = Input(Bool())
val exception = Flipped(ValidIO(new RoqExceptionInfo))
// to ROB
val isXRet = Output(Bool())
val trapTarget = Output(UInt(VAddrBits.W))
val interrupt = Output(Bool())
// from LSQ
......@@ -614,10 +613,7 @@ class CSR extends FunctionUnit with HasCSRConst
// Branch control
val retTarget = Wire(UInt(VAddrBits.W))
val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
csrio.redirectOut.valid := valid && func === CSROpType.jmp && !isEcall
csrio.redirectOut.bits := retTarget
flushPipe := resetSatp
XSDebug(csrio.redirectOut.valid, "redirect to %x, pc=%x\n", csrio.redirectOut.bits, cfIn.pc)
flushPipe := resetSatp || (valid && func === CSROpType.jmp && !isEcall)
retTarget := DontCare
// val illegalEret = TODO
......@@ -659,11 +655,6 @@ class CSR extends FunctionUnit with HasCSRConst
retTarget := uepc(VAddrBits-1, 0)
}
XSDebug(csrio.redirectOut.valid,
"Rediret %x isSret:%d retTarget:%x sepc:%x cfInpc:%x valid:%d\n",
csrio.redirectOut.bits, isSret, retTarget, sepc, cfIn.pc, valid
)
io.in.ready := true.B
io.out.valid := valid
......@@ -697,31 +688,31 @@ class CSR extends FunctionUnit with HasCSRConst
// interrupts
val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum))
val raiseIntr = csrio.exception.valid && csrio.isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", csrio.exception.bits.cf.pc, intrNO)
val raiseIntr = csrio.exception.valid && csrio.exception.bits.isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", csrio.exception.bits.uop.cf.pc, intrNO)
// exceptions
val raiseException = csrio.exception.valid && !csrio.isInterrupt
val hasInstrPageFault = csrio.exception.bits.cf.exceptionVec(instrPageFault) && raiseException
val hasLoadPageFault = csrio.exception.bits.cf.exceptionVec(loadPageFault) && raiseException
val hasStorePageFault = csrio.exception.bits.cf.exceptionVec(storePageFault) && raiseException
val hasStoreAddrMisaligned = csrio.exception.bits.cf.exceptionVec(storeAddrMisaligned) && raiseException
val hasLoadAddrMisaligned = csrio.exception.bits.cf.exceptionVec(loadAddrMisaligned) && raiseException
val hasInstrAccessFault = csrio.exception.bits.cf.exceptionVec(instrAccessFault) && raiseException
val hasLoadAccessFault = csrio.exception.bits.cf.exceptionVec(loadAccessFault) && raiseException
val hasStoreAccessFault = csrio.exception.bits.cf.exceptionVec(storeAccessFault) && raiseException
val raiseExceptionVec = csrio.exception.bits.cf.exceptionVec
val raiseException = csrio.exception.valid && !csrio.exception.bits.isInterrupt
val hasInstrPageFault = csrio.exception.bits.uop.cf.exceptionVec(instrPageFault) && raiseException
val hasLoadPageFault = csrio.exception.bits.uop.cf.exceptionVec(loadPageFault) && raiseException
val hasStorePageFault = csrio.exception.bits.uop.cf.exceptionVec(storePageFault) && raiseException
val hasStoreAddrMisaligned = csrio.exception.bits.uop.cf.exceptionVec(storeAddrMisaligned) && raiseException
val hasLoadAddrMisaligned = csrio.exception.bits.uop.cf.exceptionVec(loadAddrMisaligned) && raiseException
val hasInstrAccessFault = csrio.exception.bits.uop.cf.exceptionVec(instrAccessFault) && raiseException
val hasLoadAccessFault = csrio.exception.bits.uop.cf.exceptionVec(loadAccessFault) && raiseException
val hasStoreAccessFault = csrio.exception.bits.uop.cf.exceptionVec(storeAccessFault) && raiseException
val raiseExceptionVec = csrio.exception.bits.uop.cf.exceptionVec
val exceptionNO = ExcPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(raiseExceptionVec(i), i.U, sum))
val causeNO = (raiseIntr << (XLEN-1)).asUInt() | Mux(raiseIntr, intrNO, exceptionNO)
val raiseExceptionIntr = csrio.exception.valid
XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n",
csrio.exception.bits.cf.pc, intrNO, intrVec, exceptionNO, raiseExceptionVec.asUInt
csrio.exception.bits.uop.cf.pc, intrNO, intrVec, exceptionNO, raiseExceptionVec.asUInt
)
XSDebug(raiseExceptionIntr,
"pc %x mstatus %x mideleg %x medeleg %x mode %x\n",
csrio.exception.bits.cf.pc,
csrio.exception.bits.uop.cf.pc,
mstatus,
mideleg,
medeleg,
......@@ -734,9 +725,9 @@ class CSR extends FunctionUnit with HasCSRConst
val tval = Mux(
hasInstrPageFault,
Mux(
csrio.exception.bits.cf.crossPageIPFFix,
SignExt(csrio.exception.bits.cf.pc + 2.U, XLEN),
SignExt(csrio.exception.bits.cf.pc, XLEN)
csrio.exception.bits.uop.cf.crossPageIPFFix,
SignExt(csrio.exception.bits.uop.cf.pc + 2.U, XLEN),
SignExt(csrio.exception.bits.uop.cf.pc, XLEN)
),
memExceptionAddr
)
......@@ -753,9 +744,14 @@ class CSR extends FunctionUnit with HasCSRConst
val deleg = Mux(raiseIntr, mideleg , medeleg)
// val delegS = ((deleg & (1 << (causeNO & 0xf))) != 0) && (priviledgeMode < ModeM);
val delegS = (deleg(causeNO(3,0))) && (priviledgeMode < ModeM)
val delegS = deleg(causeNO(3,0)) && (priviledgeMode < ModeM)
val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check
csrio.trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
val isXRet = func === CSROpType.jmp && !isEcall
csrio.isXRet := RegNext(isXRet)
csrio.trapTarget := RegNext(Mux(csrio.isXRet,
retTarget,
Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
))
when (raiseExceptionIntr) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
......@@ -763,7 +759,7 @@ class CSR extends FunctionUnit with HasCSRConst
when (delegS) {
scause := causeNO
sepc := SignExt(csrio.exception.bits.cf.pc, XLEN)
sepc := SignExt(csrio.exception.bits.uop.cf.pc, XLEN)
mstatusNew.spp := priviledgeMode
mstatusNew.pie.s := mstatusOld.ie.s
mstatusNew.ie.s := false.B
......@@ -771,7 +767,7 @@ class CSR extends FunctionUnit with HasCSRConst
when (tvalWen) { stval := 0.U }
}.otherwise {
mcause := causeNO
mepc := SignExt(csrio.exception.bits.cf.pc, XLEN)
mepc := SignExt(csrio.exception.bits.uop.cf.pc, XLEN)
mstatusNew.mpp := priviledgeMode
mstatusNew.pie.m := mstatusOld.ie.m
mstatusNew.ie.m := false.B
......@@ -782,11 +778,6 @@ class CSR extends FunctionUnit with HasCSRConst
mstatus := mstatusNew.asUInt
}
XSDebug(raiseExceptionIntr && delegS,
"Red(%d, %x) raiseExcepIntr:%d isSret:%d sepc:%x delegs:%d deleg:%x\n",
csrio.redirectOut.valid, csrio.redirectOut.bits, raiseExceptionIntr,
isSret, sepc, delegS, deleg
)
XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc)
......
......@@ -50,6 +50,7 @@ class FunctionUnitIO(val len: Int) extends XSBundle {
val out = DecoupledIO(new FuOutput(len))
val redirectIn = Flipped(ValidIO(new Redirect))
val flushIn = Input(Bool())
}
abstract class FunctionUnit(len: Int = 64) extends XSModule {
......@@ -71,7 +72,7 @@ trait HasPipelineReg {
// if flush(0), valid 0 will not given, so set flushVec(0) to false.B
val flushVec = validVec.zip(uopVec).map(x => x._1 && x._2.roqIdx.needFlush(io.redirectIn))
val flushVec = validVec.zip(uopVec).map(x => x._1 && x._2.roqIdx.needFlush(io.redirectIn, io.flushIn))
for (i <- 0 until latency) {
rdyVec(i) := !validVec(i + 1) || rdyVec(i + 1)
......
......@@ -12,16 +12,16 @@ import xiangshan.backend.decode.isa._
trait HasRedirectOut { this: RawModule =>
val redirectOutValid = IO(Output(Bool()))
val redirectOut = IO(Output(new Redirect))
val brUpdate = IO(Output(new CfiUpdateInfo))
}
class Jump extends FunctionUnit with HasRedirectOut {
val (src1, immMin, func, pc, uop) = (
val (src1, jalr_target, pc, immMin, func, uop) = (
io.in.bits.src(0),
io.in.bits.src(1)(VAddrBits - 1, 0),
io.in.bits.uop.cf.pc,
io.in.bits.uop.ctrl.imm,
io.in.bits.uop.ctrl.fuOpType,
SignExt(io.in.bits.uop.cf.pc, AddrBits),
io.in.bits.uop
)
......@@ -33,27 +33,25 @@ class Jump extends FunctionUnit with HasRedirectOut {
!(isJalr || isAuipc) -> ImmUnion.J.toImm32(immMin)
)), XLEN)
val redirectHit = uop.roqIdx.needFlush(io.redirectIn)
val redirectHit = uop.roqIdx.needFlush(io.redirectIn, io.flushIn)
val valid = io.in.valid
val isRVC = uop.cf.brUpdate.pd.isRVC
val isRVC = uop.cf.pd.isRVC
val snpc = Mux(isRVC, pc + 2.U, pc + 4.U)
val target = src1 + offset // NOTE: src1 is (pc/rf(rs1)), src2 is (offset)
redirectOutValid := valid
redirectOutValid := valid && !isAuipc
redirectOut := DontCare
// redirectOut.pc := uop.cf.pc
redirectOut.target := target
redirectOut.brTag := uop.brTag
redirectOut.cfiUpdate.target := target
redirectOut.level := RedirectLevel.flushAfter
// redirectOut.interrupt := DontCare
redirectOut.roqIdx := uop.roqIdx
redirectOut.ftqIdx := uop.cf.ftqPtr
redirectOut.ftqOffset := uop.cf.ftqOffset
redirectOut.cfiUpdate.predTaken := true.B
redirectOut.cfiUpdate.taken := true.B
redirectOut.cfiUpdate.target := target
redirectOut.cfiUpdate.isMisPred := target =/= jalr_target
brUpdate := DontCare //uop.cf.brUpdate
// brUpdate.pc := uop.cf.pc
brUpdate.target := target
brUpdate.brTarget := target
brUpdate.taken := true.B
// Output
val res = Mux(JumpOpType.jumpOpisAuipc(func), target, snpc)
......@@ -64,15 +62,14 @@ class Jump extends FunctionUnit with HasRedirectOut {
io.out.bits.data := res
// NOTE: the debug info is for one-cycle exec, if FMV needs multi-cycle, may needs change it
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d)\n",
io.in.valid,
io.in.ready,
io.out.valid,
io.out.ready,
io.redirectIn.valid,
io.redirectIn.bits.level,
redirectHit,
io.redirectIn.bits.brTag.value
redirectHit
)
XSDebug(io.in.valid, "src1:%x offset:%x func:%b type:JUMP pc:%x res:%x\n", src1, offset, func, pc, res)
}
......@@ -41,7 +41,7 @@ class Radix2Divider(len: Int) extends AbstractDivider(len) {
val uopReg = RegEnable(uop, newReq)
val cnt = Counter(len)
when (newReq && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn)) {
when (newReq && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn, io.flushIn)) {
state := s_log2
} .elsewhen (state === s_log2) {
// `canSkipShift` is calculated as following:
......@@ -71,7 +71,7 @@ class Radix2Divider(len: Int) extends AbstractDivider(len) {
}
}
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn, io.flushIn)
when(kill){
state := s_idle
}
......@@ -87,4 +87,4 @@ class Radix2Divider(len: Int) extends AbstractDivider(len) {
io.out.valid := state === s_finish
io.in.ready := state === s_idle
}
\ No newline at end of file
}
......@@ -33,11 +33,11 @@ class SRT4Divider(len: Int) extends AbstractDivider(len) {
val divZero = b === 0.U
val divZeroReg = RegEnable(divZero, newReq)
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn, io.flushIn)
switch(state){
is(s_idle){
when (io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn)) {
when (io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn, io.flushIn)) {
state := Mux(divZero, s_finish, s_lzd)
}
}
......
......@@ -18,12 +18,12 @@ class FDivSqrt extends FPUSubModule {
val uopReg = RegEnable(io.in.bits.uop, io.in.fire())
val single = RegEnable(tag === S, io.in.fire())
val rmReg = RegEnable(rm, io.in.fire())
val kill = uopReg.roqIdx.needFlush(io.redirectIn)
val kill = uopReg.roqIdx.needFlush(io.redirectIn, io.flushIn)
val killReg = RegInit(false.B)
switch(state){
is(s_idle){
when(io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn)){ state := s_div }
when(io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn, io.flushIn)){ state := s_div }
}
is(s_div){
when(divSqrtRawValid){
......@@ -47,7 +47,7 @@ class FDivSqrt extends FPUSubModule {
val src1 = unbox(io.in.bits.src(0), tag, None)
val src2 = unbox(io.in.bits.src(1), tag, None)
divSqrt.io.inValid := io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn)
divSqrt.io.inValid := io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn, io.flushIn)
divSqrt.io.sqrtOp := fpCtrl.sqrt
divSqrt.io.a := src1
divSqrt.io.b := src2
......
......@@ -21,7 +21,7 @@ class IntToFP extends FPUSubModule {
switch(state){
is(s_idle){
when(io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn)){
when(io.in.fire() && !io.in.bits.uop.roqIdx.needFlush(io.redirectIn, io.flushIn)){
state := s_cvt
}
}
......@@ -34,7 +34,7 @@ class IntToFP extends FPUSubModule {
}
}
}
when(state =/= s_idle && uopReg.roqIdx.needFlush(io.redirectIn)){
when(state =/= s_idle && uopReg.roqIdx.needFlush(io.redirectIn, io.flushIn)){
state := s_idle
}
......
......@@ -16,6 +16,7 @@ class BypassQueue(number: Int) extends XSModule {
val in = Flipped(ValidIO(new MicroOp))
val out = ValidIO(new MicroOp)
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
})
if (number < 0) {
io.out.valid := false.B
......@@ -29,11 +30,11 @@ class BypassQueue(number: Int) extends XSModule {
val valid = Bool()
val bits = new MicroOp
})))
queue(0).valid := io.in.valid && !io.in.bits.roqIdx.needFlush(io.redirect)
queue(0).valid := io.in.valid && !io.in.bits.roqIdx.needFlush(io.redirect, io.flush)
queue(0).bits := io.in.bits
(0 until (number-1)).map{i =>
queue(i+1) := queue(i)
queue(i+1).valid := queue(i).valid && !queue(i).bits.roqIdx.needFlush(io.redirect)
queue(i+1).valid := queue(i).valid && !queue(i).bits.roqIdx.needFlush(io.redirect, io.flush)
}
io.out.valid := queue(number-1).valid
io.out.bits := queue(number-1).bits
......@@ -73,13 +74,14 @@ class ReservationStationCtrl
val iqIdxWidth = log2Up(iqSize)
val fastWakeup = fixedDelay >= 0 // NOTE: if do not enable fastWakeup(bypass), set fixedDelay to -1
val nonBlocked = fastWakeup
val srcNum = max(exuCfg.intSrcCnt, exuCfg.fpSrcCnt)
val srcNum = if (exuCfg == Exu.jumpExeUnitCfg) 2 else max(exuCfg.intSrcCnt, exuCfg.fpSrcCnt)
require(srcNum >= 1 && srcNum <= 3)
println(s"[RsCtrl] ExuConfig: ${exuCfg.name} (srcNum = $srcNum)")
val io = IO(new XSBundle {
// flush
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
// enq Ctrl sigs at dispatch-2, only use srcState
val enqCtrl = Flipped(DecoupledIO(new MicroOp))
......@@ -174,7 +176,7 @@ class ReservationStationCtrl
val bubbleReg = RegNext(bubbleValid)
val bubblePtrReg = RegNext(Mux(moveMask(bubblePtr), bubblePtr-1.U, bubblePtr))
lastbubbleMask := ~Mux(bubbleReg, UIntToOH(bubblePtrReg), 0.U) & (if(feedback) ~(0.U(iqSize.W))
else Mux(RegNext(selectValid && io.redirect.valid), 0.U, ~(0.U(iqSize.W))))
else Mux(RegNext(selectValid && (io.redirect.valid || io.flush)), 0.U, ~(0.U(iqSize.W))))
// deq
val dequeue = if (feedback) bubbleReg
......@@ -231,7 +233,7 @@ class ReservationStationCtrl
// enq
val isFull = tailPtr.flag
// agreement with dispatch: don't fire when io.redirect.valid
val enqueue = io.enqCtrl.fire() && !io.redirect.valid
val enqueue = io.enqCtrl.fire() && !(io.redirect.valid || io.flush)
val tailInc = tailPtr+1.U
val tailDec = tailPtr-1.U
tailPtr := Mux(dequeue === enqueue, tailPtr, Mux(dequeue, tailDec, tailInc))
......@@ -350,13 +352,14 @@ class ReservationStationData
val iqIdxWidth = log2Up(iqSize)
val fastWakeup = fixedDelay >= 0 // NOTE: if do not enable fastWakeup(bypass), set fixedDelay to -1
val nonBlocked = fastWakeup
val srcNum = max(exuCfg.intSrcCnt, exuCfg.fpSrcCnt)
val srcNum = if (exuCfg == Exu.jumpExeUnitCfg) 2 else max(exuCfg.intSrcCnt, exuCfg.fpSrcCnt)
require(srcNum >= 1 && srcNum <= 3)
println(s"[RsData] ExuConfig: ${exuCfg.name} (srcNum = $srcNum)")
val io = IO(new XSBundle {
// flush
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
// send to exu
val deq = DecoupledIO(new ExuInput)
......@@ -367,6 +370,7 @@ class ReservationStationData
// read src op value
val srcRegValue = Vec(srcNum, Input(UInt((XLEN + 1).W)))
val jumpPc = if(exuCfg == Exu.jumpExeUnitCfg) Input(UInt(VAddrBits.W)) else null
val jalr_target = if(exuCfg == Exu.jumpExeUnitCfg) Input(UInt(VAddrBits.W)) else null
// broadcast selected uop to other issue queues
val selectedUop = ValidIO(new MicroOp)
......@@ -391,6 +395,9 @@ class ReservationStationData
// Data : single read, multi write
// ------------------------
val pcMem = if(exuCfg == Exu.jumpExeUnitCfg)
Some(Module(new SyncDataModuleTemplate(UInt(VAddrBits.W), iqSize, numRead = 1, numWrite = 1))) else None
val data = (0 until srcNum).map{i =>
val d = Module(new RSDataSingleSrc(XLEN + 1, iqSize, wakeupCnt + extraListenPortsCnt))
d.suggestName(s"${this.name}_data${i}")
......@@ -446,6 +453,12 @@ class ReservationStationData
p"${enqUop.src3State}|${enqUop.ctrl.src3Type} pc:0x${Hexadecimal(enqUop.cf.pc)} roqIdx:${enqUop.roqIdx}\n")
}
if(pcMem.nonEmpty){
pcMem.get.io.wen(0) := enqEnReg
pcMem.get.io.waddr(0) := enqPtrReg
pcMem.get.io.wdata(0) := io.jumpPc
}
data.map(_.w.addr := enqPtrReg)
data.zip(io.ctrl.enqSrcReady).map{ case (src, ready) => src.w.wen := RegNext(ready && enqEn) }
......@@ -455,9 +468,8 @@ class ReservationStationData
SignExt(io.jumpPc, XLEN),
io.srcRegValue(0)
)
// data.io.w.bits.data(0) := src1Mux
data(0).w.wdata := src1Mux
data(1).w.wdata := io.jalr_target
case Exu.aluExeUnitCfg =>
val src1Mux = Mux(enqUopReg.ctrl.src1Type === SrcType.pc,
SignExt(enqUopReg.cf.pc, XLEN),
......@@ -515,6 +527,10 @@ class ReservationStationData
exuInput := DontCare
exuInput.uop := uop(deq)
exuInput.uop.cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
if(pcMem.nonEmpty){
pcMem.get.io.raddr(0) := sel.bits
exuInput.uop.cf.pc := pcMem.get.io.rdata(0)
}
data.map(_.r.addr := sel.bits)
val regValues = data.map(_.r.rdata)
XSDebug(io.deq.fire(), p"[regValues] " + List.tabulate(srcNum)(idx => p"reg$idx: ${Hexadecimal(regValues(idx))}").reduce((p1, p2) => p1 + " " + p2) + "\n")
......@@ -551,7 +567,7 @@ class ReservationStationData
if (nonBlocked) { io.ctrl.fuReady := true.B }
else { io.ctrl.fuReady := io.deq.ready }
io.ctrl.redirectVec := uop.map(_.roqIdx.needFlush(io.redirect))
io.ctrl.redirectVec := uop.map(_.roqIdx.needFlush(io.redirect, io.flush))
redirectHit := io.ctrl.redirectVec(sel.bits)
io.ctrl.feedback := DontCare
......@@ -573,6 +589,7 @@ class ReservationStationData
bpQueue.io.in.valid := sel.valid // FIXME: error when function is blocked => fu should not be blocked
bpQueue.io.in.bits := uop(sel.bits)
bpQueue.io.redirect := io.redirect
bpQueue.io.flush := io.flush
io.selectedUop.valid := bpQueue.io.out.valid
io.selectedUop.bits := bpQueue.io.out.bits
io.selectedUop.bits.cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
......
......@@ -4,7 +4,6 @@ import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.brq.BrqPtr
trait HasFreeListConsts extends HasXSParameter {
def FL_SIZE: Int = NRPhyRegs-32
......@@ -34,7 +33,8 @@ object FreeListPtr extends HasFreeListConsts {
class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrHelper{
val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
val redirect = Input(Bool())
val flush = Input(Bool())
val req = new Bundle {
// need to alloc (not actually do the allocation)
......@@ -100,16 +100,15 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH
freeRegs := distanceBetween(tailPtr, headPtrNext)
// priority: (1) exception and flushPipe; (2) walking; (3) mis-prediction; (4) normal dequeue
headPtr := Mux(io.redirect.valid && io.redirect.bits.isUnconditional(),
headPtr := Mux(io.flush,
FreeListPtr(!tailPtrNext.flag, tailPtrNext.value),
Mux(io.walk.valid,
headPtr - io.walk.bits,
Mux(io.redirect.valid, headPtr, headPtrNext))
Mux(io.redirect, headPtr, headPtrNext))
)
XSDebug(p"head:$headPtr tail:$tailPtr\n")
XSDebug(io.redirect.valid, p"redirect: brqIdx=${io.redirect.bits.brTag.value}\n")
val enableFreelistCheck = false
if (enableFreelistCheck) {
......
......@@ -16,6 +16,7 @@ class RenameBypassInfo extends XSBundle {
class Rename extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
val roqCommits = Flipped(new RoqCommitIO)
// from decode buffer
val in = Vec(RenameWidth, Flipped(DecoupledIO(new CfCtrl)))
......@@ -47,9 +48,11 @@ class Rename extends XSModule with HasCircularQueuePtrHelper {
val allPhyResource = Seq((intRat, intFreeList, false), (fpRat, fpFreeList, true))
allPhyResource.map{ case (rat, freelist, _) =>
rat.redirect := io.redirect
rat.redirect := io.redirect.valid
rat.flush := io.flush
rat.walkWen := io.roqCommits.isWalk
freelist.redirect := io.redirect
freelist.redirect := io.redirect.valid
freelist.flush := io.flush
freelist.walk.valid := io.roqCommits.isWalk
}
val canOut = io.out(0).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc && !io.roqCommits.isWalk
......@@ -69,10 +72,15 @@ class Rename extends XSModule with HasCircularQueuePtrHelper {
// speculatively assign the instruction with an roqIdx
val validCount = PopCount(io.in.map(_.valid))
val roqIdxHead = RegInit(0.U.asTypeOf(new RoqPtr))
val lastCycleMisprediction = RegNext(io.redirect.valid && !io.redirect.bits.isUnconditional() && !io.redirect.bits.flushItself())
val roqIdxHeadNext = Mux(io.redirect.valid,
Mux(io.redirect.bits.isUnconditional(), 0.U.asTypeOf(new RoqPtr), io.redirect.bits.roqIdx),
Mux(lastCycleMisprediction, roqIdxHead + 1.U, Mux(canOut, roqIdxHead + validCount, roqIdxHead))
val lastCycleMisprediction = RegNext(io.redirect.valid && !io.redirect.bits.flushItself())
val roqIdxHeadNext = Mux(io.flush,
0.U.asTypeOf(new RoqPtr),
Mux(io.redirect.valid,
io.redirect.bits.roqIdx,
Mux(lastCycleMisprediction,
roqIdxHead + 1.U,
Mux(canOut, roqIdxHead + validCount, roqIdxHead))
)
)
roqIdxHead := roqIdxHeadNext
......@@ -100,7 +108,6 @@ class Rename extends XSModule with HasCircularQueuePtrHelper {
for (i <- 0 until RenameWidth) {
uops(i).cf := io.in(i).bits.cf
uops(i).ctrl := io.in(i).bits.ctrl
uops(i).brTag := io.in(i).bits.brTag
val inValid = io.in(i).valid
......
......@@ -33,7 +33,8 @@ object hartIdRTFp extends (() => Int) {
class RenameTable(float: Boolean) extends XSModule {
val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
val redirect = Input(Bool())
val flush = Input(Bool())
val walkWen = Input(Bool())
val readPorts = Vec({if(float) 4 else 3} * RenameWidth, new RatReadPort)
val specWritePorts = Vec(CommitWidth, new RatWritePort)
......@@ -48,8 +49,8 @@ class RenameTable(float: Boolean) extends XSModule {
// When redirect happens (mis-prediction), don't update the rename table
// However, when mis-prediction and walk happens at the same time, rename table needs to be updated
for(w <- io.specWritePorts){
when(w.wen && (!io.redirect.valid || io.walkWen)) {
for (w <- io.specWritePorts){
when (w.wen && (!(io.redirect || io.flush) || io.walkWen)) {
spec_table(w.addr) := w.wdata
}
}
......@@ -65,8 +66,7 @@ class RenameTable(float: Boolean) extends XSModule {
when(w.wen){ arch_table(w.addr) := w.wdata }
}
val flush = io.redirect.valid && io.redirect.bits.isUnconditional()
when (flush) {
when (io.flush) {
spec_table := arch_table
// spec table needs to be updated when flushPipe
for (w <- io.archWritePorts) {
......
......@@ -6,6 +6,7 @@ import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.LSUOpType
import xiangshan.backend.ftq.FtqPtr
import xiangshan.mem.{LqPtr, SqPtr}
object roqDebugId extends Function0[Integer] {
......@@ -17,9 +18,9 @@ object roqDebugId extends Function0[Integer] {
}
class RoqPtr extends CircularQueuePtr(RoqPtr.RoqSize) with HasCircularQueuePtrHelper {
def needFlush(redirect: Valid[Redirect]): Bool = {
def needFlush(redirect: Valid[Redirect], flush: Bool): Bool = {
val flushItself = redirect.bits.flushItself() && this === redirect.bits.roqIdx
redirect.valid && (redirect.bits.isUnconditional() || flushItself || isAfter(this, redirect.bits.roqIdx))
flush || (redirect.valid && (flushItself || isAfter(this, redirect.bits.roqIdx)))
}
}
......@@ -35,6 +36,7 @@ object RoqPtr extends HasXSParameter {
class RoqCSRIO extends XSBundle {
val intrBitSet = Input(Bool())
val trapTarget = Input(UInt(VAddrBits.W))
val isXRet = Input(Bool())
val fflags = Output(Valid(UInt(5.W)))
val dirty_fs = Output(Bool())
......@@ -80,6 +82,8 @@ class RoqDeqPtrWrapper extends XSModule with HasCircularQueuePtrHelper {
val intrBitSetReg = Input(Bool())
val hasNoSpecExec = Input(Bool())
val commitType = Input(CommitType())
val misPredBlock = Input(Bool())
val isReplaying = Input(Bool())
// output: the CommitWidth deqPtr
val out = Vec(CommitWidth, Output(new RoqPtr))
val next_out = Vec(CommitWidth, Output(new RoqPtr))
......@@ -97,11 +101,11 @@ class RoqDeqPtrWrapper extends XSModule with HasCircularQueuePtrHelper {
// for normal commits: only to consider when there're no exceptions
// we don't need to consider whether the first instruction has exceptions since it wil trigger exceptions.
val commitBlocked = VecInit((0 until CommitWidth).map(i => if (i == 0) false.B else possibleException(i).asUInt.orR || io.deq_flushPipe(i)))
val canCommit = VecInit((0 until CommitWidth).map(i => io.deq_v(i) && io.deq_w(i) /*&& !commitBlocked(i)*/))
val canCommit = VecInit((0 until CommitWidth).map(i => io.deq_v(i) && io.deq_w(i) && !io.misPredBlock && !io.isReplaying))
val normalCommitCnt = PriorityEncoder(canCommit.map(c => !c) :+ true.B)
// when io.intrBitSetReg or there're possible exceptions in these instructions, only one instruction is allowed to commit
val allowOnlyOne = VecInit(commitBlocked.drop(1)).asUInt.orR || io.intrBitSetReg
val commitCnt = Mux(allowOnlyOne, io.deq_v(0) && io.deq_w(0), normalCommitCnt)
val commitCnt = Mux(allowOnlyOne, canCommit(0), normalCommitCnt)
val resetDeqPtrVec = VecInit((0 until CommitWidth).map(_.U.asTypeOf(new RoqPtr)))
val commitDeqPtrVec = VecInit(deqPtrVec.map(_ + commitCnt))
......@@ -202,12 +206,22 @@ class RoqEnqPtrWrapper extends XSModule with HasCircularQueuePtrHelper {
// }
class RoqExceptionInfo extends XSBundle {
val uop = new MicroOp
val isInterrupt = Bool()
}
class RoqFlushInfo extends XSBundle {
val ftqIdx = new FtqPtr
val ftqOffset = UInt(log2Up(PredictWidth).W)
}
class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new Bundle() {
val redirect = Input(Valid(new Redirect))
val enq = new RoqEnqIO
val redirectOut = Output(Valid(new Redirect))
val exception = Output(new MicroOp)
val flushOut = ValidIO(new RoqFlushInfo)
val exception = ValidIO(new RoqExceptionInfo)
// exu + brq
val exeWbResults = Vec(numWbPorts, Flipped(ValidIO(new ExuOutput)))
val commits = new RoqCommitIO
......@@ -264,6 +278,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
val walkPtr = walkPtrVec(0)
val isEmpty = enqPtr === deqPtr
val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
/**
* states of Roq
......@@ -369,23 +384,25 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
// Thus, we don't allow load/store instructions to trigger an interrupt.
val intrBitSetReg = RegNext(io.csr.intrBitSet)
val intrEnable = intrBitSetReg && !hasNoSpecExec && !CommitType.isLoadStore(deqDispatchData.commitType)
val exceptionEnable = writebacked(deqPtr.value) && Cat(deqExceptionVec).orR()
val exceptionEnable = writebacked(deqPtr.value) && deqExceptionVec.asUInt.orR()
val isFlushPipe = writebacked(deqPtr.value) && deqWritebackData.flushPipe
io.redirectOut := DontCare
io.redirectOut.valid := (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable || isFlushPipe)
io.redirectOut.bits.level := Mux(intrEnable || exceptionEnable, RedirectLevel.exception, RedirectLevel.flushAll)
io.redirectOut.bits.interrupt := intrEnable
io.redirectOut.bits.target := Mux(intrEnable || exceptionEnable, io.csr.trapTarget, deqDispatchData.pc + 4.U)
io.exception := debug_deqUop
io.exception.ctrl.commitType := deqDispatchData.commitType
io.exception.cf.pc := deqDispatchData.pc
io.exception.cf.exceptionVec := deqExceptionVec
io.exception.cf.crossPageIPFFix := deqDispatchData.crossPageIPFFix
XSDebug(io.redirectOut.valid,
p"generate redirect: pc 0x${Hexadecimal(io.exception.cf.pc)} intr $intrEnable " +
p"excp $exceptionEnable flushPipe $isFlushPipe target 0x${Hexadecimal(io.redirectOut.bits.target)} " +
io.flushOut.valid := (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable || isFlushPipe)
io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable)
io.exception.valid := RegNext(exceptionHappen)
io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
io.exception.bits.uop.cf.pc := DontCare // we get pc at ftq, so roq don't save pc
io.exception.bits.uop.cf.exceptionVec := RegEnable(deqExceptionVec, exceptionHappen)
io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(deqDispatchData.crossPageIPFFix, exceptionHappen)
io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
XSDebug(io.flushOut.valid,
p"generate redirect: pc 0x${Hexadecimal(io.exception.bits.uop.cf.pc)} intr $intrEnable " +
p"excp $exceptionEnable flushPipe $isFlushPipe " +
p"Trap_target 0x${Hexadecimal(io.csr.trapTarget)} exceptionVec ${Binary(deqExceptionVec.asUInt)}\n")
......@@ -420,6 +437,18 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
}).reduce(_|_)
val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
// when mispredict branches writeback, stop commit in the next 2 cycles
// TODO: don't check all exu write back
val misPredWb = Cat(VecInit((0 until numWbPorts).map(i =>
io.exeWbResults(i).bits.redirect.cfiUpdate.isMisPred && io.exeWbResults(i).bits.redirectValid
))).orR()
val misPredBlockCounter = Reg(UInt(2.W))
misPredBlockCounter := Mux(misPredWb,
"b11".U,
misPredBlockCounter >> 1.U
)
val misPredBlock = misPredBlockCounter(0)
io.commits.isWalk := state =/= s_idle
val commit_v = Mux(state === s_idle, VecInit(deqPtrVec.map(ptr => valid(ptr.value))), VecInit(walkPtrVec.map(ptr => valid(ptr.value))))
val commit_w = VecInit(deqPtrVec.map(ptr => writebacked(ptr.value)))
......@@ -430,8 +459,8 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
for (i <- 0 until CommitWidth) {
// defaults: state === s_idle and instructions commit
// when intrBitSetReg, allow only one instruction to commit at each clock cycle
val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || commit_exception(0)
io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked
val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || deqExceptionVec.asUInt.orR
io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked && !misPredBlock && !isReplaying
io.commits.info(i) := dispatchDataRead(i)
when (state === s_walk) {
......@@ -490,7 +519,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
* (3) walk: when walking comes to the end, switch to s_walk
* (4) s_extrawalk to s_walk
*/
val state_next = Mux(io.redirectOut.valid,
val state_next = Mux(io.flushOut.valid,
s_idle,
Mux(io.redirect.valid,
Mux(io.enq.needAlloc.asUInt.orR, s_extrawalk, s_walk),
......@@ -514,6 +543,9 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
deqPtrGenModule.io.commitType := deqDispatchData.commitType
deqPtrGenModule.io.misPredBlock := misPredBlock
deqPtrGenModule.io.isReplaying := isReplaying
deqPtrVec := deqPtrGenModule.io.out
val deqPtrVec_next = deqPtrGenModule.io.next_out
......@@ -548,7 +580,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
val lastCycleRedirect = RegNext(io.redirect.valid)
val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
val commitCnt = PopCount(io.commits.valid)
validCounter := Mux(io.redirectOut.valid,
validCounter := Mux(io.flushOut.valid,
0.U,
Mux(state === s_idle,
(validCounter - commitCnt) + dispatchNum,
......@@ -556,7 +588,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
)
)
allowEnqueue := Mux(io.redirectOut.valid,
allowEnqueue := Mux(io.flushOut.valid,
true.B,
Mux(state === s_idle,
validCounter + dispatchNum <= (RoqSize - RenameWidth).U,
......@@ -599,7 +631,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
}
}
// reset: when exception, reset all valid to false
when (io.redirectOut.valid) {
when (io.flushOut.valid) {
for (i <- 0 until RoqSize) {
valid(i) := false.B
}
......@@ -651,6 +683,8 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
wdata.commitType := req.ctrl.commitType
wdata.pdest := req.pdest
wdata.old_pdest := req.old_pdest
wdata.ftqIdx := req.cf.ftqPtr
wdata.ftqOffset := req.cf.ftqOffset
wdata.pc := req.cf.pc
wdata.crossPageIPFFix := req.cf.crossPageIPFFix
// wdata.exceptionVec := req.cf.exceptionVec
......@@ -759,14 +793,14 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
XSPerf("writeback", PopCount((0 until RoqSize).map(i => valid(i) && writebacked(i))))
// XSPerf("enqInstr", PopCount(io.dp1Req.map(_.fire())))
// XSPerf("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
XSPerf("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
XSPerf("walkCycle", state === s_walk || state === s_extrawalk)
XSPerf("walkInstrAcc", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U), acc = true)
XSPerf("walkCycleAcc", state === s_walk || state === s_extrawalk, acc = true)
val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
val deqUopCommitType = io.commits.info(0).commitType
XSPerf("waitNormalCycle", deqNotWritebacked && deqUopCommitType === CommitType.NORMAL)
XSPerf("waitBranchCycle", deqNotWritebacked && deqUopCommitType === CommitType.BRANCH)
XSPerf("waitLoadCycle", deqNotWritebacked && deqUopCommitType === CommitType.LOAD)
XSPerf("waitStoreCycle", deqNotWritebacked && deqUopCommitType === CommitType.STORE)
XSPerf("waitNormalCycleAcc", deqNotWritebacked && deqUopCommitType === CommitType.NORMAL, acc = true)
XSPerf("waitBranchCycleAcc", deqNotWritebacked && deqUopCommitType === CommitType.BRANCH, acc = true)
XSPerf("waitLoadCycleAcc", deqNotWritebacked && deqUopCommitType === CommitType.LOAD, acc = true)
XSPerf("waitStoreCycleAcc", deqNotWritebacked && deqUopCommitType === CommitType.STORE, acc = true)
XSPerf("roqHeadPC", io.commits.info(0).pc)
val instrCnt = RegInit(0.U(64.W))
......@@ -806,11 +840,11 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper {
diffTestDebugLrScValid(i) := uop.diffTestDebugLrScValid
wpc(i) := SignExt(uop.cf.pc, XLEN)
trapVec(i) := io.commits.valid(i) && (state===s_idle) && uop.ctrl.isXSTrap
isRVC(i) := uop.cf.brUpdate.pd.isRVC
isRVC(i) := uop.cf.pd.isRVC
}
val retireCounterFix = Mux(io.redirectOut.valid, 1.U, retireCounter)
val retirePCFix = SignExt(Mux(io.redirectOut.valid, debug_deqUop.cf.pc, debug_microOp(firstValidCommit).cf.pc), XLEN)
val retireInstFix = Mux(io.redirectOut.valid, debug_deqUop.cf.instr, debug_microOp(firstValidCommit).cf.instr)
val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
val retirePCFix = SignExt(Mux(io.exception.valid, debug_deqUop.cf.pc, debug_microOp(firstValidCommit).cf.pc), XLEN)
val retireInstFix = Mux(io.exception.valid, debug_deqUop.cf.instr, debug_microOp(firstValidCommit).cf.instr)
val scFailed = !diffTestDebugLrScValid(0) &&
debug_deqUop.ctrl.fuType === FuType.mou &&
......
......@@ -13,6 +13,7 @@ trait HasBPUParameter extends HasXSParameter {
val EnableCFICommitLog = true
val EnbaleCFIPredLog = true
val EnableBPUTimeRecord = EnableCFICommitLog || EnbaleCFIPredLog
val EnableCommit = false
}
class TableAddr(val idxBits: Int, val banks: Int) extends XSBundle with HasIFUConst {
......@@ -42,7 +43,7 @@ class PredictorResponse extends XSBundle {
// the valid bits indicates whether a target is hit
val targets = Vec(PredictWidth, UInt(VAddrBits.W))
val hits = Vec(PredictWidth, Bool())
val types = Vec(PredictWidth, UInt(2.W))
val isBrs = Vec(PredictWidth, Bool())
val isRVC = Vec(PredictWidth, Bool())
}
class BimResp extends XSBundle {
......@@ -123,18 +124,24 @@ abstract class BasePredictor extends XSModule
val pc = Flipped(ValidIO(UInt(VAddrBits.W)))
val hist = Input(UInt(HistoryLength.W))
val inMask = Input(UInt(PredictWidth.W))
val update = Flipped(ValidIO(new CfiUpdateInfo))
val update = Flipped(ValidIO(new FtqEntry))
}
val io = new DefaultBasePredictorIO
val debug = true
}
class BrInfo extends XSBundle {
val metas = Vec(PredictWidth, new BpuMeta)
val rasSp = UInt(log2Ceil(RasSize).W)
val rasTop = new RASEntry
val specCnt = Vec(PredictWidth, UInt(10.W))
}
class BPUStageIO extends XSBundle {
val pc = UInt(VAddrBits.W)
val mask = UInt(PredictWidth.W)
val resp = new PredictorResponse
val brInfo = Vec(PredictWidth, new BpuMeta)
val brInfo = new BrInfo
}
......@@ -173,7 +180,6 @@ abstract class BPUStage extends XSModule with HasBPUParameter
io.out.mask := inLatch.mask
io.out.resp <> inLatch.resp
io.out.brInfo := inLatch.brInfo
(0 until PredictWidth).map(i => io.out.brInfo(i).sawNotTakenBranch := io.pred.sawNotTakenBr(i))
if (BPUDebug) {
val jmpIdx = io.pred.jmpIdx
......@@ -212,7 +218,7 @@ class BPUStage1 extends BPUStage {
ubtbResp.hits.asUInt, ubtbResp.takens.asUInt, ~ubtbResp.takens.asUInt & brMask.asUInt, ubtbResp.is_RVC.asUInt)
}
if (EnableBPUTimeRecord) {
io.out.brInfo.map(_.debug_ubtb_cycle := GTimer())
io.out.brInfo.metas.map(_.debug_ubtb_cycle := GTimer())
}
}
@chiselName
......@@ -220,9 +226,9 @@ class BPUStage2 extends BPUStage {
// Use latched response from s1
val btbResp = inLatch.resp.btb
val bimResp = inLatch.resp.bim
takens := VecInit((0 until PredictWidth).map(i => btbResp.hits(i) && (btbResp.types(i) === BTBtype.B && bimResp.ctrs(i)(1) || btbResp.types(i) =/= BTBtype.B)))
takens := VecInit((0 until PredictWidth).map(i => btbResp.hits(i) && (btbResp.isBrs(i) && bimResp.ctrs(i)(1) || !btbResp.isBrs(i))))
targets := btbResp.targets
brMask := VecInit((0 until PredictWidth).map(i => btbResp.types(i) === BTBtype.B && btbResp.hits(i)))
brMask := VecInit((0 until PredictWidth).map(i => btbResp.isBrs(i) && btbResp.hits(i)))
jalMask := DontCare
hasHalfRVI := btbResp.hits(PredictWidth-1) && !btbResp.isRVC(PredictWidth-1) && HasCExtension.B
......@@ -232,7 +238,7 @@ class BPUStage2 extends BPUStage {
btbResp.hits.asUInt, VecInit(bimResp.ctrs.map(_(1))).asUInt)
}
if (EnableBPUTimeRecord) {
io.out.brInfo.map(_.debug_btb_cycle := GTimer())
io.out.brInfo.metas.map(_.debug_btb_cycle := GTimer())
}
}
@chiselName
......@@ -240,9 +246,7 @@ class BPUStage3 extends BPUStage {
class S3IO extends XSBundle {
val predecode = Input(new Predecode)
val realMask = Input(UInt(PredictWidth.W))
val prevHalf = Flipped(ValidIO(new PrevHalfInstr))
val recover = Flipped(ValidIO(new CfiUpdateInfo))
val redirect = Flipped(ValidIO(new Redirect))
}
val s3IO = IO(new S3IO)
// TAGE has its own pipelines and the
......@@ -253,7 +257,6 @@ class BPUStage3 extends BPUStage {
val loopResp = io.in.resp.loop.exit
// realMask is in it
val pdMask = s3IO.predecode.mask
val pdLastHalf = s3IO.predecode.lastHalf
val pds = s3IO.predecode.pd
......@@ -274,14 +277,12 @@ class BPUStage3 extends BPUStage {
val brPred = (if(EnableBPD) tageTakens else bimTakens).asUInt
val loopRes = (if (EnableLoop) loopResp else VecInit(Fill(PredictWidth, 0.U(1.W)))).asUInt
val prevHalfTaken = s3IO.prevHalf.valid && s3IO.prevHalf.bits.taken && HasCExtension.B
val prevHalfTakenMask = prevHalfTaken.asUInt
val brTakens = ((brs & brPred | prevHalfTakenMask) & ~loopRes)
val brTakens = ((brs & brPred) & ~loopRes)
// we should provide btb resp as well
btbHits := btbResp.hits.asUInt | prevHalfTakenMask
btbHits := btbResp.hits.asUInt
// predict taken only if btb has a target, jal targets will be provided by IFU
takens := VecInit((0 until PredictWidth).map(i => (brTakens(i) || jalrs(i)) && btbHits(i) || jals(i)))
// predict taken only if btb has a target, jal and br targets will be provided by IFU
takens := VecInit((0 until PredictWidth).map(i => jalrs(i) && btbHits(i) || (jals(i) || brTakens(i))))
targets := inLatch.resp.btb.targets
......@@ -302,17 +303,16 @@ class BPUStage3 extends BPUStage {
ras.io.callIdx.bits := callIdx
ras.io.isRVC := (calls & RVCs).orR //TODO: this is ugly
ras.io.isLastHalfRVI := s3IO.predecode.hasLastHalfRVI
ras.io.recover := s3IO.recover
ras.io.redirect := s3IO.redirect
ras.fires <> fires
for(i <- 0 until PredictWidth){
io.out.brInfo(i).rasSp := ras.io.meta.rasSp
io.out.brInfo(i).rasTopCtr := ras.io.meta.rasTopCtr
io.out.brInfo(i).rasToqAddr := ras.io.meta.rasToqAddr
io.out.brInfo.rasSp := ras.io.meta.rasSp
io.out.brInfo.rasTop := ras.io.meta.rasTop
}
takens := VecInit((0 until PredictWidth).map(i => {
((brTakens(i) || jalrs(i)) && btbHits(i)) ||
jals(i) ||
(jalrs(i) && btbHits(i)) ||
jals(i) || brTakens(i) ||
(ras.io.out.valid && rets(i)) ||
(!ras.io.out.valid && rets(i) && btbHits(i))
}
......@@ -326,26 +326,13 @@ class BPUStage3 extends BPUStage {
}
// we should provide the prediction for the first half RVI of the end of a fetch packet
// branch taken information would be lost in the prediction of the next packet,
// so we preserve this information here
when (hasHalfRVI && btbResp.types(PredictWidth-1) === BTBtype.B && btbHits(PredictWidth-1) && HasCExtension.B) {
takens(PredictWidth-1) := brPred(PredictWidth-1) && !loopRes(PredictWidth-1)
}
// targets would be lost as well, since it is from btb
// unless it is a ret, which target is from ras
when (prevHalfTaken && !rets(0) && HasCExtension.B) {
targets(0) := s3IO.prevHalf.bits.target
}
// Wrap tage resp and tage meta in
// This is ugly
io.out.resp.tage <> io.in.resp.tage
io.out.resp.loop <> io.in.resp.loop
for (i <- 0 until PredictWidth) {
io.out.brInfo(i).tageMeta := io.in.brInfo(i).tageMeta
io.out.brInfo(i).specCnt := io.in.brInfo(i).specCnt
io.out.brInfo.metas(i).tageMeta := io.in.brInfo.metas(i).tageMeta
io.out.brInfo.specCnt(i) := io.in.brInfo.specCnt(i)
}
if (BPUDebug) {
......@@ -357,7 +344,7 @@ class BPUStage3 extends BPUStage {
}
XSDebug(p"brs:${Binary(brs)} jals:${Binary(jals)} jalrs:${Binary(jalrs)} calls:${Binary(calls)} rets:${Binary(rets)} rvcs:${Binary(RVCs)}\n")
XSDebug(p"callIdx:${callIdx} retIdx:${retIdx}\n")
XSDebug(p"brPred:${Binary(brPred)} loopRes:${Binary(loopRes)} prevHalfTaken:${prevHalfTaken} brTakens:${Binary(brTakens)}\n")
XSDebug(p"brPred:${Binary(brPred)} loopRes:${Binary(loopRes)} brTakens:${Binary(brTakens)}\n")
}
if (EnbaleCFIPredLog) {
......@@ -366,7 +353,7 @@ class BPUStage3 extends BPUStage {
}
if (EnableBPUTimeRecord) {
io.out.brInfo.map(_.debug_tage_cycle := GTimer())
io.out.brInfo.metas.map(_.debug_tage_cycle := GTimer())
}
}
......@@ -376,8 +363,8 @@ trait BranchPredictorComponents extends HasXSParameter {
val bim = Module(new BIM)
val tage = (if(EnableBPD) { Module(new Tage) }
else { Module(new FakeTage) })
val loop = Module(new LoopPredictor)
val preds = Seq(ubtb, btb, bim, tage, loop)
// val loop = Module(new LoopPredictor)
val preds = Seq(ubtb, btb, bim, tage/* , loop */)
preds.map(_.io := DontCare)
}
......@@ -387,10 +374,12 @@ class BPUReq extends XSBundle {
val inMask = UInt(PredictWidth.W)
}
abstract class BaseBPU extends XSModule with BranchPredictorComponents with HasBPUParameter{
abstract class BaseBPU extends XSModule with BranchPredictorComponents
with HasBPUParameter with HasIFUConst {
val io = IO(new Bundle() {
// from backend
val cfiUpdateInfo = Flipped(ValidIO(new CfiUpdateInfo))
val redirect = Flipped(ValidIO(new Redirect))
val commit = Flipped(ValidIO(new FtqEntry))
// from if1
val in = Input(new BPUReq)
val inFire = Input(Vec(4, Bool()))
......@@ -398,14 +387,12 @@ abstract class BaseBPU extends XSModule with BranchPredictorComponents with HasB
val out = Vec(3, Output(new BranchPrediction))
// from if4
val predecode = Input(new Predecode)
val realMask = Input(UInt(PredictWidth.W))
val prevHalf = Flipped(ValidIO(new PrevHalfInstr))
// to if4, some bpu info used for updating
val bpuMeta = Output(Vec(PredictWidth, new BpuMeta))
val brInfo = Output(new BrInfo)
})
preds.map(p => {
p.io.update <> io.cfiUpdateInfo
p.io.update <> io.commit
p.fires <> io.inFire
})
......@@ -436,14 +423,14 @@ abstract class BaseBPU extends XSModule with BranchPredictorComponents with HasB
io.out(1) <> s2.io.pred
io.out(2) <> s3.io.pred
io.bpuMeta := s3.io.out.brInfo
io.brInfo := s3.io.out.brInfo
if (BPUDebug) {
XSDebug(io.inFire(3), "bpuMeta sent!\n")
for (i <- 0 until PredictWidth) {
val b = io.bpuMeta(i)
XSDebug(io.inFire(3), "brInfo(%d): ubtbWrWay:%d, ubtbHit:%d, btbWrWay:%d, btbHitJal:%d, bimCtr:%d, fetchIdx:%d\n",
i.U, b.ubtbWriteWay, b.ubtbHits, b.btbWriteWay, b.btbHitJal, b.bimCtr, b.fetchIdx)
val b = io.brInfo.metas(i)
XSDebug(io.inFire(3), "brInfo(%d): ubtbWrWay:%d, ubtbHit:%d, btbWrWay:%d, bimCtr:%d\n",
i.U, b.ubtbWriteWay, b.ubtbHits, b.btbWriteWay, b.bimCtr)
val t = b.tageMeta
XSDebug(io.inFire(3), " tageMeta: pvder(%d):%d, altDiffers:%d, pvderU:%d, pvderCtr:%d, allocate(%d):%d\n",
t.provider.valid, t.provider.bits, t.altDiffers, t.providerU, t.providerCtr, t.allocate.valid, t.allocate.bits)
......@@ -459,7 +446,7 @@ class FakeBPU extends BaseBPU {
i <> DontCare
i.takens := 0.U
})
io.bpuMeta <> DontCare
io.brInfo <> DontCare
}
@chiselName
class BPU extends BaseBPU {
......@@ -467,12 +454,11 @@ class BPU extends BaseBPU {
//**********************Stage 1****************************//
val s1_resp_in = Wire(new PredictorResponse)
val s1_brInfo_in = Wire(Vec(PredictWidth, new BpuMeta))
val s1_brInfo_in = Wire(new BrInfo)
s1_resp_in.tage := DontCare
s1_resp_in.loop := DontCare
s1_brInfo_in := DontCare
(0 until PredictWidth).foreach(i => s1_brInfo_in(i).fetchIdx := i.U)
val s1_inLatch = RegEnable(io.in, s1_fire)
ubtb.io.pc.valid := s2_fire
......@@ -484,8 +470,8 @@ class BPU extends BaseBPU {
// Wrap ubtb response into resp_in and brInfo_in
s1_resp_in.ubtb <> ubtb.io.out
for (i <- 0 until PredictWidth) {
s1_brInfo_in(i).ubtbWriteWay := ubtb.io.uBTBMeta.writeWay(i)
s1_brInfo_in(i).ubtbHits := ubtb.io.uBTBMeta.hits(i)
s1_brInfo_in.metas(i).ubtbWriteWay := ubtb.io.uBTBMeta.writeWay(i)
s1_brInfo_in.metas(i).ubtbHits := ubtb.io.uBTBMeta.hits(i)
}
btb.io.pc.valid := s1_fire
......@@ -497,8 +483,7 @@ class BPU extends BaseBPU {
// Wrap btb response into resp_in and brInfo_in
s1_resp_in.btb <> btb.io.resp
for (i <- 0 until PredictWidth) {
s1_brInfo_in(i).btbWriteWay := btb.io.meta.writeWay(i)
s1_brInfo_in(i).btbHitJal := btb.io.meta.hitJal(i)
s1_brInfo_in.metas(i).btbWriteWay := btb.io.meta.writeWay(i)
}
bim.io.pc.valid := s1_fire
......@@ -509,7 +494,7 @@ class BPU extends BaseBPU {
// Wrap bim response into resp_in and brInfo_in
s1_resp_in.bim <> bim.io.resp
for (i <- 0 until PredictWidth) {
s1_brInfo_in(i).bimCtr := bim.io.meta.ctrs(i)
s1_brInfo_in.metas(i).bimCtr := bim.io.meta.ctrs(i)
}
......@@ -538,29 +523,24 @@ class BPU extends BaseBPU {
// Wrap tage response and meta into s3.io.in.bits
// This is ugly
loop.io.pc.valid := s2_fire
loop.io.if3_fire := s3_fire
loop.io.pc.bits := s2.io.in.pc
loop.io.inMask := io.predecode.mask
loop.io.respIn.taken := s3.io.pred.taken
loop.io.respIn.jmpIdx := s3.io.pred.jmpIdx
// loop.io.pc.valid := s2_fire
// loop.io.if3_fire := s3_fire
// loop.io.pc.bits := s2.io.in.pc
// loop.io.inMask := io.predecode.mask
// loop.io.respIn.taken := s3.io.pred.taken
// loop.io.respIn.jmpIdx := s3.io.pred.jmpIdx
s3.io.in.resp.tage <> tage.io.resp
s3.io.in.resp.loop <> loop.io.resp
// s3.io.in.resp.loop <> loop.io.resp
for (i <- 0 until PredictWidth) {
s3.io.in.brInfo(i).tageMeta := tage.io.meta(i)
s3.io.in.brInfo(i).specCnt := loop.io.meta.specCnts(i)
s3.io.in.brInfo.metas(i).tageMeta := tage.io.meta(i)
// s3.io.in.brInfo.specCnt(i) := loop.io.meta.specCnts(i)
}
s3.s3IO.predecode <> io.predecode
s3.s3IO.realMask := io.realMask
s3.s3IO.prevHalf := io.prevHalf
s3.s3IO.recover.valid <> io.cfiUpdateInfo.valid
s3.s3IO.recover.bits <> io.cfiUpdateInfo.bits
s3.s3IO.redirect <> io.redirect
if (BPUDebug) {
if (debug_verbose) {
......@@ -576,11 +556,17 @@ class BPU extends BaseBPU {
if (EnableCFICommitLog) {
val buValid = io.cfiUpdateInfo.valid && !io.cfiUpdateInfo.bits.isReplay
val buinfo = io.cfiUpdateInfo.bits
val pd = buinfo.pd
val tage_cycle = buinfo.bpuMeta.debug_tage_cycle
XSDebug(buValid, p"cfi_update: isBr(${pd.isBr}) pc(${Hexadecimal(buinfo.pc)}) taken(${buinfo.taken}) mispred(${buinfo.isMisPred}) cycle($tage_cycle) hist(${Hexadecimal(buinfo.bpuMeta.predHist.asUInt)})\n")
val buValid = io.commit.valid
val buinfo = io.commit.bits
for (i <- 0 until PredictWidth) {
val cfi_idx = buinfo.cfiIndex
val isTaken = cfi_idx.valid && cfi_idx.bits === i.U
val isCfi = buinfo.valids(i) && (buinfo.br_mask(i) || cfi_idx.valid && cfi_idx.bits === i.U)
val isBr = buinfo.br_mask(i)
val pc = packetAligned(buinfo.ftqPC) + (i * instBytes).U - Mux((i==0).B && buinfo.hasLastPrev, 2.U, 0.U)
val tage_cycle = buinfo.metas(i).debug_tage_cycle
XSDebug(buValid && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) taken(${isTaken}) mispred(${buinfo.mispred(i)}) cycle($tage_cycle) hist(${Hexadecimal(buinfo.predHist.asUInt)})\n")
}
}
}
......
......@@ -62,8 +62,7 @@ class BIM extends BasePredictor with BimParams {
val u = io.update.bits
val updateBank = bimAddr.getBank(u.pc)
val updateRow = bimAddr.getBankIdx(u.pc)
val updateRow = bimAddr.getBankIdx(u.ftqPC)
val wrbypass_ctrs = Reg(Vec(bypassEntries, Vec(BimBanks, UInt(2.W))))
......@@ -76,48 +75,48 @@ class BIM extends BasePredictor with BimParams {
val wrbypass_hit = wrbypass_hits.reduce(_||_)
val wrbypass_hit_idx = PriorityEncoder(wrbypass_hits)
val oldCtr = Mux(wrbypass_hit && wrbypass_ctr_valids(wrbypass_hit_idx)(updateBank), wrbypass_ctrs(wrbypass_hit_idx)(updateBank), u.bpuMeta.bimCtr)
val newTaken = u.taken
val newCtr = satUpdate(oldCtr, 2, newTaken)
val oldCtrs = VecInit((0 until BimBanks).map(b =>
Mux(wrbypass_hit && wrbypass_ctr_valids(wrbypass_hit_idx)(b),
wrbypass_ctrs(wrbypass_hit_idx)(b), u.metas(b).bimCtr)))
val newTakens = VecInit((0 until BimBanks).map(b => u.cfiIndex.valid && u.cfiIndex.bits === b.U))
val newCtrs = VecInit((0 until BimBanks).map(b => satUpdate(oldCtrs(b), 2, newTakens(b))))
// val oldSaturated = newCtr === oldCtr
val needToUpdate = io.update.valid && u.pd.isBr && !u.isReplay
val needToUpdate = VecInit((0 until PredictWidth).map(i => io.update.valid && u.br_mask(i) && u.valids(i)))
when (reset.asBool) { wrbypass_ctr_valids.foreach(_.foreach(_ := false.B))}
when (needToUpdate) {
when (wrbypass_hit) {
wrbypass_ctrs(wrbypass_hit_idx)(updateBank) := newCtr
wrbypass_ctr_valids(wrbypass_hit_idx)(updateBank) := true.B
} .otherwise {
wrbypass_ctrs(wrbypass_enq_idx)(updateBank) := newCtr
(0 until BimBanks).foreach(b => wrbypass_ctr_valids(wrbypass_enq_idx)(b) := false.B) // reset valid bits
wrbypass_ctr_valids(wrbypass_enq_idx)(updateBank) := true.B
wrbypass_rows(wrbypass_enq_idx) := updateRow
wrbypass_enq_idx := (wrbypass_enq_idx + 1.U)(log2Up(bypassEntries)-1,0)
for (b <- 0 until BimBanks) {
when (needToUpdate(b)) {
when (wrbypass_hit) {
wrbypass_ctrs(wrbypass_hit_idx)(b) := newCtrs(b)
wrbypass_ctr_valids(wrbypass_hit_idx)(b) := true.B
} .otherwise {
wrbypass_ctrs(wrbypass_enq_idx)(b) := newCtrs(b)
(0 until BimBanks).foreach(b => wrbypass_ctr_valids(wrbypass_enq_idx)(b) := false.B) // reset valid bits
wrbypass_ctr_valids(wrbypass_enq_idx)(b) := true.B
wrbypass_rows(wrbypass_enq_idx) := updateRow
wrbypass_enq_idx := (wrbypass_enq_idx + 1.U)(log2Up(bypassEntries)-1,0)
}
}
}
for (b <- 0 until BimBanks) {
bim(b).io.w.req.valid := needToUpdate && b.U === updateBank || doing_reset
bim(b).io.w.req.valid := needToUpdate(b) || doing_reset
bim(b).io.w.req.bits.setIdx := Mux(doing_reset, resetRow, updateRow)
bim(b).io.w.req.bits.data := Mux(doing_reset, 2.U(2.W), newCtr)
}
if (!env.FPGAPlatform && env.EnablePerfDebug) {
val bimResp = Wire(Vec(PredictWidth, Bool()))
for(i <- 0 until PredictWidth) {
bimResp(i) := io.resp.ctrs(i)(1)
}
ExcitingUtils.addSource(bimResp, "bimResp")
bim(b).io.w.req.bits.data := Mux(doing_reset, 2.U(2.W), newCtrs(b))
}
if (BPUDebug && debug) {
XSDebug(doing_reset, "Reseting...\n")
XSDebug("[update] v=%d pc=%x pnpc=%x tgt=%x", io.update.valid, u.pc, u.pnpc, u.target)
XSDebug("[update] taken=%d isMisPred=%d", u.taken, u.isMisPred)
XSDebug(false, true.B, p"brTag=${u.brTag} pd.isBr=${u.pd.isBr} brInfo.bimCtr=${Binary(u.bpuMeta.bimCtr)}\n")
XSDebug("needToUpdate=%d updateBank=%x updateRow=%x newCtr=%b oldCtr=%b\n", needToUpdate, updateBank, updateRow, newCtr, oldCtr)
XSDebug("[update] v=%d pc=%x valids=%b, tgt=%x\n", io.update.valid, u.ftqPC, u.valids.asUInt, u.target)
XSDebug("[update] brMask=%b, taken=%b isMisPred=%b\n", u.br_mask.asUInt, newTakens.asUInt, u.mispred.asUInt)
for (i <- 0 until BimBanks) {
XSDebug(true.B, p"bimCtr(${i.U})=${Binary(u.metas(i).bimCtr)} oldCtr=${Binary(oldCtrs(i))} newCtr=${Binary(newCtrs(i))}\n")
}
XSDebug("needToUpdate=%b updateRow=%x\n", needToUpdate.asUInt, updateRow)
XSDebug("[wrbypass] hit=%d hits=%b\n", wrbypass_hit, wrbypass_hits.asUInt)
}
......
......@@ -36,16 +36,16 @@ class BtbMetaEntry() extends XSBundle with BTBParams {
val valid = Bool()
// TODO: don't need full length of tag
val tag = UInt((VAddrBits - log2Ceil(nRows) - log2Ceil(PredictWidth) - instOffsetBits).W)
val btbType = UInt(2.W)
val isBr = Bool()
val isRVC = Bool()
}
object BtbMetaEntry {
def apply(tag: UInt, btbType: UInt, isRVC: Bool) = {
def apply(tag: UInt, isBr: UInt, isRVC: Bool) = {
val e = Wire(new BtbMetaEntry)
e.valid := true.B
e.tag := tag
e.btbType := btbType
e.isBr := isBr
e.isRVC := isRVC
e
}
......@@ -55,12 +55,11 @@ class BTB extends BasePredictor with BTBParams{
class BTBResp extends Resp {
val targets = Vec(PredictWidth, UInt(VAddrBits.W))
val hits = Vec(PredictWidth, Bool())
val types = Vec(PredictWidth, UInt(2.W))
val isBrs = Vec(PredictWidth, Bool())
val isRVC = Vec(PredictWidth, Bool())
}
class BTBMeta extends Meta {
val writeWay = Vec(PredictWidth, UInt(log2Up(BtbWays).W))
val hitJal = Vec(PredictWidth, Bool())
}
class BTBFromOthers extends FromOthers {}
......@@ -157,10 +156,10 @@ class BTB extends BasePredictor with BTBParams{
// Use real pc to calculate the target
io.resp.targets(b) := Mux(data_entry.extended, if2_edataRead, Cat(if2_pc(VAddrBits-1, lowerBitsSize+instOffsetBits), data_entry.lower, 0.U(instOffsetBits.W)))
io.resp.hits(b) := if2_bankHits(b)
io.resp.types(b) := meta_entry.btbType
io.resp.isBrs(b) := meta_entry.isBr
io.resp.isRVC(b) := meta_entry.isRVC
io.meta.writeWay(b) := writeWay(b)
io.meta.hitJal(b) := if2_bankHits(b) && meta_entry.btbType === BTBtype.J
// io.meta.hitJal(b) := if2_bankHits(b) && meta_entry.btbType === BTBtype.J
}
def pdInfoToBTBtype(pd: PreDecodeInfo) = {
......@@ -173,30 +172,34 @@ class BTB extends BasePredictor with BTBParams{
}
val u = io.update.bits
val new_target = Mux(u.pd.isBr, u.brTarget, u.target)
val cfi_pc = packetAligned(u.ftqPC) + (u.cfiIndex.bits << instOffsetBits)
val new_target = u.target
val new_lower = new_target(lowerBitsSize+instOffsetBits-1, instOffsetBits)
val update_pc_higher = u.pc(VAddrBits-1, lowerBitsSize+instOffsetBits)
val update_pc_higher = cfi_pc(VAddrBits-1, lowerBitsSize+instOffsetBits)
val update_target_higher = new_target(VAddrBits-1, lowerBitsSize+instOffsetBits)
val higher_identical = update_pc_higher === update_target_higher
val new_extended = !higher_identical
val updateWay = u.bpuMeta.btbWriteWay
val updateBankIdx = btbAddr.getBank(u.pc)
val updateRow = btbAddr.getBankIdx(u.pc)
val updateType = pdInfoToBTBtype(u.pd)
val metaWrite = BtbMetaEntry(btbAddr.getTag(u.pc), updateType, u.pd.isRVC)
val updateWay = u.metas(u.cfiIndex.bits).btbWriteWay
val updateBank = u.cfiIndex.bits
val updateRow = btbAddr.getBankIdx(cfi_pc)
val updateIsBr = u.br_mask(u.cfiIndex.bits)
val updateTaken = u.cfiIndex.valid
// TODO: remove isRVC
val metaWrite = BtbMetaEntry(btbAddr.getTag(cfi_pc), updateIsBr, u.cfiIsRVC)
val dataWrite = BtbDataEntry(new_lower, new_extended)
val jalFirstEncountered = !u.isMisPred && !u.bpuMeta.btbHitJal && updateType === BTBtype.J
val updateValid = io.update.valid && (u.isMisPred || jalFirstEncountered) && !u.isReplay
// val jalFirstEncountered = !u.isMisPred && !u.bpuMeta.btbHitJal && updateType === BTBtype.J
val updateValid = io.update.valid && updateTaken
// Update btb
for (w <- 0 until BtbWays) {
for (b <- 0 until BtbBanks) {
meta(w)(b).io.w.req.valid := updateValid && b.U === updateBankIdx && w.U === updateWay
meta(w)(b).io.w.req.valid := updateValid && b.U === updateBank && w.U === updateWay
meta(w)(b).io.w.req.bits.setIdx := updateRow
meta(w)(b).io.w.req.bits.data := metaWrite
data(w)(b).io.w.req.valid := updateValid && b.U === updateBankIdx && w.U === updateWay
data(w)(b).io.w.req.valid := updateValid && b.U === updateBank && w.U === updateWay
data(w)(b).io.w.req.bits.setIdx := updateRow
data(w)(b).io.w.req.bits.data := dataWrite
}
......@@ -206,18 +209,6 @@ class BTB extends BasePredictor with BTBParams{
edata.io.w.req.bits.setIdx := updateRow
edata.io.w.req.bits.data := u.target
if (!env.FPGAPlatform && env.EnablePerfDebug) {
val btbAns = Wire(Vec(PredictWidth, new PredictorAnswer))
btbAns.zipWithIndex.foreach{ case(x,i) =>
x.hit := io.resp.hits(i)
x.taken := DontCare
x.target := io.resp.targets(i)
}
ExcitingUtils.addSource(btbAns, "btbAns")
}
if (BPUDebug && debug) {
val debug_verbose = true
......@@ -228,18 +219,18 @@ class BTB extends BasePredictor with BTBParams{
if (debug_verbose) {
for (i <- 0 until BtbBanks){
for (j <- 0 until BtbWays) {
XSDebug(validLatch, "read_resp[w=%d][b=%d][r=%d] is valid(%d) mask(%d), tag=0x%x, lower=0x%x, type=%d, isExtend=%d, isRVC=%d\n",
j.U, i.U, if2_row, if2_metaRead(j)(i).valid, if2_mask(i), if2_metaRead(j)(i).tag, if2_dataRead(j)(i).lower, if2_metaRead(j)(i).btbType, if2_dataRead(j)(i).extended, if2_metaRead(j)(i).isRVC)
XSDebug(validLatch, "read_resp[w=%d][b=%d][r=%d] is valid(%d) mask(%d), tag=0x%x, lower=0x%x, isBr=%d, isExtend=%d, isRVC=%d\n",
j.U, i.U, if2_row, if2_metaRead(j)(i).valid, if2_mask(i), if2_metaRead(j)(i).tag, if2_dataRead(j)(i).lower, if2_metaRead(j)(i).isBr, if2_dataRead(j)(i).extended, if2_metaRead(j)(i).isRVC)
}
}
}
for (i <- 0 until BtbBanks) {
XSDebug(validLatch && if2_bankHits(i), "resp(%d): bank(%d) hits, tgt=%x, isRVC=%d, type=%d\n",
i.U, i.U, io.resp.targets(i), io.resp.isRVC(i), io.resp.types(i))
XSDebug(validLatch && if2_bankHits(i), "resp(%d): bank(%d) hits, tgt=%x, isRVC=%d, isBr=%d\n",
i.U, i.U, io.resp.targets(i), io.resp.isRVC(i), io.resp.isBrs(i))
}
XSDebug(updateValid, "update_req: cycle=%d, pc=0x%x, target=0x%x, misPred=%d, lower=%x, extended=%d, way=%d, bank=%d, row=0x%x\n",
u.bpuMeta.debug_btb_cycle, u.pc, new_target, u.isMisPred, new_lower, new_extended, updateWay, updateBankIdx, updateRow)
u.metas(u.cfiIndex.bits).debug_btb_cycle, cfi_pc, new_target, u.mispred(u.cfiIndex.bits), new_lower, new_extended, updateWay, updateBank, updateRow)
for (i <- 0 until BtbBanks) {
// Conflict when not hit and allocating a valid entry
val conflict = if2_metaRead(allocWays(i))(i).valid && !if2_bankHits(i)
......
......@@ -40,11 +40,13 @@ class FrontendImp (outer: Frontend) extends LazyModuleImp(outer)
val l1plusPrefetcher = Module(new L1plusPrefetcher)
val instrUncache = outer.instrUncache.module
val needFlush = io.backend.redirect.valid
val needFlush = io.backend.redirect_cfiUpdate.valid
// from backend
ifu.io.redirect <> io.backend.redirect
ifu.io.cfiUpdateInfo <> io.backend.cfiUpdateInfo
ifu.io.redirect <> io.backend.redirect_cfiUpdate
ifu.io.commitUpdate <> io.backend.commit_cfiUpdate
ifu.io.ftqEnqPtr <> io.backend.ftqEnqPtr
ifu.io.ftqLeftOne <> io.backend.ftqLeftOne
// to icache
val grantClientId = clientId(io.icacheMemGrant.bits.id)
val grantEntryId = entryId(io.icacheMemGrant.bits.id)
......@@ -86,6 +88,8 @@ class FrontendImp (outer: Frontend) extends LazyModuleImp(outer)
ibuffer.io.flush := needFlush
// ibuffer to backend
io.backend.cfVec <> ibuffer.io.out
// ifu to backend
io.backend.fetchInfo <> ifu.io.toFtq
// for(out <- ibuffer.io.out){
// XSInfo(out.fire(),
......
......@@ -6,7 +6,7 @@ import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.fu.HasExceptionNO
import xiangshan.backend.ftq.FtqPtr
class IbufPtr extends CircularQueuePtr(IbufPtr.IBufSize) { }
......@@ -31,12 +31,13 @@ class Ibuffer extends XSModule with HasCircularQueuePtrHelper {
class IBufEntry extends XSBundle {
val inst = UInt(32.W)
val pc = UInt(VAddrBits.W)
val pnpc = UInt(VAddrBits.W)
val brInfo = new BpuMeta
val pd = new PreDecodeInfo
val ipf = Bool()
val acf = Bool()
val crossPageIPFFix = Bool()
val pred_taken = Bool()
val ftqPtr = new FtqPtr
val ftqOffset = UInt(log2Ceil(PredictWidth).W)
}
// Ignore
......@@ -92,12 +93,13 @@ class Ibuffer extends XSModule with HasCircularQueuePtrHelper {
when(io.in.bits.mask(i)) {
inWire.inst := io.in.bits.instrs(i)
inWire.pc := io.in.bits.pc(i)
inWire.pnpc := io.in.bits.pnpc(i)
inWire.brInfo := io.in.bits.bpuMeta(i)
inWire.pd := io.in.bits.pd(i)
inWire.ipf := io.in.bits.ipf
inWire.acf := io.in.bits.acf
inWire.crossPageIPFFix := io.in.bits.crossPageIPFFix
inWire.pred_taken := io.in.bits.pred_taken(i)
inWire.ftqPtr := io.in.bits.ftqPtr
inWire.ftqOffset := i.U
// ibuf(tail_vec(offset(i)).value) := inWire
}
ibuf.io.waddr(i) := tail_vec(offset(i)).value
......@@ -130,11 +132,11 @@ class Ibuffer extends XSModule with HasCircularQueuePtrHelper {
io.out(i).bits.exceptionVec(instrPageFault) := outWire.ipf
io.out(i).bits.exceptionVec(instrAccessFault) := outWire.acf
// io.out(i).bits.brUpdate := outWire.brInfo
io.out(i).bits.brUpdate := DontCare
io.out(i).bits.brUpdate.pc := outWire.pc
io.out(i).bits.brUpdate.pnpc := outWire.pnpc
io.out(i).bits.brUpdate.pd := outWire.pd
io.out(i).bits.brUpdate.bpuMeta := outWire.brInfo
io.out(i).bits.pd := outWire.pd
io.out(i).bits.pred_taken := outWire.pred_taken
io.out(i).bits.ftqPtr := outWire.ftqPtr
io.out(i).bits.ftqOffset := outWire.ftqOffset
io.out(i).bits.crossPageIPFFix := outWire.crossPageIPFFix
val head_wire = next_head_ptr.value + i.U
......
......@@ -62,7 +62,6 @@ class TageResp extends TageBundle {
class TageUpdate extends TageBundle {
val pc = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(TageBanks).W)
val hist = UInt(HistoryLength.W)
// update tag and ctr
val mask = Vec(TageBanks, Bool())
......@@ -318,12 +317,12 @@ class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPerio
XSDebug(RegNext(io.req.valid), "TageTableResp: hits:%b, maskLatch is %b\n", if3_req_rhits.asUInt, if3_mask)
XSDebug(RegNext(io.req.valid) && !if3_req_rhits.reduce(_||_), "TageTableResp: no hits!\n")
XSDebug(io.update.mask.reduce(_||_), "update Table: pc:%x, fetchIdx:%d, hist:%x, bank:%d, taken:%d, alloc:%d, oldCtr:%d\n",
u.pc, u.fetchIdx, u.hist, b, u.taken(b), u.alloc(b), u.oldCtr(b))
XSDebug(io.update.mask.reduce(_||_), "update Table: pc:%x, hist:%x, bank:%d, taken:%d, alloc:%d, oldCtr:%d\n",
u.pc, u.hist, b, u.taken(b), u.alloc(b), u.oldCtr(b))
XSDebug(io.update.mask.reduce(_||_), "update Table: writing tag:%b, ctr%d in idx:%d\n",
update_wdata(b).tag, update_wdata(b).ctr, update_idx)
XSDebug(io.update.mask.reduce(_||_), "update u: pc:%x, fetchIdx:%d, hist:%x, bank:%d, writing in u:%b\n",
u.pc, u.fetchIdx, u.hist, ub, io.update.u(ub))
XSDebug(io.update.mask.reduce(_||_), "update u: pc:%x, hist:%x, bank:%d, writing in u:%b\n",
u.pc, u.hist, ub, io.update.u(ub))
val updateBank = PriorityEncoder(io.update.mask)
XSDebug(wrbypass_hit && wrbypass_ctr_valids(wrbypass_hit_idx)(updateBank),
......@@ -394,6 +393,7 @@ class Tage extends BaseTage {
req.bits.pc := io.pc.bits
req.bits.hist := io.hist
req.bits.mask := io.inMask
if (!EnableSC) {t.io.update := DontCare}
t
}
}
......@@ -421,12 +421,12 @@ class Tage extends BaseTage {
val debug_hist_s3 = RegEnable(debug_hist_s2, enable=s3_fire)
val u = io.update.bits
val updateValid = io.update.valid && !io.update.bits.isReplay
val updateHist = u.bpuMeta.predHist.asUInt
val updateValids = u.valids.map(v => v && io.update.valid)
val updateHist = u.predHist.asUInt
val updateIsBr = u.pd.isBr
val updateMeta = u.bpuMeta.tageMeta
val updateMisPred = u.isMisPred && updateIsBr
val updateBrMask = u.br_mask
val updateMetas = VecInit(u.metas.map(_.tageMeta))
val updateMisPred = u.mispred
val updateMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(TageBanks, Bool()))))
val updateUMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(TageBanks, Bool()))))
......@@ -447,10 +447,10 @@ class Tage extends BaseTage {
scUpdateTaken := DontCare
scUpdateOldCtrs := DontCare
val updateSCMeta = u.bpuMeta.tageMeta.scMeta
val updateTageMisPred = updateMeta.taken =/= u.taken && updateIsBr
val updateSCMetas = VecInit(u.metas.map(_.tageMeta.scMeta))
val updateTageMisPreds = VecInit((0 until PredictWidth).map(i => updateMetas(i).taken =/= u.takens(i) && updateBrMask(i)))
val updateBank = u.pc(log2Ceil(TageBanks)+instOffsetBits-1, instOffsetBits)
// val updateBank = u.pc(log2Ceil(TageBanks)+instOffsetBits-1, instOffsetBits)
// access tag tables and output meta info
for (w <- 0 until TageBanks) {
......@@ -544,9 +544,12 @@ class Tage extends BaseTage {
}
}
val isUpdateTaken = updateValid && updateBank === w.U &&
u.taken && updateIsBr
when (updateIsBr && updateValid && updateBank === w.U) {
val updateValid = updateValids(w)
val updateMeta = updateMetas(w)
val updateIsBr = updateBrMask(w)
val isUpdateTaken = updateValid && u.takens(w) && updateIsBr
val updateMisPred = updateTageMisPreds(w)
when (updateValid && updateIsBr) {
when (updateMeta.provider.valid) {
val provider = updateMeta.provider.bits
......@@ -562,50 +565,49 @@ class Tage extends BaseTage {
updateAlloc(provider)(w) := false.B
}
}
}
when (updateValid && updateTageMisPred) {
val idx = updateBank
val allocate = updateMeta.allocate
when (allocate.valid) {
updateMask(allocate.bits)(idx) := true.B
updateTaken(allocate.bits)(idx) := u.taken
updateAlloc(allocate.bits)(idx) := true.B
updateUMask(allocate.bits)(idx) := true.B
updateU(allocate.bits)(idx) := 0.U
}.otherwise {
val provider = updateMeta.provider
val decrMask = Mux(provider.valid, ~LowerMask(UIntToOH(provider.bits), TageNTables), 0.U(TageNTables.W))
for (i <- 0 until TageNTables) {
when (decrMask(i)) {
updateUMask(i)(idx) := true.B
updateU(i)(idx) := 0.U
when (updateValid && updateMisPred) {
val allocate = updateMeta.allocate
when (allocate.valid) {
updateMask(allocate.bits)(w) := true.B
updateTaken(allocate.bits)(w) := isUpdateTaken
updateAlloc(allocate.bits)(w) := true.B
updateUMask(allocate.bits)(w) := true.B
updateU(allocate.bits)(w) := 0.U
}.otherwise {
val provider = updateMeta.provider
val decrMask = Mux(provider.valid, ~LowerMask(UIntToOH(provider.bits), TageNTables), 0.U(TageNTables.W))
for (i <- 0 until TageNTables) {
when (decrMask(i)) {
updateUMask(i)(w) := true.B
updateU(i)(w) := 0.U
}
}
}
}
}
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")
}
}
}
// 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) {
......@@ -616,38 +618,32 @@ class Tage extends BaseTage {
tables(i).io.update.uMask(w) := updateUMask(i)(w)
tables(i).io.update.u(w) := updateU(i)(w)
tables(i).io.update.pc := packetAligned(u.ftqPC) + (w << instOffsetBits).U
}
// use fetch pc instead of instruction pc
tables(i).io.update.pc := u.pc
tables(i).io.update.hist := updateHist
tables(i).io.update.fetchIdx := u.bpuMeta.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.bpuMeta.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
// }
if (!env.FPGAPlatform && env.EnablePerfDebug) {
val tageAns = Wire(Vec(PredictWidth, new PredictorAnswer))
tageAns.zipWithIndex.foreach{ case(x,i) =>
x.hit := io.resp.hits(i)
x.taken := io.resp.takens(i)
x.target := DontCare
}
ExcitingUtils.addSource(tageAns, "tageAns")
}
if (BPUDebug && debug) {
val m = updateMeta
val bri = u.bpuMeta
for (b <- 0 until TageBanks) {
val m = updateMetas(b)
val bri = u.metas(b)
XSDebug(updateValids(b), "update(%d): pc=%x, fetchpc=%x, cycle=%d, hist=%x, taken:%d, misPred:%d, bimctr:%d, pvdr(%d):%d, altDiff:%d, pvdrU:%d, pvdrCtr:%d, alloc(%d):%d\n",
b.U, u.ftqPC, packetAligned(u.ftqPC)+(b << instOffsetBits).U, bri.debug_tage_cycle, updateHist, u.takens(b), u.mispred(b),
bri.bimCtr, m.provider.valid, m.provider.bits, m.altDiffers, m.providerU, m.providerCtr, m.allocate.valid, m.allocate.bits
)
}
val if4_resps = RegEnable(if3_resps, s3_fire)
XSDebug(io.pc.valid, "req: pc=0x%x, hist=%x\n", io.pc.bits, io.hist)
XSDebug(s3_fire, "s3Fire:%d, resp: pc=%x, hist=%x\n", s3_fire, debug_pc_s2, debug_hist_s2)
......@@ -656,10 +652,8 @@ class Tage extends BaseTage {
for (i <- 0 until TageNTables) {
XSDebug(RegNext(s3_fire), "TageTable(%d): valids:%b, resp_ctrs:%b, resp_us:%b\n", i.U, VecInit(if4_resps(i).map(_.valid)).asUInt, Cat(if4_resps(i).map(_.bits.ctr)), Cat(if4_resps(i).map(_.bits.u)))
}
XSDebug(io.update.valid, "update: pc=%x, fetchpc=%x, cycle=%d, hist=%x, taken:%d, misPred:%d, bimctr:%d, pvdr(%d):%d, altDiff:%d, pvdrU:%d, pvdrCtr:%d, alloc(%d):%d\n",
u.pc, u.pc - (bri.fetchIdx << instOffsetBits.U), bri.debug_tage_cycle, updateHist, u.taken, u.isMisPred, 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")
// XSDebug(io.update.valid && updateIsBr, p"update: sc: ${updateSCMeta}\n")
// XSDebug(true.B, p"scThres: use(${useThreshold}), update(${updateThreshold})\n")
}
}
......
......@@ -38,7 +38,8 @@ class LsqEnqIO extends XSBundle {
class LsqWrappper extends XSModule with HasDCacheParameters {
val io = IO(new Bundle() {
val enq = new LsqEnqIO
val brqRedirect = Input(Valid(new Redirect))
val brqRedirect = Flipped(ValidIO(new Redirect))
val flush = Input(Bool())
val loadIn = Vec(LoadPipelineWidth, Flipped(Valid(new LsPipelineBundle)))
val storeIn = Vec(StorePipelineWidth, Flipped(Valid(new LsPipelineBundle)))
val loadDataForwarded = Vec(LoadPipelineWidth, Input(Bool()))
......@@ -89,6 +90,7 @@ class LsqWrappper extends XSModule with HasDCacheParameters {
// load queue wiring
loadQueue.io.brqRedirect <> io.brqRedirect
loadQueue.io.flush <> io.flush
loadQueue.io.loadIn <> io.loadIn
loadQueue.io.storeIn <> io.storeIn
loadQueue.io.loadDataForwarded <> io.loadDataForwarded
......@@ -102,6 +104,7 @@ class LsqWrappper extends XSModule with HasDCacheParameters {
// store queue wiring
// storeQueue.io <> DontCare
storeQueue.io.brqRedirect <> io.brqRedirect
storeQueue.io.flush <> io.flush
storeQueue.io.storeIn <> io.storeIn
storeQueue.io.sbuffer <> io.sbuffer
storeQueue.io.mmioStout <> io.mmioStout
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册