xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision 93b51ff08d18a635951028ae9d097df7e64518cc)
109c6f1ddSLingrui98/***************************************************************************************
209c6f1ddSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
309c6f1ddSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
409c6f1ddSLingrui98*
509c6f1ddSLingrui98* XiangShan is licensed under Mulan PSL v2.
609c6f1ddSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
709c6f1ddSLingrui98* You may obtain a copy of Mulan PSL v2 at:
809c6f1ddSLingrui98*          http://license.coscl.org.cn/MulanPSL2
909c6f1ddSLingrui98*
1009c6f1ddSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1109c6f1ddSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1209c6f1ddSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1309c6f1ddSLingrui98*
1409c6f1ddSLingrui98* See the Mulan PSL v2 for more details.
15c49ebec8SHaoyuan Feng*
16c49ebec8SHaoyuan Feng*
17c49ebec8SHaoyuan Feng* Acknowledgement
18c49ebec8SHaoyuan Feng*
19c49ebec8SHaoyuan Feng* This implementation is inspired by several key papers:
20c49ebec8SHaoyuan Feng* [1] Glenn Reinman, Todd Austin, and Brad Calder. "[A scalable front-end architecture for fast instruction delivery.]
21c49ebec8SHaoyuan Feng* (https://doi.org/10.1109/ISCA.1999.765954)" 26th International Symposium on Computer Architecture (ISCA). 1999.
22c49ebec8SHaoyuan Feng*
2309c6f1ddSLingrui98***************************************************************************************/
2409c6f1ddSLingrui98
2509c6f1ddSLingrui98package xiangshan.frontend
2609c6f1ddSLingrui98
2709c6f1ddSLingrui98import chisel3._
2809c6f1ddSLingrui98import chisel3.util._
29cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
303c02ee8fSwakafaimport utility._
31cf7d6b7aSMuziimport utility.ChiselDB
324b2c87baS梁森 Liang Senimport utility.mbist.MbistPipeline
33*93b51ff0SHuSipengimport utility.sram.SplittedSRAMTemplate
34cf7d6b7aSMuziimport utils._
3509c6f1ddSLingrui98import xiangshan._
361ca0e4f3SYinan Xuimport xiangshan.backend.CtrlToFtqIO
37cf7d6b7aSMuziimport xiangshan.frontend.icache._
3851532d8bSGuokai Chen
3951532d8bSGuokai Chenclass FtqDebugBundle extends Bundle {
4051532d8bSGuokai Chen  val pc        = UInt(39.W)
4151532d8bSGuokai Chen  val target    = UInt(39.W)
4251532d8bSGuokai Chen  val isBr      = Bool()
4351532d8bSGuokai Chen  val isJmp     = Bool()
4451532d8bSGuokai Chen  val isCall    = Bool()
4551532d8bSGuokai Chen  val isRet     = Bool()
4651532d8bSGuokai Chen  val misPred   = Bool()
4751532d8bSGuokai Chen  val isTaken   = Bool()
4851532d8bSGuokai Chen  val predStage = UInt(2.W)
4951532d8bSGuokai Chen}
5009c6f1ddSLingrui98
513b739f49SXuan Huclass FtqPtr(entries: Int) extends CircularQueuePtr[FtqPtr](
523b739f49SXuan Hu      entries
5309c6f1ddSLingrui98    ) {
543b739f49SXuan Hu  def this()(implicit p: Parameters) = this(p(XSCoreParamsKey).FtqSize)
5509c6f1ddSLingrui98}
5609c6f1ddSLingrui98
5709c6f1ddSLingrui98object FtqPtr {
5809c6f1ddSLingrui98  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
5909c6f1ddSLingrui98    val ptr = Wire(new FtqPtr)
6009c6f1ddSLingrui98    ptr.flag  := f
6109c6f1ddSLingrui98    ptr.value := v
6209c6f1ddSLingrui98    ptr
6309c6f1ddSLingrui98  }
64cf7d6b7aSMuzi  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr =
6509c6f1ddSLingrui98    apply(!ptr.flag, ptr.value)
6609c6f1ddSLingrui98}
6709c6f1ddSLingrui98
6809c6f1ddSLingrui98class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
6909c6f1ddSLingrui98
7009c6f1ddSLingrui98  val io = IO(new Bundle() {
7109c6f1ddSLingrui98    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
7209c6f1ddSLingrui98    val ren   = Input(Vec(numRead, Bool()))
7309c6f1ddSLingrui98    val rdata = Output(Vec(numRead, gen))
7409c6f1ddSLingrui98    val waddr = Input(UInt(log2Up(FtqSize).W))
7509c6f1ddSLingrui98    val wen   = Input(Bool())
7609c6f1ddSLingrui98    val wdata = Input(gen)
7709c6f1ddSLingrui98  })
7809c6f1ddSLingrui98
7909c6f1ddSLingrui98  for (i <- 0 until numRead) {
80*93b51ff0SHuSipeng    val sram = Module(new SplittedSRAMTemplate(
81721555e1SHuSipeng      gen,
82721555e1SHuSipeng      set = FtqSize,
83721555e1SHuSipeng      way = 1,
84721555e1SHuSipeng      dataSplit = 2,
85721555e1SHuSipeng      singlePort = false,
86*93b51ff0SHuSipeng      withClockGate = true,
87721555e1SHuSipeng      hasMbist = hasMbist
88721555e1SHuSipeng    ))
8909c6f1ddSLingrui98    sram.io.r.req.valid       := io.ren(i)
9009c6f1ddSLingrui98    sram.io.r.req.bits.setIdx := io.raddr(i)
9109c6f1ddSLingrui98    io.rdata(i)               := sram.io.r.resp.data(0)
9209c6f1ddSLingrui98    sram.io.w.req.valid       := io.wen
9309c6f1ddSLingrui98    sram.io.w.req.bits.setIdx := io.waddr
9409c6f1ddSLingrui98    sram.io.w.req.bits.data   := VecInit(io.wdata)
9509c6f1ddSLingrui98  }
9609c6f1ddSLingrui98
9709c6f1ddSLingrui98}
9809c6f1ddSLingrui98
9909c6f1ddSLingrui98class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
10009c6f1ddSLingrui98  val startAddr     = UInt(VAddrBits.W)
101b37e4b45SLingrui98  val nextLineAddr  = UInt(VAddrBits.W)
10209c6f1ddSLingrui98  val isNextMask    = Vec(PredictWidth, Bool())
103b37e4b45SLingrui98  val fallThruError = Bool()
104b37e4b45SLingrui98  // val carry = Bool()
10509c6f1ddSLingrui98  def getPc(offset: UInt) = {
10685215037SLingrui98    def getHigher(pc: UInt) = pc(VAddrBits - 1, log2Ceil(PredictWidth) + instOffsetBits + 1)
10785215037SLingrui98    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth) + instOffsetBits, instOffsetBits)
108cf7d6b7aSMuzi    Cat(
109cf7d6b7aSMuzi      getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth) + instOffsetBits), nextLineAddr, startAddr)),
110cf7d6b7aSMuzi      getOffset(startAddr) + offset,
111cf7d6b7aSMuzi      0.U(instOffsetBits.W)
112cf7d6b7aSMuzi    )
11309c6f1ddSLingrui98  }
11409c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
115a229ab6cSLingrui98    def carryPos(addr: UInt) = addr(instOffsetBits + log2Ceil(PredictWidth) + 1)
116adc0b8dfSGuokai Chen    this.startAddr    := resp.pc(3)
117adc0b8dfSGuokai Chen    this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs
11809c6f1ddSLingrui98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
119935edac4STang Haojin      (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool
12009c6f1ddSLingrui98    ))
121adc0b8dfSGuokai Chen    this.fallThruError := resp.fallThruError(3)
12209c6f1ddSLingrui98    this
12309c6f1ddSLingrui98  }
124cf7d6b7aSMuzi  override def toPrintable: Printable =
125b37e4b45SLingrui98    p"startAddr:${Hexadecimal(startAddr)}"
12609c6f1ddSLingrui98}
12709c6f1ddSLingrui98
12809c6f1ddSLingrui98class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
12909c6f1ddSLingrui98  val brMask    = Vec(PredictWidth, Bool())
13009c6f1ddSLingrui98  val jmpInfo   = ValidUndirectioned(Vec(3, Bool()))
13109c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
13209c6f1ddSLingrui98  val jalTarget = UInt(VAddrBits.W)
13309c6f1ddSLingrui98  val rvcMask   = Vec(PredictWidth, Bool())
13409c6f1ddSLingrui98  def hasJal    = jmpInfo.valid && !jmpInfo.bits(0)
13509c6f1ddSLingrui98  def hasJalr   = jmpInfo.valid && jmpInfo.bits(0)
13609c6f1ddSLingrui98  def hasCall   = jmpInfo.valid && jmpInfo.bits(1)
13709c6f1ddSLingrui98  def hasRet    = jmpInfo.valid && jmpInfo.bits(2)
13809c6f1ddSLingrui98
13909c6f1ddSLingrui98  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
14009c6f1ddSLingrui98    val pds = pdWb.pd
14109c6f1ddSLingrui98    this.brMask        := VecInit(pds.map(pd => pd.isBr && pd.valid))
14209c6f1ddSLingrui98    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
143cf7d6b7aSMuzi    this.jmpInfo.bits := ParallelPriorityMux(
144cf7d6b7aSMuzi      pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
145cf7d6b7aSMuzi      pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))
146cf7d6b7aSMuzi    )
14709c6f1ddSLingrui98    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
14809c6f1ddSLingrui98    this.rvcMask   := VecInit(pds.map(pd => pd.isRVC))
14909c6f1ddSLingrui98    this.jalTarget := pdWb.jalTarget
15009c6f1ddSLingrui98  }
15109c6f1ddSLingrui98
15209c6f1ddSLingrui98  def toPd(offset: UInt) = {
15309c6f1ddSLingrui98    require(offset.getWidth == log2Ceil(PredictWidth))
15409c6f1ddSLingrui98    val pd = Wire(new PreDecodeInfo)
15509c6f1ddSLingrui98    pd.valid := true.B
15609c6f1ddSLingrui98    pd.isRVC := rvcMask(offset)
15709c6f1ddSLingrui98    val isBr   = brMask(offset)
15809c6f1ddSLingrui98    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
15909c6f1ddSLingrui98    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
16009c6f1ddSLingrui98    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
16109c6f1ddSLingrui98    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
16209c6f1ddSLingrui98    pd
16309c6f1ddSLingrui98  }
16409c6f1ddSLingrui98}
16509c6f1ddSLingrui98
166f9c51548Sssszwicclass PrefetchPtrDB(implicit p: Parameters) extends Bundle {
167f9c51548Sssszwic  val fromFtqPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
168f9c51548Sssszwic  val fromIfuPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
169f9c51548Sssszwic}
17009c6f1ddSLingrui98
1713711cf36S小造xu_zhclass Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo {
172abdc3a32Sxu_zh  val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None
1733711cf36S小造xu_zh}
17409c6f1ddSLingrui98
17509c6f1ddSLingrui98class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
17609c6f1ddSLingrui98  val meta      = UInt(MaxMetaLength.W)
177deb3a97eSGao-Zeyu  val ftb_entry = new FTBEntry
17809c6f1ddSLingrui98}
17909c6f1ddSLingrui98
18009c6f1ddSLingrui98class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
18109c6f1ddSLingrui98  val target   = UInt(VAddrBits.W)
18209c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
18309c6f1ddSLingrui98}
18409c6f1ddSLingrui98
18509c6f1ddSLingrui98class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
18654c6d89dSxiaofeibao-xjtu  val valid  = Output(Bool())
18709c6f1ddSLingrui98  val ptr    = Output(new FtqPtr)
18809c6f1ddSLingrui98  val offset = Output(UInt(log2Ceil(PredictWidth).W))
18909c6f1ddSLingrui98  val data   = Input(gen)
19054c6d89dSxiaofeibao-xjtu  def apply(valid: Bool, ptr: FtqPtr, offset: UInt) = {
19154c6d89dSxiaofeibao-xjtu    this.valid  := valid
19209c6f1ddSLingrui98    this.ptr    := ptr
19309c6f1ddSLingrui98    this.offset := offset
19409c6f1ddSLingrui98    this.data
19509c6f1ddSLingrui98  }
19609c6f1ddSLingrui98}
19709c6f1ddSLingrui98
19809c6f1ddSLingrui98class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
19909c6f1ddSLingrui98  val redirect       = Valid(new BranchPredictionRedirect)
20009c6f1ddSLingrui98  val update         = Valid(new BranchPredictionUpdate)
20109c6f1ddSLingrui98  val enq_ptr        = Output(new FtqPtr)
202fd3aa057SYuandongliang  val redirctFromIFU = Output(Bool())
20309c6f1ddSLingrui98}
20409c6f1ddSLingrui98
2052c9f4a9fSxu_zhclass BpuFlushInfo(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
20609c6f1ddSLingrui98  // when ifu pipeline is not stalled,
20709c6f1ddSLingrui98  // a packet from bpu s3 can reach f1 at most
20809c6f1ddSLingrui98  val s2 = Valid(new FtqPtr)
209cb4f77ceSLingrui98  val s3 = Valid(new FtqPtr)
210cf7d6b7aSMuzi  def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) =
21109c6f1ddSLingrui98    src.valid && !isAfter(src.bits, idx_to_flush)
21209c6f1ddSLingrui98  def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
213cb4f77ceSLingrui98  def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
21409c6f1ddSLingrui98}
2152c9f4a9fSxu_zh
2162c9f4a9fSxu_zhclass FtqToIfuIO(implicit p: Parameters) extends XSBundle {
2172c9f4a9fSxu_zh  val req              = Decoupled(new FetchRequestBundle)
2182c9f4a9fSxu_zh  val redirect         = Valid(new BranchPredictionRedirect)
2192c9f4a9fSxu_zh  val topdown_redirect = Valid(new BranchPredictionRedirect)
2202c9f4a9fSxu_zh  val flushFromBpu     = new BpuFlushInfo
22109c6f1ddSLingrui98}
22209c6f1ddSLingrui98
2232c9f4a9fSxu_zhclass FtqToICacheIO(implicit p: Parameters) extends XSBundle {
224c5c5edaeSJenius  // NOTE: req.bits must be prepare in T cycle
225c5c5edaeSJenius  // while req.valid is set true in T + 1 cycle
226c5c5edaeSJenius  val req = Decoupled(new FtqToICacheRequestBundle)
227c5c5edaeSJenius}
228c5c5edaeSJenius
2292c9f4a9fSxu_zhclass FtqToPrefetchIO(implicit p: Parameters) extends XSBundle {
230b92f8445Sssszwic  val req              = Decoupled(new FtqICacheInfo)
2312c9f4a9fSxu_zh  val flushFromBpu     = new BpuFlushInfo
232fbdb359dSMuzi  val backendException = UInt(ExceptionType.width.W)
233b92f8445Sssszwic}
234b92f8445Sssszwic
23509c6f1ddSLingrui98trait HasBackendRedirectInfo extends HasXSParameter {
23609c6f1ddSLingrui98  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
23709c6f1ddSLingrui98}
23809c6f1ddSLingrui98
23909c6f1ddSLingrui98class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
240b56f947eSYinan Xu  // write to backend pc mem
241b56f947eSYinan Xu  val pc_mem_wen   = Output(Bool())
242f533cba7SHuSipeng  val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W))
243b56f947eSYinan Xu  val pc_mem_wdata = Output(new Ftq_RF_Components)
244873dc383SLingrui98  // newest target
2456022c595SsinceforYy  val newest_entry_en     = Output(Bool())
246873dc383SLingrui98  val newest_entry_target = Output(UInt(VAddrBits.W))
247873dc383SLingrui98  val newest_entry_ptr    = Output(new FtqPtr)
24809c6f1ddSLingrui98}
24909c6f1ddSLingrui98
25009c6f1ddSLingrui98class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
25109c6f1ddSLingrui98  val io = IO(new Bundle {
25209c6f1ddSLingrui98    val start_addr     = Input(UInt(VAddrBits.W))
25309c6f1ddSLingrui98    val old_entry      = Input(new FTBEntry)
25409c6f1ddSLingrui98    val pd             = Input(new Ftq_pd_Entry)
25509c6f1ddSLingrui98    val cfiIndex       = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
25609c6f1ddSLingrui98    val target         = Input(UInt(VAddrBits.W))
25709c6f1ddSLingrui98    val hit            = Input(Bool())
25809c6f1ddSLingrui98    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
25909c6f1ddSLingrui98
26009c6f1ddSLingrui98    val new_entry         = Output(new FTBEntry)
26109c6f1ddSLingrui98    val new_br_insert_pos = Output(Vec(numBr, Bool()))
26209c6f1ddSLingrui98    val taken_mask        = Output(Vec(numBr, Bool()))
263803124a6SLingrui98    val jmp_taken         = Output(Bool())
26409c6f1ddSLingrui98    val mispred_mask      = Output(Vec(numBr + 1, Bool()))
26509c6f1ddSLingrui98
26609c6f1ddSLingrui98    // for perf counters
26709c6f1ddSLingrui98    val is_init_entry           = Output(Bool())
26809c6f1ddSLingrui98    val is_old_entry            = Output(Bool())
26909c6f1ddSLingrui98    val is_new_br               = Output(Bool())
27009c6f1ddSLingrui98    val is_jalr_target_modified = Output(Bool())
271dcf4211fSYuandongliang    val is_strong_bias_modified = Output(Bool())
27209c6f1ddSLingrui98    val is_br_full              = Output(Bool())
27309c6f1ddSLingrui98  })
27409c6f1ddSLingrui98
27509c6f1ddSLingrui98  // no mispredictions detected at predecode
27609c6f1ddSLingrui98  val hit = io.hit
27709c6f1ddSLingrui98  val pd  = io.pd
27809c6f1ddSLingrui98
27909c6f1ddSLingrui98  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
28009c6f1ddSLingrui98
28109c6f1ddSLingrui98  val cfi_is_br       = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
28209c6f1ddSLingrui98  val entry_has_jmp   = pd.jmpInfo.valid
28309c6f1ddSLingrui98  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
28409c6f1ddSLingrui98  val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid
28509c6f1ddSLingrui98  val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid
28609c6f1ddSLingrui98  val new_jmp_is_ret  = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid
28709c6f1ddSLingrui98  val last_jmp_rvi    = entry_has_jmp && pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask.last
288a60a2901SLingrui98  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
28909c6f1ddSLingrui98
29009c6f1ddSLingrui98  val cfi_is_jal  = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
29109c6f1ddSLingrui98  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
29209c6f1ddSLingrui98
293a60a2901SLingrui98  def carryPos = log2Ceil(PredictWidth) + instOffsetBits
29409c6f1ddSLingrui98  def getLower(pc: UInt) = pc(carryPos - 1, instOffsetBits)
29509c6f1ddSLingrui98  // if not hit, establish a new entry
29609c6f1ddSLingrui98  init_entry.valid := true.B
29709c6f1ddSLingrui98  // tag is left for ftb to assign
298eeb5ff92SLingrui98
299eeb5ff92SLingrui98  // case br
300eeb5ff92SLingrui98  val init_br_slot = init_entry.getSlotForBr(0)
301eeb5ff92SLingrui98  when(cfi_is_br) {
302eeb5ff92SLingrui98    init_br_slot.valid  := true.B
303eeb5ff92SLingrui98    init_br_slot.offset := io.cfiIndex.bits
304b37e4b45SLingrui98    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
305dcf4211fSYuandongliang    init_entry.strong_bias(0) := true.B // set to strong bias on init
306eeb5ff92SLingrui98  }
307eeb5ff92SLingrui98
308eeb5ff92SLingrui98  // case jmp
309eeb5ff92SLingrui98  when(entry_has_jmp) {
310eeb5ff92SLingrui98    init_entry.tailSlot.offset := pd.jmpOffset
311eeb5ff92SLingrui98    init_entry.tailSlot.valid  := new_jmp_is_jal || new_jmp_is_jalr
312eeb5ff92SLingrui98    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare = false)
313dcf4211fSYuandongliang    init_entry.strong_bias(numBr - 1) := new_jmp_is_jalr // set strong bias for the jalr on init
314eeb5ff92SLingrui98  }
315eeb5ff92SLingrui98
31609c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
317a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
318a60a2901SLingrui98  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos - instOffsetBits), true.B)
3194d53e0efSzhou tao
3204d53e0efSzhou tao  require(
3214d53e0efSzhou tao    isPow2(PredictWidth),
3224d53e0efSzhou tao    "If PredictWidth does not satisfy the power of 2," +
3234d53e0efSzhou tao      "pftAddr := getLower(io.start_addr) and carry := true.B  not working!!"
3244d53e0efSzhou tao  )
3254d53e0efSzhou tao
32609c6f1ddSLingrui98  init_entry.isJalr := new_jmp_is_jalr
32709c6f1ddSLingrui98  init_entry.isCall := new_jmp_is_call
32809c6f1ddSLingrui98  init_entry.isRet  := new_jmp_is_ret
329f4ebc4b2SLingrui98  // that means fall thru points to the middle of an inst
330ae409b75SSteve Gou  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask(pd.jmpOffset)
33109c6f1ddSLingrui98
33209c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
33309c6f1ddSLingrui98  val oe              = io.old_entry
334eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
33509c6f1ddSLingrui98  val br_recorded     = br_recorded_vec.asUInt.orR
33609c6f1ddSLingrui98  val is_new_br       = cfi_is_br && !br_recorded
33709c6f1ddSLingrui98  val new_br_offset   = io.cfiIndex.bits
33809c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
339eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
34009c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map {
341cf7d6b7aSMuzi    i =>
342cf7d6b7aSMuzi      i match {
343eeb5ff92SLingrui98        case 0 =>
344eeb5ff92SLingrui98          !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
345eeb5ff92SLingrui98        case idx =>
346eeb5ff92SLingrui98          allBrSlotsVec(idx - 1).valid && new_br_offset > allBrSlotsVec(idx - 1).offset &&
347eeb5ff92SLingrui98          (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
34809c6f1ddSLingrui98      }
34909c6f1ddSLingrui98  })
35009c6f1ddSLingrui98
35109c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
35209c6f1ddSLingrui98  for (i <- 0 until numBr) {
353eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
354eeb5ff92SLingrui98    when(new_br_insert_onehot(i)) {
355eeb5ff92SLingrui98      slot.valid  := true.B
356eeb5ff92SLingrui98      slot.offset := new_br_offset
357b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr - 1)
358dcf4211fSYuandongliang      old_entry_modified.strong_bias(i) := true.B
359eeb5ff92SLingrui98    }.elsewhen(new_br_offset > oe.allSlotsForBr(i).offset) {
360dcf4211fSYuandongliang      old_entry_modified.strong_bias(i) := false.B
361eeb5ff92SLingrui98      // all other fields remain unchanged
362eeb5ff92SLingrui98    }.otherwise {
363eeb5ff92SLingrui98      // case i == 0, remain unchanged
364eeb5ff92SLingrui98      if (i != 0) {
365b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr - 1).B && !oe.brSlots.last.valid
366eeb5ff92SLingrui98        when(!noNeedToMoveFromFormerSlot) {
367eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i - 1))
368dcf4211fSYuandongliang          old_entry_modified.strong_bias(i) := oe.strong_bias(i)
36909c6f1ddSLingrui98        }
370eeb5ff92SLingrui98      }
371eeb5ff92SLingrui98    }
372eeb5ff92SLingrui98  }
37309c6f1ddSLingrui98
374eeb5ff92SLingrui98  // two circumstances:
375eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
376eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
377eeb5ff92SLingrui98  //        the previous last br or the new br
378eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
379eeb5ff92SLingrui98  val pft_need_to_change  = is_new_br && may_have_to_replace
38009c6f1ddSLingrui98  // it should either be the given last br or the new br
38109c6f1ddSLingrui98  when(pft_need_to_change) {
382eeb5ff92SLingrui98    val new_pft_offset =
383cf7d6b7aSMuzi      Mux(!new_br_insert_onehot.asUInt.orR, new_br_offset, oe.allSlotsForBr.last.offset)
384eeb5ff92SLingrui98
385710a8720SLingrui98    // set jmp to invalid
38609c6f1ddSLingrui98    old_entry_modified.pftAddr              := getLower(io.start_addr) + new_pft_offset
38709c6f1ddSLingrui98    old_entry_modified.carry                := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
388f4ebc4b2SLingrui98    old_entry_modified.last_may_be_rvi_call := false.B
38909c6f1ddSLingrui98    old_entry_modified.isCall               := false.B
39009c6f1ddSLingrui98    old_entry_modified.isRet                := false.B
391eeb5ff92SLingrui98    old_entry_modified.isJalr               := false.B
39209c6f1ddSLingrui98  }
39309c6f1ddSLingrui98
39409c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
395710a8720SLingrui98  val old_target      = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
396b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
397eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3983bcae573SLingrui98  when(jalr_target_modified) {
39909c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
400dcf4211fSYuandongliang    old_entry_jmp_target_modified.strong_bias := 0.U.asTypeOf(Vec(numBr, Bool()))
40109c6f1ddSLingrui98  }
40209c6f1ddSLingrui98
403dcf4211fSYuandongliang  val old_entry_strong_bias    = WireInit(oe)
404dcf4211fSYuandongliang  val strong_bias_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
40509c6f1ddSLingrui98  for (i <- 0 until numBr) {
406dcf4211fSYuandongliang    when(br_recorded_vec(0)) {
407dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(0) :=
408dcf4211fSYuandongliang        oe.strong_bias(0) && io.cfiIndex.valid && oe.brValids(0) && io.cfiIndex.bits === oe.brOffset(0)
409dcf4211fSYuandongliang    }.elsewhen(br_recorded_vec(numBr - 1)) {
410dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(0) := false.B
411dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(numBr - 1) :=
412dcf4211fSYuandongliang        oe.strong_bias(numBr - 1) && io.cfiIndex.valid && oe.brValids(numBr - 1) && io.cfiIndex.bits === oe.brOffset(
413dcf4211fSYuandongliang          numBr - 1
414dcf4211fSYuandongliang        )
41509c6f1ddSLingrui98    }
416dcf4211fSYuandongliang    strong_bias_modified_vec(i) := oe.strong_bias(i) && oe.brValids(i) && !old_entry_strong_bias.strong_bias(i)
417dcf4211fSYuandongliang  }
418dcf4211fSYuandongliang  val strong_bias_modified = strong_bias_modified_vec.reduce(_ || _)
41909c6f1ddSLingrui98
42009c6f1ddSLingrui98  val derived_from_old_entry =
421dcf4211fSYuandongliang    Mux(is_new_br, old_entry_modified, Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_strong_bias))
42209c6f1ddSLingrui98
42309c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
42409c6f1ddSLingrui98
42509c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
42609c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map {
42709c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
42809c6f1ddSLingrui98  })
429803124a6SLingrui98  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
43009c6f1ddSLingrui98  for (i <- 0 until numBr) {
43109c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
43209c6f1ddSLingrui98  }
43309c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
43409c6f1ddSLingrui98
43509c6f1ddSLingrui98  // for perf counters
43609c6f1ddSLingrui98  io.is_init_entry           := !hit
437dcf4211fSYuandongliang  io.is_old_entry            := hit && !is_new_br && !jalr_target_modified && !strong_bias_modified
43809c6f1ddSLingrui98  io.is_new_br               := hit && is_new_br
4393bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
440dcf4211fSYuandongliang  io.is_strong_bias_modified := hit && strong_bias_modified
441eeb5ff92SLingrui98  io.is_br_full              := hit && is_new_br && may_have_to_replace
44209c6f1ddSLingrui98}
44309c6f1ddSLingrui98
444c5c5edaeSJeniusclass FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
445c5c5edaeSJenius  val io = IO(new Bundle {
446c5c5edaeSJenius    val ifuPtr_w           = Input(new FtqPtr)
447c5c5edaeSJenius    val ifuPtrPlus1_w      = Input(new FtqPtr)
4486bf9b30dSLingrui98    val ifuPtrPlus2_w      = Input(new FtqPtr)
449b92f8445Sssszwic    val pfPtr_w            = Input(new FtqPtr)
450b92f8445Sssszwic    val pfPtrPlus1_w       = Input(new FtqPtr)
451c5c5edaeSJenius    val commPtr_w          = Input(new FtqPtr)
4526bf9b30dSLingrui98    val commPtrPlus1_w     = Input(new FtqPtr)
453c5c5edaeSJenius    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
454c5c5edaeSJenius    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
4556bf9b30dSLingrui98    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
456b92f8445Sssszwic    val pfPtr_rdata        = Output(new Ftq_RF_Components)
457b92f8445Sssszwic    val pfPtrPlus1_rdata   = Output(new Ftq_RF_Components)
458c5c5edaeSJenius    val commPtr_rdata      = Output(new Ftq_RF_Components)
4596bf9b30dSLingrui98    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
460c5c5edaeSJenius
461c5c5edaeSJenius    val wen   = Input(Bool())
462c5c5edaeSJenius    val waddr = Input(UInt(log2Ceil(FtqSize).W))
463c5c5edaeSJenius    val wdata = Input(new Ftq_RF_Components)
464c5c5edaeSJenius  })
465c5c5edaeSJenius
4666bf9b30dSLingrui98  val num_pc_read = numOtherReads + 5
467cf7d6b7aSMuzi  val mem         = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, num_pc_read, 1, "FtqPC"))
468c5c5edaeSJenius  mem.io.wen(0)   := io.wen
469c5c5edaeSJenius  mem.io.waddr(0) := io.waddr
470c5c5edaeSJenius  mem.io.wdata(0) := io.wdata
471c5c5edaeSJenius
4726bf9b30dSLingrui98  // read one cycle ahead for ftq local reads
473cf7d6b7aSMuzi  val raddr_vec = VecInit(Seq(
474cf7d6b7aSMuzi    io.ifuPtr_w.value,
475cf7d6b7aSMuzi    io.ifuPtrPlus1_w.value,
476cf7d6b7aSMuzi    io.ifuPtrPlus2_w.value,
477cf7d6b7aSMuzi    io.pfPtr_w.value,
478cf7d6b7aSMuzi    io.pfPtrPlus1_w.value,
479cf7d6b7aSMuzi    io.commPtrPlus1_w.value,
480cf7d6b7aSMuzi    io.commPtr_w.value
481cf7d6b7aSMuzi  ))
482c5c5edaeSJenius
483c5c5edaeSJenius  mem.io.raddr := raddr_vec
484c5c5edaeSJenius
485b92f8445Sssszwic  io.ifuPtr_rdata       := mem.io.rdata.dropRight(6).last
486b92f8445Sssszwic  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(5).last
487b92f8445Sssszwic  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(4).last
488b92f8445Sssszwic  io.pfPtr_rdata        := mem.io.rdata.dropRight(3).last
489b92f8445Sssszwic  io.pfPtrPlus1_rdata   := mem.io.rdata.dropRight(2).last
4906bf9b30dSLingrui98  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
491c5c5edaeSJenius  io.commPtr_rdata      := mem.io.rdata.last
492c5c5edaeSJenius}
493c5c5edaeSJenius
49409c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
495e30430c2SJay    with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
496e30430c2SJay    with HasICacheParameters {
49709c6f1ddSLingrui98  val io = IO(new Bundle {
49809c6f1ddSLingrui98    val fromBpu     = Flipped(new BpuToFtqIO)
49909c6f1ddSLingrui98    val fromIfu     = Flipped(new IfuToFtqIO)
50009c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
50109c6f1ddSLingrui98
50209c6f1ddSLingrui98    val toBpu       = new FtqToBpuIO
50309c6f1ddSLingrui98    val toIfu       = new FtqToIfuIO
504c5c5edaeSJenius    val toICache    = new FtqToICacheIO
50509c6f1ddSLingrui98    val toBackend   = new FtqToCtrlIO
506b92f8445Sssszwic    val toPrefetch  = new FtqToPrefetchIO
507b92f8445Sssszwic    val icacheFlush = Output(Bool())
5087052722fSJay
50909c6f1ddSLingrui98    val bpuInfo = new Bundle {
51009c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
51109c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
51209c6f1ddSLingrui98    }
5131d1e6d4dSJenius
5141d1e6d4dSJenius    val mmioCommitRead = Flipped(new mmioCommitRead)
515d2b20d1aSTang Haojin
516d2b20d1aSTang Haojin    // for perf
517d2b20d1aSTang Haojin    val ControlBTBMissBubble = Output(Bool())
518d2b20d1aSTang Haojin    val TAGEMissBubble       = Output(Bool())
519d2b20d1aSTang Haojin    val SCMissBubble         = Output(Bool())
520d2b20d1aSTang Haojin    val ITTAGEMissBubble     = Output(Bool())
521d2b20d1aSTang Haojin    val RASMissBubble        = Output(Bool())
52209c6f1ddSLingrui98  })
52309c6f1ddSLingrui98  io.bpuInfo := DontCare
52409c6f1ddSLingrui98
525d2b20d1aSTang Haojin  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
526d2b20d1aSTang Haojin  // only driven by clock, not valid-ready
527d2b20d1aSTang Haojin  topdown_stage                  := io.fromBpu.resp.bits.topdown_info
528d2b20d1aSTang Haojin  io.toIfu.req.bits.topdown_info := topdown_stage
529d2b20d1aSTang Haojin
530d2b20d1aSTang Haojin  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
531d2b20d1aSTang Haojin
53242dddaceSXuan Hu  // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception
53342dddaceSXuan Hu  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju
53442dddaceSXuan Hu  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0)
535bace178aSGao-Zeyu
536bace178aSGao-Zeyu  val aheadValid         = ftqIdxAhead.map(_.valid).reduce(_ | _) && !io.fromBackend.redirect.valid
537bace178aSGao-Zeyu  val realAhdValid       = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
538d2b20d1aSTang Haojin  val backendRedirect    = Wire(Valid(new BranchPredictionRedirect))
5391c6fc24aSEaston Man  val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect))
5401c6fc24aSEaston Man  backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid))
5411c6fc24aSEaston Man  backendRedirectReg.bits  := RegEnable(backendRedirect.bits, backendRedirect.valid)
542bace178aSGao-Zeyu  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
543bace178aSGao-Zeyu  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
54409c6f1ddSLingrui98
545df5b4b8eSYinan Xu  val stage2Flush  = backendRedirect.valid
54609c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
54709c6f1ddSLingrui98  val ifuFlush     = Wire(Bool())
54809c6f1ddSLingrui98
54909c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
55009c6f1ddSLingrui98
55109c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
55209c6f1ddSLingrui98  val flushToIfu             = !allowToIfu
553bace178aSGao-Zeyu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
554bace178aSGao-Zeyu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
55509c6f1ddSLingrui98
556f56177cbSJenius  def copyNum                                              = 5
557b92f8445Sssszwic  val bpuPtr, ifuPtr, pfPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U))
558c9bc5480SLingrui98  val ifuPtrPlus1                                          = RegInit(FtqPtr(false.B, 1.U))
5596bf9b30dSLingrui98  val ifuPtrPlus2                                          = RegInit(FtqPtr(false.B, 2.U))
560b92f8445Sssszwic  val pfPtrPlus1                                           = RegInit(FtqPtr(false.B, 1.U))
5616bf9b30dSLingrui98  val commPtrPlus1                                         = RegInit(FtqPtr(false.B, 1.U))
562f56177cbSJenius  val copied_ifu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
563dc270d3bSJenius  val copied_bpu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
5646bf9b30dSLingrui98  require(FtqSize >= 4)
565c5c5edaeSJenius  val ifuPtr_write       = WireInit(ifuPtr)
566c5c5edaeSJenius  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
5676bf9b30dSLingrui98  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
568b92f8445Sssszwic  val pfPtr_write        = WireInit(pfPtr)
569b92f8445Sssszwic  val pfPtrPlus1_write   = WireInit(pfPtrPlus1)
570c5c5edaeSJenius  val ifuWbPtr_write     = WireInit(ifuWbPtr)
571c5c5edaeSJenius  val commPtr_write      = WireInit(commPtr)
5726bf9b30dSLingrui98  val commPtrPlus1_write = WireInit(commPtrPlus1)
57389cc69c1STang Haojin  val robCommPtr_write   = WireInit(robCommPtr)
574c5c5edaeSJenius  ifuPtr       := ifuPtr_write
575c5c5edaeSJenius  ifuPtrPlus1  := ifuPtrPlus1_write
5766bf9b30dSLingrui98  ifuPtrPlus2  := ifuPtrPlus2_write
577b92f8445Sssszwic  pfPtr        := pfPtr_write
578b92f8445Sssszwic  pfPtrPlus1   := pfPtrPlus1_write
579c5c5edaeSJenius  ifuWbPtr     := ifuWbPtr_write
580c5c5edaeSJenius  commPtr      := commPtr_write
581f83ef67eSLingrui98  commPtrPlus1 := commPtrPlus1_write
582f56177cbSJenius  copied_ifu_ptr.map { ptr =>
583f56177cbSJenius    ptr := ifuPtr_write
584f56177cbSJenius    dontTouch(ptr)
585f56177cbSJenius  }
58689cc69c1STang Haojin  robCommPtr := robCommPtr_write
58709c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
58843aca6c2SGuokai Chen  val canCommit    = Wire(Bool())
58909c6f1ddSLingrui98
590c1b28b66STang Haojin  // Instruction page fault and instruction access fault are sent from backend with redirect requests.
591c1b28b66STang Haojin  // When IPF and IAF are sent, backendPcFaultIfuPtr points to the FTQ entry whose first instruction
592c1b28b66STang Haojin  // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write.
593c1b28b66STang Haojin  // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this
594c1b28b66STang Haojin  // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests.
595fbdb359dSMuzi  val backendException  = RegInit(ExceptionType.none)
596c1b28b66STang Haojin  val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U))
597c1b28b66STang Haojin  when(fromBackendRedirect.valid) {
598fbdb359dSMuzi    backendException := ExceptionType.fromOH(
599fbdb359dSMuzi      has_pf = fromBackendRedirect.bits.cfiUpdate.backendIPF,
600fbdb359dSMuzi      has_gpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF,
601fbdb359dSMuzi      has_af = fromBackendRedirect.bits.cfiUpdate.backendIAF
602fbdb359dSMuzi    )
603cf7d6b7aSMuzi    when(
604fbdb359dSMuzi      fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF ||
605fbdb359dSMuzi        fromBackendRedirect.bits.cfiUpdate.backendIAF
606cf7d6b7aSMuzi    ) {
607c1b28b66STang Haojin      backendPcFaultPtr := ifuWbPtr_write
608c1b28b66STang Haojin    }
609c1b28b66STang Haojin  }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) {
610fbdb359dSMuzi    backendException := ExceptionType.none
611c1b28b66STang Haojin  }
612c1b28b66STang Haojin
61309c6f1ddSLingrui98  // **********************************************************************
61409c6f1ddSLingrui98  // **************************** enq from bpu ****************************
61509c6f1ddSLingrui98  // **********************************************************************
61643aca6c2SGuokai Chen  val new_entry_ready = validEntries < FtqSize.U || canCommit
61709c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
61809c6f1ddSLingrui98
61909c6f1ddSLingrui98  val bpu_s2_resp     = io.fromBpu.resp.bits.s2
620cb4f77ceSLingrui98  val bpu_s3_resp     = io.fromBpu.resp.bits.s3
621adc0b8dfSGuokai Chen  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
622adc0b8dfSGuokai Chen  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
62309c6f1ddSLingrui98
62409c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
625935edac4STang Haojin  val enq_fire    = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
626935edac4STang Haojin  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
62709c6f1ddSLingrui98
628b37e4b45SLingrui98  val bpu_in_resp     = io.fromBpu.resp.bits.selectedResp
629adc0b8dfSGuokai Chen  val bpu_in_stage    = io.fromBpu.resp.bits.selectedRespIdxForFtq
63009c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
63109c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
63209c6f1ddSLingrui98
633b92f8445Sssszwic  // read ports:      pfReq1 + pfReq2 ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
634b92f8445Sssszwic  val ftq_pc_mem = Module(new FtqPcMemWrapper(2))
6356bf9b30dSLingrui98  // resp from uBTB
636c5c5edaeSJenius  ftq_pc_mem.io.wen   := bpu_in_fire
637c5c5edaeSJenius  ftq_pc_mem.io.waddr := bpu_in_resp_idx
638c5c5edaeSJenius  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
63909c6f1ddSLingrui98
64009c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
641cf7d6b7aSMuzi  val ftq_redirect_mem = Module(new SyncDataModuleTemplate(
642cf7d6b7aSMuzi    new Ftq_Redirect_SRAMEntry,
643cf7d6b7aSMuzi    FtqSize,
644cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum + 1,
645cf7d6b7aSMuzi    1,
646cf7d6b7aSMuzi    hasRen = true
647cf7d6b7aSMuzi  ))
64809c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
649deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
650deb3a97eSGao-Zeyu  ftq_redirect_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
651deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_spec_info
652deb3a97eSGao-Zeyu  println(f"ftq redirect MEM: entry ${ftq_redirect_mem.io.wdata(0).getWidth} * ${FtqSize} * 3")
65309c6f1ddSLingrui98
65409c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
65509c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
656adc0b8dfSGuokai Chen  ftq_meta_1r_sram.io.wen             := io.fromBpu.resp.bits.lastStage.valid(3)
65709c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr           := io.fromBpu.resp.bits.lastStage.ftq_idx.value
658c2d1ec7dSLingrui98  ftq_meta_1r_sram.io.wdata.meta      := io.fromBpu.resp.bits.last_stage_meta
659deb3a97eSGao-Zeyu  ftq_meta_1r_sram.io.wdata.ftb_entry := io.fromBpu.resp.bits.last_stage_ftb_entry
66095a47398SGao-Zeyu  //                                                            ifuRedirect + backendRedirect (commit moved to ftq_meta_1r_sram)
661cf7d6b7aSMuzi  val ftb_entry_mem = Module(new SyncDataModuleTemplate(
662cf7d6b7aSMuzi    new FTBEntry_FtqMem,
663cf7d6b7aSMuzi    FtqSize,
664cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum,
665cf7d6b7aSMuzi    1,
666cf7d6b7aSMuzi    hasRen = true
667cf7d6b7aSMuzi  ))
668adc0b8dfSGuokai Chen  ftb_entry_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
66909c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
670c2d1ec7dSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
6714b2c87baS梁森 Liang Sen  private val mbistPl = MbistPipeline.PlaceMbistPipeline(1, "MbistPipeFtq", hasMbist)
67209c6f1ddSLingrui98
67309c6f1ddSLingrui98  // multi-write
674b0ed7239SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
6756bf9b30dSLingrui98  val newest_entry_target          = Reg(UInt(VAddrBits.W))
6761c6fc24aSEaston Man  val newest_entry_target_modified = RegInit(false.B)
6776bf9b30dSLingrui98  val newest_entry_ptr             = Reg(new FtqPtr)
6781c6fc24aSEaston Man  val newest_entry_ptr_modified    = RegInit(false.B)
67909c6f1ddSLingrui98  val cfiIndex_vec                 = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
68009c6f1ddSLingrui98  val mispredict_vec               = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
68109c6f1ddSLingrui98  val pred_stage                   = Reg(Vec(FtqSize, UInt(2.W)))
682209a4cafSSteve Gou  val pred_s1_cycle                = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
68309c6f1ddSLingrui98
68491346769SMuzi  val c_empty :: c_toCommit :: c_committed :: c_flushed :: Nil = Enum(4)
6851c6fc24aSEaston Man  val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) {
68691346769SMuzi    VecInit(Seq.fill(PredictWidth)(c_empty))
68709c6f1ddSLingrui98  }))
6881c6fc24aSEaston Man  val commitStateQueueEnable = WireInit(VecInit(Seq.fill(FtqSize)(false.B)))
6891c6fc24aSEaston Man  val commitStateQueueNext   = WireInit(commitStateQueueReg)
6901c6fc24aSEaston Man
6911c6fc24aSEaston Man  for (f <- 0 until FtqSize) {
6921c6fc24aSEaston Man    when(commitStateQueueEnable(f)) {
6931c6fc24aSEaston Man      commitStateQueueReg(f) := commitStateQueueNext(f)
6941c6fc24aSEaston Man    }
6951c6fc24aSEaston Man  }
69609c6f1ddSLingrui98
69709c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
69809c6f1ddSLingrui98  val entry_fetch_status         = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
69909c6f1ddSLingrui98
70009c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
70109c6f1ddSLingrui98  val entry_hit_status                         = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
70209c6f1ddSLingrui98
703f63797a4SLingrui98  // modify registers one cycle later to cut critical path
704f63797a4SLingrui98  val last_cycle_bpu_in       = RegNext(bpu_in_fire)
7051c6fc24aSEaston Man  val last_cycle_bpu_in_ptr   = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
7066bf9b30dSLingrui98  val last_cycle_bpu_in_idx   = last_cycle_bpu_in_ptr.value
7071c6fc24aSEaston Man  val last_cycle_bpu_target   = RegEnable(bpu_in_resp.getTarget(3), bpu_in_fire)
7081c6fc24aSEaston Man  val last_cycle_cfiIndex     = RegEnable(bpu_in_resp.cfiIndex(3), bpu_in_fire)
7091c6fc24aSEaston Man  val last_cycle_bpu_in_stage = RegEnable(bpu_in_stage, bpu_in_fire)
710f56177cbSJenius
7117be982afSLingrui98  def extra_copyNum_for_commitStateQueue = 2
7121c6fc24aSEaston Man  val copied_last_cycle_bpu_in =
7131c6fc24aSEaston Man    VecInit(Seq.fill(copyNum + extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
7141c6fc24aSEaston Man  val copied_last_cycle_bpu_in_ptr_for_ftq =
7151c6fc24aSEaston Man    VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
716f56177cbSJenius
7171c6fc24aSEaston Man  newest_entry_target_modified := false.B
7181c6fc24aSEaston Man  newest_entry_ptr_modified    := false.B
719f63797a4SLingrui98  when(last_cycle_bpu_in) {
720f63797a4SLingrui98    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
721f63797a4SLingrui98    cfiIndex_vec(last_cycle_bpu_in_idx)       := last_cycle_cfiIndex
722f63797a4SLingrui98    pred_stage(last_cycle_bpu_in_idx)         := last_cycle_bpu_in_stage
7236bf9b30dSLingrui98
724b0ed7239SLingrui98    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
7251c6fc24aSEaston Man    newest_entry_target_modified         := true.B
7266bf9b30dSLingrui98    newest_entry_target                  := last_cycle_bpu_target
7271c6fc24aSEaston Man    newest_entry_ptr_modified            := true.B
7286bf9b30dSLingrui98    newest_entry_ptr                     := last_cycle_bpu_in_ptr
72909c6f1ddSLingrui98  }
73009c6f1ddSLingrui98
7317be982afSLingrui98  // reduce fanout by delay write for a cycle
7327be982afSLingrui98  when(RegNext(last_cycle_bpu_in)) {
7331c6fc24aSEaston Man    mispredict_vec(RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)) :=
7341c6fc24aSEaston Man      WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
7357be982afSLingrui98  }
7367be982afSLingrui98
737209a4cafSSteve Gou  // record s1 pred cycles
738cf7d6b7aSMuzi  pred_s1_cycle.map { vec =>
739209a4cafSSteve Gou    when(bpu_in_fire && (bpu_in_stage === BP_S1)) {
740209a4cafSSteve Gou      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
741209a4cafSSteve Gou    }
742cf7d6b7aSMuzi  }
743209a4cafSSteve Gou
7447be982afSLingrui98  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
7457be982afSLingrui98  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
7467be982afSLingrui98  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
7477be982afSLingrui98    case ((in, ptr), i) =>
7487be982afSLingrui98      when(in) {
7497be982afSLingrui98        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
7507be982afSLingrui98        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
7517be982afSLingrui98        for (j <- 0 until perSetEntries) {
7529361b0c5SLingrui98          when(ptr.value === (i * perSetEntries + j).U) {
75391346769SMuzi            commitStateQueueNext(i * perSetEntries + j) := VecInit(Seq.fill(PredictWidth)(c_empty))
7541c6fc24aSEaston Man            // Clock gating optimization, use 1 gate cell to control a row
7551c6fc24aSEaston Man            commitStateQueueEnable(i * perSetEntries + j) := true.B
7567be982afSLingrui98          }
7577be982afSLingrui98        }
7587be982afSLingrui98      }
7599361b0c5SLingrui98  }
7607be982afSLingrui98
76109c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
762dc270d3bSJenius  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
763c9bc5480SLingrui98  when(io.toIfu.req.fire && allowToIfu) {
764c5c5edaeSJenius    ifuPtr_write      := ifuPtrPlus1
7656bf9b30dSLingrui98    ifuPtrPlus1_write := ifuPtrPlus2
7666bf9b30dSLingrui98    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
767c9bc5480SLingrui98  }
768b92f8445Sssszwic  when(io.toPrefetch.req.fire && allowToIfu) {
769b92f8445Sssszwic    pfPtr_write      := pfPtrPlus1
770b92f8445Sssszwic    pfPtrPlus1_write := pfPtrPlus1 + 1.U
771b92f8445Sssszwic  }
77209c6f1ddSLingrui98
77309c6f1ddSLingrui98  // only use ftb result to assign hit status
774adc0b8dfSGuokai Chen  when(bpu_s2_resp.valid(3)) {
775adc0b8dfSGuokai Chen    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
77609c6f1ddSLingrui98  }
77709c6f1ddSLingrui98
7782f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid      := bpu_s2_redirect
77909c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits       := bpu_s2_resp.ftq_idx
780b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.valid := bpu_s2_redirect
781b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.bits  := bpu_s2_resp.ftq_idx
782adc0b8dfSGuokai Chen  when(bpu_s2_redirect) {
78309c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
784dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
78509c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
78609c6f1ddSLingrui98    when(!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
787c5c5edaeSJenius      ifuPtr_write      := bpu_s2_resp.ftq_idx
788c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
7896bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
79009c6f1ddSLingrui98    }
791b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s2_resp.ftq_idx)) {
792b92f8445Sssszwic      pfPtr_write      := bpu_s2_resp.ftq_idx
793b92f8445Sssszwic      pfPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
794b92f8445Sssszwic    }
79509c6f1ddSLingrui98  }
79609c6f1ddSLingrui98
797cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid      := bpu_s3_redirect
798cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits       := bpu_s3_resp.ftq_idx
799b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.valid := bpu_s3_redirect
800b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.bits  := bpu_s3_resp.ftq_idx
801adc0b8dfSGuokai Chen  when(bpu_s3_redirect) {
802cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
803dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
804cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
805cb4f77ceSLingrui98    when(!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
806c5c5edaeSJenius      ifuPtr_write      := bpu_s3_resp.ftq_idx
807c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
8086bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
809cb4f77ceSLingrui98    }
810b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s3_resp.ftq_idx)) {
811b92f8445Sssszwic      pfPtr_write      := bpu_s3_resp.ftq_idx
812b92f8445Sssszwic      pfPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
813b92f8445Sssszwic    }
814cb4f77ceSLingrui98  }
815cb4f77ceSLingrui98
81609c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
817b92f8445Sssszwic  XSError(isBefore(bpuPtr, pfPtr) && !isFull(bpuPtr, pfPtr), "\npfPtr is before bpuPtr!\n")
8182448f137SGuokai Chen  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
81909c6f1ddSLingrui98
820cf7d6b7aSMuzi  (0 until copyNum).map(i => XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n"))
821dc270d3bSJenius
82209c6f1ddSLingrui98  // ****************************************************************
82309c6f1ddSLingrui98  // **************************** to ifu ****************************
82409c6f1ddSLingrui98  // ****************************************************************
825f22cf846SJenius  // 0  for ifu, and 1-4 for ICache
826935edac4STang Haojin  val bpu_in_bypass_buf         = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
827935edac4STang Haojin  val copied_bpu_in_bypass_buf  = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
828f56177cbSJenius  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
8291c6fc24aSEaston Man  val bpu_in_bypass_ptr         = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
83009c6f1ddSLingrui98  val last_cycle_to_ifu_fire    = RegNext(io.toIfu.req.fire)
831b92f8445Sssszwic  val last_cycle_to_pf_fire     = RegNext(io.toPrefetch.req.fire)
83209c6f1ddSLingrui98
8331c6fc24aSEaston Man  val copied_bpu_in_bypass_ptr      = VecInit(Seq.fill(copyNum)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
834f56177cbSJenius  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
83588bc4f90SLingrui98
83609c6f1ddSLingrui98  // read pc and target
8376bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
8386bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
8396bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
840b92f8445Sssszwic  ftq_pc_mem.io.pfPtr_w        := pfPtr_write
841b92f8445Sssszwic  ftq_pc_mem.io.pfPtrPlus1_w   := pfPtrPlus1_write
8426bf9b30dSLingrui98  ftq_pc_mem.io.commPtr_w      := commPtr_write
8436bf9b30dSLingrui98  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
844c5c5edaeSJenius
8455ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
846f63797a4SLingrui98
847f56177cbSJenius  val toICachePcBundle               = Wire(Vec(copyNum, new Ftq_RF_Components))
848dc270d3bSJenius  val toICacheEntryToSend            = Wire(Vec(copyNum, Bool()))
8493e1dbb17SMuzi  val nextCycleToPrefetchPcBundle    = Wire(new Ftq_RF_Components)
8503e1dbb17SMuzi  val nextCycleToPrefetchEntryToSend = Wire(Bool())
8513e1dbb17SMuzi  val toPrefetchPcBundle             = RegNext(nextCycleToPrefetchPcBundle)
8523e1dbb17SMuzi  val toPrefetchEntryToSend          = RegNext(nextCycleToPrefetchEntryToSend)
853b37e4b45SLingrui98  val toIfuPcBundle                  = Wire(new Ftq_RF_Components)
854f63797a4SLingrui98  val entry_is_to_send               = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
855f63797a4SLingrui98  val entry_ftq_offset               = WireInit(cfiIndex_vec(ifuPtr.value))
8566bf9b30dSLingrui98  val entry_next_addr                = Wire(UInt(VAddrBits.W))
857b004fa13SJenius
858f56177cbSJenius  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
859f56177cbSJenius  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
860b0ed7239SLingrui98  val diff_entry_next_addr   = WireInit(update_target(ifuPtr.value)) // TODO: remove this
861f63797a4SLingrui98
862cf7d6b7aSMuzi  val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(
863cf7d6b7aSMuzi    entry_fetch_status(ifuPtrPlus1.value) === f_to_send
864cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1)))
865cf7d6b7aSMuzi  val copied_ifu_ptr_to_send = VecInit(Seq.fill(copyNum)(RegNext(
866cf7d6b7aSMuzi    entry_fetch_status(ifuPtr.value) === f_to_send
867cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr)))
868dc270d3bSJenius
869f56177cbSJenius  for (i <- 0 until copyNum) {
870f56177cbSJenius    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)) {
871f56177cbSJenius      toICachePcBundle(i)    := copied_bpu_in_bypass_buf(i)
872dc270d3bSJenius      toICacheEntryToSend(i) := true.B
873f56177cbSJenius    }.elsewhen(copied_last_cycle_to_ifu_fire(i)) {
874f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_plus1_rdata(i)
875dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i)
876f56177cbSJenius    }.otherwise {
877f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_ptr_rdata(i)
878dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i)
879f56177cbSJenius    }
880f56177cbSJenius  }
881f56177cbSJenius
8823e1dbb17SMuzi  // Calculate requests sent to prefetcher one cycle in advance to cut critical path
8833e1dbb17SMuzi  when(bpu_in_fire && bpu_in_resp_ptr === pfPtr_write) {
8843e1dbb17SMuzi    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.wdata
8853e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := true.B
8863e1dbb17SMuzi  }.elsewhen(io.toPrefetch.req.fire) {
8873e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtrPlus1_rdata
8883e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtrPlus1.value) === f_to_send ||
8893e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtrPlus1
890b92f8445Sssszwic  }.otherwise {
8913e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtr_rdata
8923e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtr.value) === f_to_send ||
8933e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr // reduce potential bubbles
894b92f8445Sssszwic  }
895b92f8445Sssszwic
896873dc383SLingrui98  // TODO: reconsider target address bypass logic
89709c6f1ddSLingrui98  when(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
89888bc4f90SLingrui98    toIfuPcBundle        := bpu_in_bypass_buf_for_ifu
899f678dd91SSteve Gou    entry_is_to_send     := true.B
9006bf9b30dSLingrui98    entry_next_addr      := last_cycle_bpu_target
901f63797a4SLingrui98    entry_ftq_offset     := last_cycle_cfiIndex
902b0ed7239SLingrui98    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
90309c6f1ddSLingrui98  }.elsewhen(last_cycle_to_ifu_fire) {
904c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
905c5c5edaeSJenius    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
906cf7d6b7aSMuzi      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1) // reduce potential bubbles
907cf7d6b7aSMuzi    entry_next_addr := Mux(
908cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
90988bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
910cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))
911cf7d6b7aSMuzi    ) // ifuPtr+2
912c5c5edaeSJenius  }.otherwise {
913c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
91428f2cf58SLingrui98    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
91528f2cf58SLingrui98      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
916cf7d6b7aSMuzi    entry_next_addr := Mux(
917cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
91888bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
919cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))
920cf7d6b7aSMuzi    ) // ifuPtr+1
92109c6f1ddSLingrui98  }
92209c6f1ddSLingrui98
923f678dd91SSteve Gou  io.toIfu.req.valid              := entry_is_to_send && ifuPtr =/= bpuPtr
924f63797a4SLingrui98  io.toIfu.req.bits.nextStartAddr := entry_next_addr
925f63797a4SLingrui98  io.toIfu.req.bits.ftqOffset     := entry_ftq_offset
926b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
927c5c5edaeSJenius
928c5c5edaeSJenius  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
929cf7d6b7aSMuzi  io.toICache.req.bits.readValid.zipWithIndex.map { case (copy, i) =>
930cf7d6b7aSMuzi    copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)
931cf7d6b7aSMuzi  }
932b92f8445Sssszwic  io.toICache.req.bits.pcMemRead.zipWithIndex.foreach { case (copy, i) =>
933b92f8445Sssszwic    copy.fromFtqPcBundle(toICachePcBundle(i))
934b92f8445Sssszwic    copy.ftqIdx := ifuPtr
935b92f8445Sssszwic  }
936fbdb359dSMuzi  io.toICache.req.bits.backendException := ExceptionType.hasException(backendException) && backendPcFaultPtr === ifuPtr
937b92f8445Sssszwic
938b92f8445Sssszwic  io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
939b92f8445Sssszwic  io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle)
940b92f8445Sssszwic  io.toPrefetch.req.bits.ftqIdx  := pfPtr
941fbdb359dSMuzi  io.toPrefetch.backendException := Mux(backendPcFaultPtr === pfPtr, backendException, ExceptionType.none)
942b004fa13SJenius  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
943b004fa13SJenius  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
944b004fa13SJenius  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
945b004fa13SJenius  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
946b004fa13SJenius  // }
947f22cf846SJenius
948b0ed7239SLingrui98  // TODO: remove this
949cf7d6b7aSMuzi  XSError(
950cf7d6b7aSMuzi    io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
951cf7d6b7aSMuzi    p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n"
952cf7d6b7aSMuzi  )
953b0ed7239SLingrui98
95409c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
955b37e4b45SLingrui98  when(toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
95609c6f1ddSLingrui98    when(io.toIfu.req.fire &&
957cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
958cf7d6b7aSMuzi      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) {
95909c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
960352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
96109c6f1ddSLingrui98    }
9628b33cd30Sklin02  }
963cf7d6b7aSMuzi  XSDebug(
9648b33cd30Sklin02    toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit,
965cf7d6b7aSMuzi    "fallThruError! start:%x, fallThru:%x\n",
966cf7d6b7aSMuzi    io.toIfu.req.bits.startAddr,
967cf7d6b7aSMuzi    io.toIfu.req.bits.nextStartAddr
968cf7d6b7aSMuzi  )
96909c6f1ddSLingrui98
970cf7d6b7aSMuzi  XSPerfAccumulate(
971cf7d6b7aSMuzi    f"fall_through_error_to_ifu",
972cf7d6b7aSMuzi    toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
973cf7d6b7aSMuzi      io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
974cf7d6b7aSMuzi  )
975a60a2901SLingrui98
97609c6f1ddSLingrui98  val ifu_req_should_be_flushed =
977cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
978cb4f77ceSLingrui98      io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
97909c6f1ddSLingrui98
98009c6f1ddSLingrui98  when(io.toIfu.req.fire && !ifu_req_should_be_flushed) {
98109c6f1ddSLingrui98    entry_fetch_status(ifuPtr.value) := f_sent
98209c6f1ddSLingrui98  }
98309c6f1ddSLingrui98
98409c6f1ddSLingrui98  // *********************************************************************
98509c6f1ddSLingrui98  // **************************** wb from ifu ****************************
98609c6f1ddSLingrui98  // *********************************************************************
98709c6f1ddSLingrui98  val pdWb         = io.fromIfu.pdWb
98809c6f1ddSLingrui98  val pds          = pdWb.bits.pd
98909c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
99009c6f1ddSLingrui98  val ifu_wb_idx   = pdWb.bits.ftqIdx.value
99109c6f1ddSLingrui98  // read ports:                                                         commit update
992cf7d6b7aSMuzi  val ftq_pd_mem =
993cf7d6b7aSMuzi    Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum + 1, 1, hasRen = true))
99409c6f1ddSLingrui98  ftq_pd_mem.io.wen(0)   := ifu_wb_valid
99509c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
99609c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
99709c6f1ddSLingrui98
99809c6f1ddSLingrui98  val hit_pd_valid       = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
99909c6f1ddSLingrui98  val hit_pd_mispred     = hit_pd_valid && pdWb.bits.misOffset.valid
100009c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init = false.B)
1001005e809bSJiuyang Liu  val pd_reg             = RegEnable(pds, pdWb.valid)
1002005e809bSJiuyang Liu  val start_pc_reg       = RegEnable(pdWb.bits.pc(0), pdWb.valid)
1003005e809bSJiuyang Liu  val wb_idx_reg         = RegEnable(ifu_wb_idx, pdWb.valid)
100409c6f1ddSLingrui98
100509c6f1ddSLingrui98  when(ifu_wb_valid) {
100609c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map {
100709c6f1ddSLingrui98      case (v, inRange) => v && inRange
100809c6f1ddSLingrui98    })
10091c6fc24aSEaston Man    commitStateQueueEnable(ifu_wb_idx) := true.B
10101c6fc24aSEaston Man    (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map {
10111c6fc24aSEaston Man      case (qe, v) => when(v) {
101291346769SMuzi          qe := c_toCommit
10131c6fc24aSEaston Man        }
101409c6f1ddSLingrui98    }
101509c6f1ddSLingrui98  }
101609c6f1ddSLingrui98
1017c5c5edaeSJenius  when(ifu_wb_valid) {
1018c5c5edaeSJenius    ifuWbPtr_write := ifuWbPtr + 1.U
1019c5c5edaeSJenius  }
102009c6f1ddSLingrui98
1021f21bbcb2SGuokai Chen  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
1022f21bbcb2SGuokai Chen
10231c6fc24aSEaston Man  ftb_entry_mem.io.ren.get.head := ifu_wb_valid
102409c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head   := ifu_wb_idx
102509c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
102609c6f1ddSLingrui98  when(RegNext(hit_pd_valid)) {
102709c6f1ddSLingrui98    // check for false hit
102809c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
1029eeb5ff92SLingrui98    val brSlots        = pred_ftb_entry.brSlots
1030eeb5ff92SLingrui98    val tailSlot       = pred_ftb_entry.tailSlot
103109c6f1ddSLingrui98    // we check cfis that bpu predicted
103209c6f1ddSLingrui98
1033eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
1034eeb5ff92SLingrui98    val br_false_hit =
1035eeb5ff92SLingrui98      brSlots.map {
1036eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
1037eeb5ff92SLingrui98      }.reduce(_ || _) ||
1038b37e4b45SLingrui98        (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
1039eeb5ff92SLingrui98          !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
1040eeb5ff92SLingrui98
1041eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
104209c6f1ddSLingrui98    val jmp_pd    = pd_reg(jmpOffset)
104309c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
104409c6f1ddSLingrui98      ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) ||
104509c6f1ddSLingrui98        (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
104609c6f1ddSLingrui98        (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
1047cf7d6b7aSMuzi        (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)))
104809c6f1ddSLingrui98
104909c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
1050352db50aSLingrui98    // assert(!has_false_hit)
105109c6f1ddSLingrui98  }
10528b33cd30Sklin02  XSDebug(
10538b33cd30Sklin02    RegNext(hit_pd_valid) && has_false_hit,
10548b33cd30Sklin02    "FTB false hit by br or jal or hit_pd, startAddr: %x\n",
10558b33cd30Sklin02    pdWb.bits.pc(0)
10568b33cd30Sklin02  )
105709c6f1ddSLingrui98
105809c6f1ddSLingrui98  when(has_false_hit) {
105909c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
106009c6f1ddSLingrui98  }
106109c6f1ddSLingrui98
106209c6f1ddSLingrui98  // *******************************************************************************
106309c6f1ddSLingrui98  // **************************** redirect from backend ****************************
106409c6f1ddSLingrui98  // *******************************************************************************
106509c6f1ddSLingrui98
106609c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
106795a47398SGao-Zeyu  // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1)
1068bace178aSGao-Zeyu  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
1069deb3a97eSGao-Zeyu  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem))
1070c776f0d5Smy-mayfly
1071c776f0d5Smy-mayfly  val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry))
107295a47398SGao-Zeyu  for (i <- 1 until FtqRedirectAheadNum) {
107395a47398SGao-Zeyu    ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid
107495a47398SGao-Zeyu    ftq_redirect_mem.io.raddr(i + IfuRedirectNum)   := ftqIdxAhead(i).bits.value
107595a47398SGao-Zeyu    ftb_entry_mem.io.ren.get(i + IfuRedirectNum)    := ftqIdxAhead(i).valid
107695a47398SGao-Zeyu    ftb_entry_mem.io.raddr(i + IfuRedirectNum)      := ftqIdxAhead(i).bits.value
1077c776f0d5Smy-mayfly
1078c776f0d5Smy-mayfly    ftq_pd_mem.io.ren.get(i) := ftqIdxAhead(i).valid
1079c776f0d5Smy-mayfly    ftq_pd_mem.io.raddr(i)   := ftqIdxAhead(i).bits.value
10809342624fSGao-Zeyu  }
108195a47398SGao-Zeyu  ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1082cf7d6b7aSMuzi  ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux(
1083cf7d6b7aSMuzi    aheadValid,
1084cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1085cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1086cf7d6b7aSMuzi  )
108795a47398SGao-Zeyu  ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1088cf7d6b7aSMuzi  ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux(
1089cf7d6b7aSMuzi    aheadValid,
1090cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1091cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1092cf7d6b7aSMuzi  )
1093bace178aSGao-Zeyu
1094c776f0d5Smy-mayfly  ftq_pd_mem.io.ren.get(0) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1095c776f0d5Smy-mayfly  ftq_pd_mem.io.raddr(0)   := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1096c776f0d5Smy-mayfly
1097bace178aSGao-Zeyu  for (i <- 0 until FtqRedirectAheadNum) {
109895a47398SGao-Zeyu    ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum)
109995a47398SGao-Zeyu    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum)
1100c776f0d5Smy-mayfly
1101c776f0d5Smy-mayfly    ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i)
1102bace178aSGao-Zeyu  }
1103cf7d6b7aSMuzi  val stage3CfiInfo =
1104cf7d6b7aSMuzi    Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum))
1105c776f0d5Smy-mayfly  val stage3PdInfo       = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0))
110609c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
110709c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
1108c776f0d5Smy-mayfly  backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset)
110909c6f1ddSLingrui98
111095a47398SGao-Zeyu  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum))
111109c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
111209c6f1ddSLingrui98
1113d2b20d1aSTang Haojin  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
1114d2b20d1aSTang Haojin  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
11153711cf36S小造xu_zh  // FIXME: not portable
1116abdc3a32Sxu_zh  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
1117cf7d6b7aSMuzi  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(
1118cf7d6b7aSMuzi    r_ftb_entry.brSlots(0).offset === r_ftqOffset,
1119cf7d6b7aSMuzi    sc_disagree(0),
1120cf7d6b7aSMuzi    sc_disagree(1)
1121cf7d6b7aSMuzi  )
1122d2b20d1aSTang Haojin
112309c6f1ddSLingrui98  when(entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
112409c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
112509c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
1126eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
112709c6f1ddSLingrui98
112809c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
1129eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
113009c6f1ddSLingrui98  }.otherwise {
113109c6f1ddSLingrui98    backendRedirectCfi.shift       := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
113209c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
113309c6f1ddSLingrui98  }
113409c6f1ddSLingrui98
113509c6f1ddSLingrui98  // ***************************************************************************
113609c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
113709c6f1ddSLingrui98  // ***************************************************************************
1138d2b20d1aSTang Haojin  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
113909c6f1ddSLingrui98  fromIfuRedirect.valid              := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
114009c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx        := pdWb.bits.ftqIdx
114109c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset     := pdWb.bits.misOffset.bits
114209c6f1ddSLingrui98  fromIfuRedirect.bits.level         := RedirectLevel.flushAfter
1143d2b20d1aSTang Haojin  fromIfuRedirect.bits.BTBMissBubble := true.B
1144d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsMemVio := false.B
1145d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsCtrl   := false.B
114609c6f1ddSLingrui98
114709c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
114809c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc        := pdWb.bits.pc(pdWb.bits.misOffset.bits)
114909c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd        := pdWb.bits.pd(pdWb.bits.misOffset.bits)
115009c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
115109c6f1ddSLingrui98  ifuRedirectCfiUpdate.target    := pdWb.bits.target
115209c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken     := pdWb.bits.cfiOffset.valid
115309c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
115409c6f1ddSLingrui98
11551c6fc24aSEaston Man  val ifuRedirectReg   = RegNextWithEnable(fromIfuRedirect, hasInit = true)
115609c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
115709c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
115809c6f1ddSLingrui98
115916a171eeSEaston Man  ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid
1160deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.head   := fromIfuRedirect.bits.ftqIdx.value
116109c6f1ddSLingrui98
116209c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
1163deb3a97eSGao-Zeyu  toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head)
1164f1267a13SEaston Man  when(ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
1165c89b4642SGuokai Chen    toBpuCfi.target := toBpuCfi.topAddr
116609c6f1ddSLingrui98  }
116709c6f1ddSLingrui98
1168d2b20d1aSTang Haojin  when(ifuRedirectReg.valid) {
1169d2b20d1aSTang Haojin    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
1170d2b20d1aSTang Haojin  }.elsewhen(RegNext(pdWb.valid)) {
1171d2b20d1aSTang Haojin    // if pdWb and no redirect, set to false
1172d2b20d1aSTang Haojin    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
1173d2b20d1aSTang Haojin  }
1174d2b20d1aSTang Haojin
11756022c595SsinceforYy  // **********************************************************************
11766022c595SsinceforYy  // ***************************** to backend *****************************
11776022c595SsinceforYy  // **********************************************************************
11786022c595SsinceforYy  // to backend pc mem / target
11796022c595SsinceforYy  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
1180f533cba7SHuSipeng  io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)
11816022c595SsinceforYy  io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in)
11826022c595SsinceforYy
11836022c595SsinceforYy  // num cycle is fixed
11846022c595SsinceforYy  val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid)
11856022c595SsinceforYy  io.toBackend.newest_entry_en     := RegNext(newest_entry_en)
11866022c595SsinceforYy  io.toBackend.newest_entry_ptr    := RegEnable(newest_entry_ptr, newest_entry_en)
11876022c595SsinceforYy  io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en)
11886022c595SsinceforYy
118909c6f1ddSLingrui98  // *********************************************************************
119009c6f1ddSLingrui98  // **************************** wb from exu ****************************
119109c6f1ddSLingrui98  // *********************************************************************
119209c6f1ddSLingrui98
1193d2b20d1aSTang Haojin  backendRedirect.valid := io.fromBackend.redirect.valid
1194d2b20d1aSTang Haojin  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1195d2b20d1aSTang Haojin  backendRedirect.bits.BTBMissBubble := false.B
1196d2b20d1aSTang Haojin
119709c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
11986bf9b30dSLingrui98    val ftqPtr    = wb.bits.ftqIdx
119909c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
120009c6f1ddSLingrui98    val taken     = wb.bits.cfiUpdate.taken
120109c6f1ddSLingrui98    val mispred   = wb.bits.cfiUpdate.isMisPred
12026bf9b30dSLingrui98    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
120309c6f1ddSLingrui98  }
120409c6f1ddSLingrui98
120509c6f1ddSLingrui98  // fix mispredict entry
120609c6f1ddSLingrui98  val lastIsMispredict = RegNext(
1207cf7d6b7aSMuzi    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter,
1208cf7d6b7aSMuzi    init = false.B
120909c6f1ddSLingrui98  )
121009c6f1ddSLingrui98
121109c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
12126bf9b30dSLingrui98    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
12136bf9b30dSLingrui98    val r_idx                                          = r_ptr.value
121409c6f1ddSLingrui98    val cfiIndex_bits_wen                              = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
121509c6f1ddSLingrui98    val cfiIndex_valid_wen                             = r_valid && r_offset === cfiIndex_vec(r_idx).bits
121609c6f1ddSLingrui98    when(cfiIndex_bits_wen || cfiIndex_valid_wen) {
121709c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
12183f88c020SGuokai Chen    }.elsewhen(r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
12193f88c020SGuokai Chen      cfiIndex_vec(r_idx).valid := false.B
122009c6f1ddSLingrui98    }
122109c6f1ddSLingrui98    when(cfiIndex_bits_wen) {
122209c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
122309c6f1ddSLingrui98    }
12241c6fc24aSEaston Man    newest_entry_target_modified := true.B
12256bf9b30dSLingrui98    newest_entry_target          := redirect.bits.cfiUpdate.target
12261c6fc24aSEaston Man    newest_entry_ptr_modified    := true.B
1227873dc383SLingrui98    newest_entry_ptr             := r_ptr
12281c6fc24aSEaston Man
1229b0ed7239SLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
123009c6f1ddSLingrui98    if (isBackend) {
123109c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
123209c6f1ddSLingrui98    }
123309c6f1ddSLingrui98  }
123409c6f1ddSLingrui98
1235bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1236bace178aSGao-Zeyu    updateCfiInfo(fromBackendRedirect)
123709c6f1ddSLingrui98  }.elsewhen(ifuRedirectToBpu.valid) {
123809c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend = false)
123909c6f1ddSLingrui98  }
124009c6f1ddSLingrui98
1241bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1242bace178aSGao-Zeyu    when(fromBackendRedirect.bits.ControlRedirectBubble) {
1243d2b20d1aSTang Haojin      when(fromBackendRedirect.bits.ControlBTBMissBubble) {
1244d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1245d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1246d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.TAGEMissBubble) {
1247d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id)                  := true.B
1248d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1249d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.SCMissBubble) {
1250d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.SCMissBubble.id)                  := true.B
1251d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1252d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.ITTAGEMissBubble) {
1253d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id)                  := true.B
1254d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1255d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.RASMissBubble) {
1256d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.RASMissBubble.id)                  := true.B
1257d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1258d2b20d1aSTang Haojin      }
1259d2b20d1aSTang Haojin
12609342624fSGao-Zeyu    }.elsewhen(backendRedirect.bits.MemVioRedirectBubble) {
1261d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id)                  := true.B
1262d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1263d2b20d1aSTang Haojin    }.otherwise {
1264d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id)                  := true.B
1265d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1266d2b20d1aSTang Haojin    }
1267d2b20d1aSTang Haojin  }.elsewhen(ifuRedirectReg.valid) {
1268d2b20d1aSTang Haojin    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1269d2b20d1aSTang Haojin    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1270d2b20d1aSTang Haojin  }
1271d2b20d1aSTang Haojin
1272d2b20d1aSTang Haojin  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1273d2b20d1aSTang Haojin  io.TAGEMissBubble       := fromBackendRedirect.bits.TAGEMissBubble
1274d2b20d1aSTang Haojin  io.SCMissBubble         := fromBackendRedirect.bits.SCMissBubble
1275d2b20d1aSTang Haojin  io.ITTAGEMissBubble     := fromBackendRedirect.bits.ITTAGEMissBubble
1276d2b20d1aSTang Haojin  io.RASMissBubble        := fromBackendRedirect.bits.RASMissBubble
1277d2b20d1aSTang Haojin
127809c6f1ddSLingrui98  // ***********************************************************************************
127909c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
128009c6f1ddSLingrui98  // ***********************************************************************************
128109c6f1ddSLingrui98
1282df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
128309c6f1ddSLingrui98
128409c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
1285b92f8445Sssszwic  io.icacheFlush := redirectVec.map(r => r.valid).reduce(_ || _)
1286b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid)
1287b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid)
128809c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_ || _)) {
1289cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
129009c6f1ddSLingrui98    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
12912f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
129209c6f1ddSLingrui98    val next                       = idx + 1.U
129309c6f1ddSLingrui98    bpuPtr := next
1294dc270d3bSJenius    copied_bpu_ptr.map(_ := next)
1295c5c5edaeSJenius    ifuPtr_write      := next
1296c5c5edaeSJenius    ifuWbPtr_write    := next
1297c5c5edaeSJenius    ifuPtrPlus1_write := idx + 2.U
12986bf9b30dSLingrui98    ifuPtrPlus2_write := idx + 3.U
1299b92f8445Sssszwic    pfPtr_write       := next
1300b92f8445Sssszwic    pfPtrPlus1_write  := idx + 2.U
13013f88c020SGuokai Chen  }
13023f88c020SGuokai Chen  when(RegNext(redirectVec.map(r => r.valid).reduce(_ || _))) {
1303cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
13043f88c020SGuokai Chen    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
13053f88c020SGuokai Chen    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
13063f88c020SGuokai Chen    when(RegNext(notIfu)) {
13071c6fc24aSEaston Man      commitStateQueueEnable(RegNext(idx.value)) := true.B
1308cf7d6b7aSMuzi      commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach { case (s, i) =>
130991346769SMuzi        when(i.U > RegNext(offset)) {
131091346769SMuzi          s := c_empty
131191346769SMuzi        }
131291346769SMuzi        when(i.U === RegNext(offset) && RegNext(flushItSelf)) {
131391346769SMuzi          s := c_flushed
131409c6f1ddSLingrui98        }
131509c6f1ddSLingrui98      }
131609c6f1ddSLingrui98    }
1317cf7d6b7aSMuzi  }
13183f88c020SGuokai Chen
131909c6f1ddSLingrui98  // only the valid bit is actually needed
1320df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
132109c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
1322d2b20d1aSTang Haojin  io.toIfu.topdown_redirect := fromBackendRedirect
132309c6f1ddSLingrui98
132409c6f1ddSLingrui98  // commit
13259aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
132609c6f1ddSLingrui98    when(c.valid) {
13271c6fc24aSEaston Man      commitStateQueueEnable(c.bits.ftqIdx.value)                 := true.B
132891346769SMuzi      commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed
132988825c5cSYinan Xu      // TODO: remove this
133088825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
1331c3abb8b6SYinan Xu      when(c.bits.commitType === 4.U) {
133291346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed
1333c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
133491346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed
1335c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
133688825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13371c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
133891346769SMuzi        commitStateQueueNext(index)(0) := c_committed
1339c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
134088825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13411c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
134291346769SMuzi        commitStateQueueNext(index)(1) := c_committed
134388825c5cSYinan Xu      }
134409c6f1ddSLingrui98    }
134509c6f1ddSLingrui98  }
134609c6f1ddSLingrui98
134709c6f1ddSLingrui98  // ****************************************************************
134809c6f1ddSLingrui98  // **************************** to bpu ****************************
134909c6f1ddSLingrui98  // ****************************************************************
135009c6f1ddSLingrui98
1351fd3aa057SYuandongliang  io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid
135251981c77SbugGenerator  io.toBpu.redirect       := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1353209a4cafSSteve Gou  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_ => 0.U(64.W)))
1354cf7d6b7aSMuzi  val redirect_latency =
1355cf7d6b7aSMuzi    GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1356209a4cafSSteve Gou  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1357cf7d6b7aSMuzi  XSPerfHistogram(
1358cf7d6b7aSMuzi    "ifu_redirect_latency",
1359cf7d6b7aSMuzi    redirect_latency,
1360cf7d6b7aSMuzi    !fromBackendRedirect.valid && ifuRedirectToBpu.valid,
1361cf7d6b7aSMuzi    0,
1362cf7d6b7aSMuzi    60,
1363cf7d6b7aSMuzi    1
1364cf7d6b7aSMuzi  )
136509c6f1ddSLingrui98
1366cf7d6b7aSMuzi  XSError(
1367cf7d6b7aSMuzi    io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr),
1368cf7d6b7aSMuzi    "Ftq received a redirect after its commit, check backend or replay"
1369cf7d6b7aSMuzi  )
137009c6f1ddSLingrui98
137102f21c16SLingrui98  val may_have_stall_from_bpu = Wire(Bool())
137202f21c16SLingrui98  val bpu_ftb_update_stall    = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
137302f21c16SLingrui98  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
13749230e379SMuzi
13759230e379SMuzi  val validInstructions     = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed)
13769230e379SMuzi  val lastInstructionStatus = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse))
1377d33d62c4SMuzi  val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed ||
1378d33d62c4SMuzi    commitStateQueueReg(commPtr.value)(0) === c_empty && commitStateQueueReg(commPtr.value)(1) === c_flushed
13799230e379SMuzi  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13809230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13819230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed)
13829230e379SMuzi  val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13839230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13849230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed ||
13859230e379SMuzi      firstInstructionFlushed)
138691346769SMuzi
138791346769SMuzi  when(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) {
1388cf7d6b7aSMuzi    robCommPtr_write := ParallelPriorityMux(
1389cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.valid).reverse,
1390cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse
1391cf7d6b7aSMuzi    )
13929230e379SMuzi  }.elsewhen(isAfter(commPtr, robCommPtr)) {
139391346769SMuzi    robCommPtr_write := commPtr
139491346769SMuzi  }.otherwise {
139591346769SMuzi    robCommPtr_write := robCommPtr
139691346769SMuzi  }
139709c6f1ddSLingrui98
1398ba5ba1dcSmy-mayfly  /**
1399ba5ba1dcSmy-mayfly    *************************************************************************************
1400ba5ba1dcSmy-mayfly    * MMIO instruction fetch is allowed only if MMIO is the oldest instruction.
1401ba5ba1dcSmy-mayfly    *************************************************************************************
1402ba5ba1dcSmy-mayfly    */
14031d1e6d4dSJenius  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
14049230e379SMuzi  val mmioLastCommit = isAfter(commPtr, mmioReadPtr) ||
14059230e379SMuzi    commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed
14061d1e6d4dSJenius  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
14071d1e6d4dSJenius
140809c6f1ddSLingrui98  // commit reads
1409c5c5edaeSJenius  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
141081101dc4SLingrui98  val commit_target =
1411cf7d6b7aSMuzi    Mux(
1412cf7d6b7aSMuzi      RegNext(commPtr === newest_entry_ptr),
14131c6fc24aSEaston Man      RegEnable(newest_entry_target, newest_entry_target_modified),
1414cf7d6b7aSMuzi      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)
1415cf7d6b7aSMuzi    )
14161c6fc24aSEaston Man  ftq_pd_mem.io.ren.get.last := canCommit
141709c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last   := commPtr.value
141809c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
141916a171eeSEaston Man  ftq_redirect_mem.io.ren.get.last := canCommit
1420deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.last   := commPtr.value
1421deb3a97eSGao-Zeyu  val commit_spec_meta = ftq_redirect_mem.io.rdata.last
142209c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0)   := canCommit
142309c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1424deb3a97eSGao-Zeyu  val commit_meta      = ftq_meta_1r_sram.io.rdata(0).meta
1425deb3a97eSGao-Zeyu  val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry
142609c6f1ddSLingrui98
142709c6f1ddSLingrui98  // need one cycle to read mem and srams
14281c6fc24aSEaston Man  val do_commit_ptr = RegEnable(commPtr, canCommit)
14295371700eSzoujr  val do_commit     = RegNext(canCommit, init = false.B)
14309230e379SMuzi  when(canMoveCommPtr) {
14316bf9b30dSLingrui98    commPtr_write      := commPtrPlus1
14326bf9b30dSLingrui98    commPtrPlus1_write := commPtrPlus1 + 1.U
14336bf9b30dSLingrui98  }
14341c6fc24aSEaston Man  val commit_state   = RegEnable(commitStateQueueReg(commPtr.value), canCommit)
14355371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1436d4fcfc3eSGuokai Chen  val do_commit_cfi  = WireInit(cfiIndex_vec(do_commit_ptr.value))
14373f88c020SGuokai Chen  //
14383f88c020SGuokai Chen  // when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
14393f88c020SGuokai Chen  //  can_commit_cfi.valid := false.B
14403f88c020SGuokai Chen  // }
14411c6fc24aSEaston Man  val commit_cfi = RegEnable(can_commit_cfi, canCommit)
144291346769SMuzi  val debug_cfi  = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid
144309c6f1ddSLingrui98
1444cf7d6b7aSMuzi  val commit_mispredict: Vec[Bool] =
1445cf7d6b7aSMuzi    VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map {
144691346769SMuzi      case (mis, state) => mis && state === c_committed
144709c6f1ddSLingrui98    })
144891346769SMuzi  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth]
14495371700eSzoujr  val can_commit_hit     = entry_hit_status(commPtr.value)
14501c6fc24aSEaston Man  val commit_hit         = RegEnable(can_commit_hit, canCommit)
14511c6fc24aSEaston Man  val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this
14521c6fc24aSEaston Man  val commit_stage       = RegEnable(pred_stage(commPtr.value), canCommit)
145309c6f1ddSLingrui98  val commit_valid       = commit_hit === h_hit || commit_cfi.valid           // hit or taken
145409c6f1ddSLingrui98
14555371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
145602f21c16SLingrui98  switch(bpu_ftb_update_stall) {
145702f21c16SLingrui98    is(0.U) {
145802f21c16SLingrui98      when(can_commit_cfi.valid && !to_bpu_hit && canCommit) {
145902f21c16SLingrui98        bpu_ftb_update_stall := 2.U // 2-cycle stall
146002f21c16SLingrui98      }
146102f21c16SLingrui98    }
146202f21c16SLingrui98    is(2.U) {
146302f21c16SLingrui98      bpu_ftb_update_stall := 1.U
146402f21c16SLingrui98    }
146502f21c16SLingrui98    is(1.U) {
146602f21c16SLingrui98      bpu_ftb_update_stall := 0.U
146702f21c16SLingrui98    }
146802f21c16SLingrui98    is(3.U) {
14698b33cd30Sklin02      // XSError below
147002f21c16SLingrui98    }
147102f21c16SLingrui98  }
14728b33cd30Sklin02  XSError(bpu_ftb_update_stall === 3.U, "bpu_ftb_update_stall should be 0, 1 or 2")
147309c6f1ddSLingrui98
1474b0ed7239SLingrui98  // TODO: remove this
1475b0ed7239SLingrui98  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1476b0ed7239SLingrui98
1477b2f6ed0aSSteve Gou  // update latency stats
1478b2f6ed0aSSteve Gou  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1479b2f6ed0aSSteve Gou  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1480b2f6ed0aSSteve Gou
148109c6f1ddSLingrui98  io.toBpu.update       := DontCare
148209c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
148309c6f1ddSLingrui98  val update = io.toBpu.update.bits
148409c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
148509c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
1486deb3a97eSGao-Zeyu  update.meta        := commit_meta
1487803124a6SLingrui98  update.cfi_idx     := commit_cfi
14888ffcd86aSLingrui98  update.full_target := commit_target
1489edc18578SLingrui98  update.from_stage  := commit_stage
1490c2d1ec7dSLingrui98  update.spec_info   := commit_spec_meta
14913f88c020SGuokai Chen  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
149209c6f1ddSLingrui98
149309c6f1ddSLingrui98  val commit_real_hit  = commit_hit === h_hit
149409c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
149509c6f1ddSLingrui98
149609c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
149709c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
149809c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
149909c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
150009c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
150109c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
150209c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
150309c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
150409c6f1ddSLingrui98
150509c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
150609c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
150709c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
150809c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
1509edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1510803124a6SLingrui98  update.br_taken_mask     := ftbEntryGen.taken_mask
1511cc2d1573SEaston Man  update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1512cc2d1573SEaston Man    case (valid, offset) => valid && commit_instCommited(offset)
1513cc2d1573SEaston Man  }
1514803124a6SLingrui98  update.jmp_taken := ftbEntryGen.jmp_taken
1515b37e4b45SLingrui98
1516803124a6SLingrui98  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1517803124a6SLingrui98  // update.full_pred.jalr_target := commit_target
1518803124a6SLingrui98  // update.full_pred.hit := true.B
1519803124a6SLingrui98  // when (update.full_pred.is_jalr) {
1520803124a6SLingrui98  //   update.full_pred.targets.last := commit_target
1521803124a6SLingrui98  // }
152209c6f1ddSLingrui98
152309c6f1ddSLingrui98  // ******************************************************************************
152409c6f1ddSLingrui98  // **************************** commit perf counters ****************************
152509c6f1ddSLingrui98  // ******************************************************************************
152609c6f1ddSLingrui98
152791346769SMuzi  val commit_inst_mask        = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt
152809c6f1ddSLingrui98  val commit_mispred_mask     = commit_mispredict.asUInt
152909c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
153009c6f1ddSLingrui98
153109c6f1ddSLingrui98  val commit_br_mask  = commit_pd.brMask.asUInt
153209c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1533cf7d6b7aSMuzi  val commit_cfi_mask = commit_br_mask | commit_jmp_mask
153409c6f1ddSLingrui98
153509c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
153609c6f1ddSLingrui98
153709c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
153809c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
153909c6f1ddSLingrui98
154009c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
154109c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
154209c6f1ddSLingrui98
1543b92f8445Sssszwic  val hartId           = p(XSCoreParamsKey).HartId
1544c686adcdSYinan Xu  val isWriteFTQTable  = Constantin.createRecord(s"isWriteFTQTable$hartId")
1545c686adcdSYinan Xu  val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle)
154609c6f1ddSLingrui98  // Cfi Info
154709c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
154809c6f1ddSLingrui98    val pc      = commit_pc_bundle.startAddr + (i * instBytes).U
154991346769SMuzi    val v       = commit_state(i) === c_committed
155009c6f1ddSLingrui98    val isBr    = commit_pd.brMask(i)
155109c6f1ddSLingrui98    val isJmp   = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
155209c6f1ddSLingrui98    val isCfi   = isBr || isJmp
155309c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
155409c6f1ddSLingrui98    val misPred = commit_mispredict(i)
1555c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
1556c2ad24ebSLingrui98    val histPtr   = commit_spec_meta.histPtr
1557deb3a97eSGao-Zeyu    val predCycle = commit_meta(63, 0)
155809c6f1ddSLingrui98    val target    = commit_target
155909c6f1ddSLingrui98
1560cf7d6b7aSMuzi    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1561cf7d6b7aSMuzi      v && offset === i.U
1562cf7d6b7aSMuzi    })))
1563cf7d6b7aSMuzi    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1564cf7d6b7aSMuzi      v && offset === i.U
1565cf7d6b7aSMuzi    }.reduce(_ || _)
1566cf7d6b7aSMuzi    val addIntoHist =
1567cf7d6b7aSMuzi      ((commit_hit === h_hit) && inFtbEntry) || (!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)
1568cf7d6b7aSMuzi    XSDebug(
1569cf7d6b7aSMuzi      v && do_commit && isCfi,
1570cf7d6b7aSMuzi      p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1571c2ad24ebSLingrui98        p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
157209c6f1ddSLingrui98        p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1573cf7d6b7aSMuzi        p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n"
1574cf7d6b7aSMuzi    )
157551532d8bSGuokai Chen
157651532d8bSGuokai Chen    val logbundle = Wire(new FtqDebugBundle)
157751532d8bSGuokai Chen    logbundle.pc        := pc
157851532d8bSGuokai Chen    logbundle.target    := target
157951532d8bSGuokai Chen    logbundle.isBr      := isBr
158051532d8bSGuokai Chen    logbundle.isJmp     := isJmp
158151532d8bSGuokai Chen    logbundle.isCall    := isJmp && commit_pd.hasCall
158251532d8bSGuokai Chen    logbundle.isRet     := isJmp && commit_pd.hasRet
158351532d8bSGuokai Chen    logbundle.misPred   := misPred
158451532d8bSGuokai Chen    logbundle.isTaken   := isTaken
158551532d8bSGuokai Chen    logbundle.predStage := commit_stage
158651532d8bSGuokai Chen
158751532d8bSGuokai Chen    ftqBranchTraceDB.log(
158851532d8bSGuokai Chen      data = logbundle /* hardware of type T */,
1589da3bf434SMaxpicca-Li      en = isWriteFTQTable.orR && v && do_commit && isCfi,
159051532d8bSGuokai Chen      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
159151532d8bSGuokai Chen      clock = clock,
159251532d8bSGuokai Chen      reset = reset
159351532d8bSGuokai Chen    )
159409c6f1ddSLingrui98  }
159509c6f1ddSLingrui98
159609c6f1ddSLingrui98  val enq           = io.fromBpu.resp
15972e1be6e1SSteve Gou  val perf_redirect = backendRedirect
159809c6f1ddSLingrui98
159909c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
160009c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
160109c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
160209c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
160309c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
160409c6f1ddSLingrui98
160509c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
160609c6f1ddSLingrui98
160709c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
160809c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
160912cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1610cf7d6b7aSMuzi  XSPerfAccumulate(
1611cf7d6b7aSMuzi    "bpu_to_ifu_bubble_when_ftq_full",
1612cf7d6b7aSMuzi    (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready
1613cf7d6b7aSMuzi  )
161409c6f1ddSLingrui98
1615bace178aSGao-Zeyu  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_ | _))
16169342624fSGao-Zeyu  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
16179342624fSGao-Zeyu  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
16189342624fSGao-Zeyu
161909c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
162009c6f1ddSLingrui98  val to_ifu   = io.toIfu.req.bits
162109c6f1ddSLingrui98
1622209a4cafSSteve Gou  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth + 1, 1)
162309c6f1ddSLingrui98
162409c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
162509c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
162609c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
162709c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
162809c6f1ddSLingrui98
162909c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
163009c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
163109c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
163209c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
163309c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
163409c6f1ddSLingrui98
163509c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
163609c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
163709c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
163809c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
163909c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
164009c6f1ddSLingrui98
16411d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
16421d7e5011SLingrui98
1643cf7d6b7aSMuzi  def pred_stage_map(src: UInt, name: String) =
16441d7e5011SLingrui98    (0 until numBpStages).map(i =>
16451d7e5011SLingrui98      f"${name}_stage_${i + 1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
16461d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_ + _)
16471d7e5011SLingrui98
16481d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs, "mispredict")
16491d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
16501d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
16511d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights, "correct")
16521d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
16531d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
16541d7e5011SLingrui98
165509c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
165609c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
165709c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
165865fddcf0Szoujr  // assert(!ftb_false_hit)
165909c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
166009c6f1ddSLingrui98
166109c6f1ddSLingrui98  val ftb_new_entry                = u(ftbEntryGen.is_init_entry)
1662b37e4b45SLingrui98  val ftb_new_entry_only_br        = ftb_new_entry && !update_ftb_entry.jmpValid
1663b37e4b45SLingrui98  val ftb_new_entry_only_jmp       = ftb_new_entry && !update_ftb_entry.brValids(0)
1664b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
166509c6f1ddSLingrui98
166609c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
166709c6f1ddSLingrui98
1668cf7d6b7aSMuzi  val ftb_modified_entry =
1669dcf4211fSYuandongliang    u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_strong_bias_modified)
167009c6f1ddSLingrui98  val ftb_modified_entry_new_br               = u(ftbEntryGen.is_new_br)
1671d2b20d1aSTang Haojin  val ftb_modified_entry_ifu_redirected       = u(ifuRedirected(do_commit_ptr.value))
167209c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
167309c6f1ddSLingrui98  val ftb_modified_entry_br_full              = ftb_modified_entry && ftbEntryGen.is_br_full
1674dcf4211fSYuandongliang  val ftb_modified_entry_strong_bias          = ftb_modified_entry && ftbEntryGen.is_strong_bias_modified
167509c6f1ddSLingrui98
1676209a4cafSSteve Gou  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1677209a4cafSSteve Gou  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1678209a4cafSSteve Gou  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth + 1, 1)
1679209a4cafSSteve Gou  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth + 1, 1)
1680209a4cafSSteve Gou  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1681209a4cafSSteve Gou  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth + 1, 1)
168209c6f1ddSLingrui98
1683209a4cafSSteve Gou  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize + 1, 1)
168409c6f1ddSLingrui98
168509c6f1ddSLingrui98  val perfCountsMap = Map(
168609c6f1ddSLingrui98    "BpInstr"                        -> PopCount(mbpInstrs),
168709c6f1ddSLingrui98    "BpBInstr"                       -> PopCount(mbpBRights | mbpBWrongs),
168809c6f1ddSLingrui98    "BpRight"                        -> PopCount(mbpRights),
168909c6f1ddSLingrui98    "BpWrong"                        -> PopCount(mbpWrongs),
169009c6f1ddSLingrui98    "BpBRight"                       -> PopCount(mbpBRights),
169109c6f1ddSLingrui98    "BpBWrong"                       -> PopCount(mbpBWrongs),
169209c6f1ddSLingrui98    "BpJRight"                       -> PopCount(mbpJRights),
169309c6f1ddSLingrui98    "BpJWrong"                       -> PopCount(mbpJWrongs),
169409c6f1ddSLingrui98    "BpIRight"                       -> PopCount(mbpIRights),
169509c6f1ddSLingrui98    "BpIWrong"                       -> PopCount(mbpIWrongs),
169609c6f1ddSLingrui98    "BpCRight"                       -> PopCount(mbpCRights),
169709c6f1ddSLingrui98    "BpCWrong"                       -> PopCount(mbpCWrongs),
169809c6f1ddSLingrui98    "BpRRight"                       -> PopCount(mbpRRights),
169909c6f1ddSLingrui98    "BpRWrong"                       -> PopCount(mbpRWrongs),
170009c6f1ddSLingrui98    "ftb_false_hit"                  -> PopCount(ftb_false_hit),
170109c6f1ddSLingrui98    "ftb_hit"                        -> PopCount(ftb_hit),
170209c6f1ddSLingrui98    "ftb_new_entry"                  -> PopCount(ftb_new_entry),
170309c6f1ddSLingrui98    "ftb_new_entry_only_br"          -> PopCount(ftb_new_entry_only_br),
170409c6f1ddSLingrui98    "ftb_new_entry_only_jmp"         -> PopCount(ftb_new_entry_only_jmp),
170509c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp"   -> PopCount(ftb_new_entry_has_br_and_jmp),
170609c6f1ddSLingrui98    "ftb_old_entry"                  -> PopCount(ftb_old_entry),
170709c6f1ddSLingrui98    "ftb_modified_entry"             -> PopCount(ftb_modified_entry),
170809c6f1ddSLingrui98    "ftb_modified_entry_new_br"      -> PopCount(ftb_modified_entry_new_br),
170909c6f1ddSLingrui98    "ftb_jalr_target_modified"       -> PopCount(ftb_modified_entry_jalr_target_modified),
171009c6f1ddSLingrui98    "ftb_modified_entry_br_full"     -> PopCount(ftb_modified_entry_br_full),
1711dcf4211fSYuandongliang    "ftb_modified_entry_strong_bias" -> PopCount(ftb_modified_entry_strong_bias)
1712209a4cafSSteve Gou  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
17131d7e5011SLingrui98    correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
171409c6f1ddSLingrui98
171509c6f1ddSLingrui98  for ((key, value) <- perfCountsMap) {
171609c6f1ddSLingrui98    XSPerfAccumulate(key, value)
171709c6f1ddSLingrui98  }
171809c6f1ddSLingrui98
171909c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
172009c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
172109c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
172209c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
172309c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1724cf7d6b7aSMuzi  XSDebug(
1725cf7d6b7aSMuzi    true.B,
1726cf7d6b7aSMuzi    p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1727cf7d6b7aSMuzi      p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n"
1728cf7d6b7aSMuzi  )
172909c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
173009c6f1ddSLingrui98
173109c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
173209c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
173309c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
173409c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
173509c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
173609c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
173709c6f1ddSLingrui98  //           !taken),
173809c6f1ddSLingrui98  //         !taken),
173909c6f1ddSLingrui98  //       false.B)
174009c6f1ddSLingrui98  //     }
174109c6f1ddSLingrui98  //   }
174209c6f1ddSLingrui98
174309c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
174409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
174509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
174609c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
174709c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
174809c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
174909c6f1ddSLingrui98  //           !taken),
175009c6f1ddSLingrui98  //         !taken),
175109c6f1ddSLingrui98  //       false.B)
175209c6f1ddSLingrui98  //     }
175309c6f1ddSLingrui98  //   }
175409c6f1ddSLingrui98
175509c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
175609c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
175709c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
175809c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
175909c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
176009c6f1ddSLingrui98  //       false.B)
176109c6f1ddSLingrui98  //     }
176209c6f1ddSLingrui98  //   }
176309c6f1ddSLingrui98
176409c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
176509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
176609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
176709c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
176809c6f1ddSLingrui98  //         isWrong ^ (!taken),
176909c6f1ddSLingrui98  //           false.B)
177009c6f1ddSLingrui98  //     }
177109c6f1ddSLingrui98  //   }
177209c6f1ddSLingrui98
177309c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
177409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
177509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
177609c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
177709c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
177809c6f1ddSLingrui98  //           false.B)
177909c6f1ddSLingrui98  //     }
178009c6f1ddSLingrui98  //   }
178109c6f1ddSLingrui98
178209c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
178309c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
178409c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
178509c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
178609c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
178709c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
178809c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
178909c6f1ddSLingrui98
179009c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
179109c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
179209c6f1ddSLingrui98
179309c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
179409c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
17951ca0e4f3SYinan Xu
1796cd365d4cSrvcoresjw  val perfEvents = Seq(
1797cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect),
1798cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect),
1799cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready),
1800cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1801cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)),
1802cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid),
1803cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid),
1804cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn),
1805cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)),
1806cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)),
1807cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)),
1808cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)),
1809cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)),
1810cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)),
1811cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)),
1812cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)),
1813cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)),
1814cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)),
1815cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)),
1816cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)),
1817cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)),
1818cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)),
1819cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)),
1820cf7d6b7aSMuzi    ("ftb_hit                ", PopCount(ftb_hit))
1821cd365d4cSrvcoresjw  )
18221ca0e4f3SYinan Xu  generatePerfEvent()
182309c6f1ddSLingrui98}
1824