xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision cf7d6b7a1a781c73aeb87de112de2e7fe5ea3b7c)
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.
1509c6f1ddSLingrui98***************************************************************************************/
1609c6f1ddSLingrui98
1709c6f1ddSLingrui98package xiangshan.frontend
1809c6f1ddSLingrui98
1909c6f1ddSLingrui98import chisel3._
2009c6f1ddSLingrui98import chisel3.util._
21*cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
223c02ee8fSwakafaimport utility._
23*cf7d6b7aSMuziimport utility.ChiselDB
24*cf7d6b7aSMuziimport utils._
2509c6f1ddSLingrui98import xiangshan._
261ca0e4f3SYinan Xuimport xiangshan.backend.CtrlToFtqIO
272e1be6e1SSteve Gouimport xiangshan.backend.decode.ImmUnion
28*cf7d6b7aSMuziimport xiangshan.frontend.icache._
2951532d8bSGuokai Chen
3051532d8bSGuokai Chenclass FtqDebugBundle extends Bundle {
3151532d8bSGuokai Chen  val pc        = UInt(39.W)
3251532d8bSGuokai Chen  val target    = UInt(39.W)
3351532d8bSGuokai Chen  val isBr      = Bool()
3451532d8bSGuokai Chen  val isJmp     = Bool()
3551532d8bSGuokai Chen  val isCall    = Bool()
3651532d8bSGuokai Chen  val isRet     = Bool()
3751532d8bSGuokai Chen  val misPred   = Bool()
3851532d8bSGuokai Chen  val isTaken   = Bool()
3951532d8bSGuokai Chen  val predStage = UInt(2.W)
4051532d8bSGuokai Chen}
4109c6f1ddSLingrui98
423b739f49SXuan Huclass FtqPtr(entries: Int) extends CircularQueuePtr[FtqPtr](
433b739f49SXuan Hu      entries
4409c6f1ddSLingrui98    ) {
453b739f49SXuan Hu  def this()(implicit p: Parameters) = this(p(XSCoreParamsKey).FtqSize)
4609c6f1ddSLingrui98}
4709c6f1ddSLingrui98
4809c6f1ddSLingrui98object FtqPtr {
4909c6f1ddSLingrui98  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
5009c6f1ddSLingrui98    val ptr = Wire(new FtqPtr)
5109c6f1ddSLingrui98    ptr.flag  := f
5209c6f1ddSLingrui98    ptr.value := v
5309c6f1ddSLingrui98    ptr
5409c6f1ddSLingrui98  }
55*cf7d6b7aSMuzi  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr =
5609c6f1ddSLingrui98    apply(!ptr.flag, ptr.value)
5709c6f1ddSLingrui98}
5809c6f1ddSLingrui98
5909c6f1ddSLingrui98class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
6009c6f1ddSLingrui98
6109c6f1ddSLingrui98  val io = IO(new Bundle() {
6209c6f1ddSLingrui98    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
6309c6f1ddSLingrui98    val ren   = Input(Vec(numRead, Bool()))
6409c6f1ddSLingrui98    val rdata = Output(Vec(numRead, gen))
6509c6f1ddSLingrui98    val waddr = Input(UInt(log2Up(FtqSize).W))
6609c6f1ddSLingrui98    val wen   = Input(Bool())
6709c6f1ddSLingrui98    val wdata = Input(gen)
6809c6f1ddSLingrui98  })
6909c6f1ddSLingrui98
7009c6f1ddSLingrui98  for (i <- 0 until numRead) {
7109c6f1ddSLingrui98    val sram = Module(new SRAMTemplate(gen, FtqSize))
7209c6f1ddSLingrui98    sram.io.r.req.valid       := io.ren(i)
7309c6f1ddSLingrui98    sram.io.r.req.bits.setIdx := io.raddr(i)
7409c6f1ddSLingrui98    io.rdata(i)               := sram.io.r.resp.data(0)
7509c6f1ddSLingrui98    sram.io.w.req.valid       := io.wen
7609c6f1ddSLingrui98    sram.io.w.req.bits.setIdx := io.waddr
7709c6f1ddSLingrui98    sram.io.w.req.bits.data   := VecInit(io.wdata)
7809c6f1ddSLingrui98  }
7909c6f1ddSLingrui98
8009c6f1ddSLingrui98}
8109c6f1ddSLingrui98
8209c6f1ddSLingrui98class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
8309c6f1ddSLingrui98  val startAddr     = UInt(VAddrBits.W)
84b37e4b45SLingrui98  val nextLineAddr  = UInt(VAddrBits.W)
8509c6f1ddSLingrui98  val isNextMask    = Vec(PredictWidth, Bool())
86b37e4b45SLingrui98  val fallThruError = Bool()
87b37e4b45SLingrui98  // val carry = Bool()
8809c6f1ddSLingrui98  def getPc(offset: UInt) = {
8985215037SLingrui98    def getHigher(pc: UInt) = pc(VAddrBits - 1, log2Ceil(PredictWidth) + instOffsetBits + 1)
9085215037SLingrui98    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth) + instOffsetBits, instOffsetBits)
91*cf7d6b7aSMuzi    Cat(
92*cf7d6b7aSMuzi      getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth) + instOffsetBits), nextLineAddr, startAddr)),
93*cf7d6b7aSMuzi      getOffset(startAddr) + offset,
94*cf7d6b7aSMuzi      0.U(instOffsetBits.W)
95*cf7d6b7aSMuzi    )
9609c6f1ddSLingrui98  }
9709c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
98a229ab6cSLingrui98    def carryPos(addr: UInt) = addr(instOffsetBits + log2Ceil(PredictWidth) + 1)
99adc0b8dfSGuokai Chen    this.startAddr    := resp.pc(3)
100adc0b8dfSGuokai Chen    this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs
10109c6f1ddSLingrui98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
102935edac4STang Haojin      (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool
10309c6f1ddSLingrui98    ))
104adc0b8dfSGuokai Chen    this.fallThruError := resp.fallThruError(3)
10509c6f1ddSLingrui98    this
10609c6f1ddSLingrui98  }
107*cf7d6b7aSMuzi  override def toPrintable: Printable =
108b37e4b45SLingrui98    p"startAddr:${Hexadecimal(startAddr)}"
10909c6f1ddSLingrui98}
11009c6f1ddSLingrui98
11109c6f1ddSLingrui98class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
11209c6f1ddSLingrui98  val brMask    = Vec(PredictWidth, Bool())
11309c6f1ddSLingrui98  val jmpInfo   = ValidUndirectioned(Vec(3, Bool()))
11409c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
11509c6f1ddSLingrui98  val jalTarget = UInt(VAddrBits.W)
11609c6f1ddSLingrui98  val rvcMask   = Vec(PredictWidth, Bool())
11709c6f1ddSLingrui98  def hasJal    = jmpInfo.valid && !jmpInfo.bits(0)
11809c6f1ddSLingrui98  def hasJalr   = jmpInfo.valid && jmpInfo.bits(0)
11909c6f1ddSLingrui98  def hasCall   = jmpInfo.valid && jmpInfo.bits(1)
12009c6f1ddSLingrui98  def hasRet    = jmpInfo.valid && jmpInfo.bits(2)
12109c6f1ddSLingrui98
12209c6f1ddSLingrui98  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
12309c6f1ddSLingrui98    val pds = pdWb.pd
12409c6f1ddSLingrui98    this.brMask        := VecInit(pds.map(pd => pd.isBr && pd.valid))
12509c6f1ddSLingrui98    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
126*cf7d6b7aSMuzi    this.jmpInfo.bits := ParallelPriorityMux(
127*cf7d6b7aSMuzi      pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
128*cf7d6b7aSMuzi      pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))
129*cf7d6b7aSMuzi    )
13009c6f1ddSLingrui98    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
13109c6f1ddSLingrui98    this.rvcMask   := VecInit(pds.map(pd => pd.isRVC))
13209c6f1ddSLingrui98    this.jalTarget := pdWb.jalTarget
13309c6f1ddSLingrui98  }
13409c6f1ddSLingrui98
13509c6f1ddSLingrui98  def toPd(offset: UInt) = {
13609c6f1ddSLingrui98    require(offset.getWidth == log2Ceil(PredictWidth))
13709c6f1ddSLingrui98    val pd = Wire(new PreDecodeInfo)
13809c6f1ddSLingrui98    pd.valid := true.B
13909c6f1ddSLingrui98    pd.isRVC := rvcMask(offset)
14009c6f1ddSLingrui98    val isBr   = brMask(offset)
14109c6f1ddSLingrui98    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
14209c6f1ddSLingrui98    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
14309c6f1ddSLingrui98    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
14409c6f1ddSLingrui98    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
14509c6f1ddSLingrui98    pd
14609c6f1ddSLingrui98  }
14709c6f1ddSLingrui98}
14809c6f1ddSLingrui98
149f9c51548Sssszwicclass PrefetchPtrDB(implicit p: Parameters) extends Bundle {
150f9c51548Sssszwic  val fromFtqPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
151f9c51548Sssszwic  val fromIfuPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
152f9c51548Sssszwic}
15309c6f1ddSLingrui98
1543711cf36S小造xu_zhclass Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo {
155abdc3a32Sxu_zh  val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None
1563711cf36S小造xu_zh}
15709c6f1ddSLingrui98
15809c6f1ddSLingrui98class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
15909c6f1ddSLingrui98  val meta      = UInt(MaxMetaLength.W)
160deb3a97eSGao-Zeyu  val ftb_entry = new FTBEntry
16109c6f1ddSLingrui98}
16209c6f1ddSLingrui98
16309c6f1ddSLingrui98class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
16409c6f1ddSLingrui98  val target   = UInt(VAddrBits.W)
16509c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
16609c6f1ddSLingrui98}
16709c6f1ddSLingrui98
16809c6f1ddSLingrui98class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
16954c6d89dSxiaofeibao-xjtu  val valid  = Output(Bool())
17009c6f1ddSLingrui98  val ptr    = Output(new FtqPtr)
17109c6f1ddSLingrui98  val offset = Output(UInt(log2Ceil(PredictWidth).W))
17209c6f1ddSLingrui98  val data   = Input(gen)
17354c6d89dSxiaofeibao-xjtu  def apply(valid: Bool, ptr: FtqPtr, offset: UInt) = {
17454c6d89dSxiaofeibao-xjtu    this.valid  := valid
17509c6f1ddSLingrui98    this.ptr    := ptr
17609c6f1ddSLingrui98    this.offset := offset
17709c6f1ddSLingrui98    this.data
17809c6f1ddSLingrui98  }
17909c6f1ddSLingrui98}
18009c6f1ddSLingrui98
18109c6f1ddSLingrui98class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
18209c6f1ddSLingrui98  val redirect       = Valid(new BranchPredictionRedirect)
18309c6f1ddSLingrui98  val update         = Valid(new BranchPredictionUpdate)
18409c6f1ddSLingrui98  val enq_ptr        = Output(new FtqPtr)
185fd3aa057SYuandongliang  val redirctFromIFU = Output(Bool())
18609c6f1ddSLingrui98}
18709c6f1ddSLingrui98
1882c9f4a9fSxu_zhclass BpuFlushInfo(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
18909c6f1ddSLingrui98  // when ifu pipeline is not stalled,
19009c6f1ddSLingrui98  // a packet from bpu s3 can reach f1 at most
19109c6f1ddSLingrui98  val s2 = Valid(new FtqPtr)
192cb4f77ceSLingrui98  val s3 = Valid(new FtqPtr)
193*cf7d6b7aSMuzi  def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) =
19409c6f1ddSLingrui98    src.valid && !isAfter(src.bits, idx_to_flush)
19509c6f1ddSLingrui98  def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
196cb4f77ceSLingrui98  def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
19709c6f1ddSLingrui98}
1982c9f4a9fSxu_zh
1992c9f4a9fSxu_zhclass FtqToIfuIO(implicit p: Parameters) extends XSBundle {
2002c9f4a9fSxu_zh  val req              = Decoupled(new FetchRequestBundle)
2012c9f4a9fSxu_zh  val redirect         = Valid(new BranchPredictionRedirect)
2022c9f4a9fSxu_zh  val topdown_redirect = Valid(new BranchPredictionRedirect)
2032c9f4a9fSxu_zh  val flushFromBpu     = new BpuFlushInfo
20409c6f1ddSLingrui98}
20509c6f1ddSLingrui98
2062c9f4a9fSxu_zhclass FtqToICacheIO(implicit p: Parameters) extends XSBundle {
207c5c5edaeSJenius  // NOTE: req.bits must be prepare in T cycle
208c5c5edaeSJenius  // while req.valid is set true in T + 1 cycle
209c5c5edaeSJenius  val req = Decoupled(new FtqToICacheRequestBundle)
210c5c5edaeSJenius}
211c5c5edaeSJenius
2122c9f4a9fSxu_zhclass FtqToPrefetchIO(implicit p: Parameters) extends XSBundle {
213b92f8445Sssszwic  val req          = Decoupled(new FtqICacheInfo)
2142c9f4a9fSxu_zh  val flushFromBpu = new BpuFlushInfo
215b92f8445Sssszwic}
216b92f8445Sssszwic
21709c6f1ddSLingrui98trait HasBackendRedirectInfo extends HasXSParameter {
21809c6f1ddSLingrui98  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
21909c6f1ddSLingrui98}
22009c6f1ddSLingrui98
22109c6f1ddSLingrui98class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
222b56f947eSYinan Xu  // write to backend pc mem
223b56f947eSYinan Xu  val pc_mem_wen   = Output(Bool())
224f533cba7SHuSipeng  val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W))
225b56f947eSYinan Xu  val pc_mem_wdata = Output(new Ftq_RF_Components)
226873dc383SLingrui98  // newest target
2276022c595SsinceforYy  val newest_entry_en     = Output(Bool())
228873dc383SLingrui98  val newest_entry_target = Output(UInt(VAddrBits.W))
229873dc383SLingrui98  val newest_entry_ptr    = Output(new FtqPtr)
23009c6f1ddSLingrui98}
23109c6f1ddSLingrui98
23209c6f1ddSLingrui98class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
23309c6f1ddSLingrui98  val io = IO(new Bundle {
23409c6f1ddSLingrui98    val start_addr     = Input(UInt(VAddrBits.W))
23509c6f1ddSLingrui98    val old_entry      = Input(new FTBEntry)
23609c6f1ddSLingrui98    val pd             = Input(new Ftq_pd_Entry)
23709c6f1ddSLingrui98    val cfiIndex       = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
23809c6f1ddSLingrui98    val target         = Input(UInt(VAddrBits.W))
23909c6f1ddSLingrui98    val hit            = Input(Bool())
24009c6f1ddSLingrui98    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
24109c6f1ddSLingrui98
24209c6f1ddSLingrui98    val new_entry         = Output(new FTBEntry)
24309c6f1ddSLingrui98    val new_br_insert_pos = Output(Vec(numBr, Bool()))
24409c6f1ddSLingrui98    val taken_mask        = Output(Vec(numBr, Bool()))
245803124a6SLingrui98    val jmp_taken         = Output(Bool())
24609c6f1ddSLingrui98    val mispred_mask      = Output(Vec(numBr + 1, Bool()))
24709c6f1ddSLingrui98
24809c6f1ddSLingrui98    // for perf counters
24909c6f1ddSLingrui98    val is_init_entry            = Output(Bool())
25009c6f1ddSLingrui98    val is_old_entry             = Output(Bool())
25109c6f1ddSLingrui98    val is_new_br                = Output(Bool())
25209c6f1ddSLingrui98    val is_jalr_target_modified  = Output(Bool())
25309c6f1ddSLingrui98    val is_always_taken_modified = Output(Bool())
25409c6f1ddSLingrui98    val is_br_full               = Output(Bool())
25509c6f1ddSLingrui98  })
25609c6f1ddSLingrui98
25709c6f1ddSLingrui98  // no mispredictions detected at predecode
25809c6f1ddSLingrui98  val hit = io.hit
25909c6f1ddSLingrui98  val pd  = io.pd
26009c6f1ddSLingrui98
26109c6f1ddSLingrui98  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
26209c6f1ddSLingrui98
26309c6f1ddSLingrui98  val cfi_is_br       = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
26409c6f1ddSLingrui98  val entry_has_jmp   = pd.jmpInfo.valid
26509c6f1ddSLingrui98  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
26609c6f1ddSLingrui98  val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid
26709c6f1ddSLingrui98  val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid
26809c6f1ddSLingrui98  val new_jmp_is_ret  = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid
26909c6f1ddSLingrui98  val last_jmp_rvi    = entry_has_jmp && pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask.last
270a60a2901SLingrui98  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
27109c6f1ddSLingrui98
27209c6f1ddSLingrui98  val cfi_is_jal  = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
27309c6f1ddSLingrui98  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
27409c6f1ddSLingrui98
275a60a2901SLingrui98  def carryPos = log2Ceil(PredictWidth) + instOffsetBits
27609c6f1ddSLingrui98  def getLower(pc: UInt) = pc(carryPos - 1, instOffsetBits)
27709c6f1ddSLingrui98  // if not hit, establish a new entry
27809c6f1ddSLingrui98  init_entry.valid := true.B
27909c6f1ddSLingrui98  // tag is left for ftb to assign
280eeb5ff92SLingrui98
281eeb5ff92SLingrui98  // case br
282eeb5ff92SLingrui98  val init_br_slot = init_entry.getSlotForBr(0)
283eeb5ff92SLingrui98  when(cfi_is_br) {
284eeb5ff92SLingrui98    init_br_slot.valid  := true.B
285eeb5ff92SLingrui98    init_br_slot.offset := io.cfiIndex.bits
286b37e4b45SLingrui98    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
287eeb5ff92SLingrui98    init_entry.always_taken(0) := true.B // set to always taken on init
288eeb5ff92SLingrui98  }
289eeb5ff92SLingrui98
290eeb5ff92SLingrui98  // case jmp
291eeb5ff92SLingrui98  when(entry_has_jmp) {
292eeb5ff92SLingrui98    init_entry.tailSlot.offset := pd.jmpOffset
293eeb5ff92SLingrui98    init_entry.tailSlot.valid  := new_jmp_is_jal || new_jmp_is_jalr
294eeb5ff92SLingrui98    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare = false)
295eeb5ff92SLingrui98  }
296eeb5ff92SLingrui98
29709c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
298a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
299a60a2901SLingrui98  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos - instOffsetBits), true.B)
30009c6f1ddSLingrui98  init_entry.isJalr  := new_jmp_is_jalr
30109c6f1ddSLingrui98  init_entry.isCall  := new_jmp_is_call
30209c6f1ddSLingrui98  init_entry.isRet   := new_jmp_is_ret
303f4ebc4b2SLingrui98  // that means fall thru points to the middle of an inst
304ae409b75SSteve Gou  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask(pd.jmpOffset)
30509c6f1ddSLingrui98
30609c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
30709c6f1ddSLingrui98  val oe              = io.old_entry
308eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
30909c6f1ddSLingrui98  val br_recorded     = br_recorded_vec.asUInt.orR
31009c6f1ddSLingrui98  val is_new_br       = cfi_is_br && !br_recorded
31109c6f1ddSLingrui98  val new_br_offset   = io.cfiIndex.bits
31209c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
313eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
31409c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map {
315*cf7d6b7aSMuzi    i =>
316*cf7d6b7aSMuzi      i match {
317eeb5ff92SLingrui98        case 0 =>
318eeb5ff92SLingrui98          !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
319eeb5ff92SLingrui98        case idx =>
320eeb5ff92SLingrui98          allBrSlotsVec(idx - 1).valid && new_br_offset > allBrSlotsVec(idx - 1).offset &&
321eeb5ff92SLingrui98          (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
32209c6f1ddSLingrui98      }
32309c6f1ddSLingrui98  })
32409c6f1ddSLingrui98
32509c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
32609c6f1ddSLingrui98  for (i <- 0 until numBr) {
327eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
328eeb5ff92SLingrui98    when(new_br_insert_onehot(i)) {
329eeb5ff92SLingrui98      slot.valid  := true.B
330eeb5ff92SLingrui98      slot.offset := new_br_offset
331b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr - 1)
332eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := true.B
333eeb5ff92SLingrui98    }.elsewhen(new_br_offset > oe.allSlotsForBr(i).offset) {
334eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := false.B
335eeb5ff92SLingrui98      // all other fields remain unchanged
336eeb5ff92SLingrui98    }.otherwise {
337eeb5ff92SLingrui98      // case i == 0, remain unchanged
338eeb5ff92SLingrui98      if (i != 0) {
339b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr - 1).B && !oe.brSlots.last.valid
340eeb5ff92SLingrui98        when(!noNeedToMoveFromFormerSlot) {
341eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i - 1))
342eeb5ff92SLingrui98          old_entry_modified.always_taken(i) := oe.always_taken(i)
34309c6f1ddSLingrui98        }
344eeb5ff92SLingrui98      }
345eeb5ff92SLingrui98    }
346eeb5ff92SLingrui98  }
34709c6f1ddSLingrui98
348eeb5ff92SLingrui98  // two circumstances:
349eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
350eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
351eeb5ff92SLingrui98  //        the previous last br or the new br
352eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
353eeb5ff92SLingrui98  val pft_need_to_change  = is_new_br && may_have_to_replace
35409c6f1ddSLingrui98  // it should either be the given last br or the new br
35509c6f1ddSLingrui98  when(pft_need_to_change) {
356eeb5ff92SLingrui98    val new_pft_offset =
357*cf7d6b7aSMuzi      Mux(!new_br_insert_onehot.asUInt.orR, new_br_offset, oe.allSlotsForBr.last.offset)
358eeb5ff92SLingrui98
359710a8720SLingrui98    // set jmp to invalid
36009c6f1ddSLingrui98    old_entry_modified.pftAddr              := getLower(io.start_addr) + new_pft_offset
36109c6f1ddSLingrui98    old_entry_modified.carry                := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
362f4ebc4b2SLingrui98    old_entry_modified.last_may_be_rvi_call := false.B
36309c6f1ddSLingrui98    old_entry_modified.isCall               := false.B
36409c6f1ddSLingrui98    old_entry_modified.isRet                := false.B
365eeb5ff92SLingrui98    old_entry_modified.isJalr               := false.B
36609c6f1ddSLingrui98  }
36709c6f1ddSLingrui98
36809c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
369710a8720SLingrui98  val old_target      = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
370b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
371eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3723bcae573SLingrui98  when(jalr_target_modified) {
37309c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
37409c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
37509c6f1ddSLingrui98  }
37609c6f1ddSLingrui98
37709c6f1ddSLingrui98  val old_entry_always_taken    = WireInit(oe)
37809c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
37909c6f1ddSLingrui98  for (i <- 0 until numBr) {
38009c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
38109c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
382710a8720SLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
38309c6f1ddSLingrui98  }
38409c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_ || _)
38509c6f1ddSLingrui98
38609c6f1ddSLingrui98  val derived_from_old_entry =
387*cf7d6b7aSMuzi    Mux(is_new_br, old_entry_modified, Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
38809c6f1ddSLingrui98
38909c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
39009c6f1ddSLingrui98
39109c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
39209c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map {
39309c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
39409c6f1ddSLingrui98  })
395803124a6SLingrui98  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
39609c6f1ddSLingrui98  for (i <- 0 until numBr) {
39709c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
39809c6f1ddSLingrui98  }
39909c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
40009c6f1ddSLingrui98
40109c6f1ddSLingrui98  // for perf counters
40209c6f1ddSLingrui98  io.is_init_entry            := !hit
4033bcae573SLingrui98  io.is_old_entry             := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
40409c6f1ddSLingrui98  io.is_new_br                := hit && is_new_br
4053bcae573SLingrui98  io.is_jalr_target_modified  := hit && jalr_target_modified
40609c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
407eeb5ff92SLingrui98  io.is_br_full               := hit && is_new_br && may_have_to_replace
40809c6f1ddSLingrui98}
40909c6f1ddSLingrui98
410c5c5edaeSJeniusclass FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
411c5c5edaeSJenius  val io = IO(new Bundle {
412c5c5edaeSJenius    val ifuPtr_w           = Input(new FtqPtr)
413c5c5edaeSJenius    val ifuPtrPlus1_w      = Input(new FtqPtr)
4146bf9b30dSLingrui98    val ifuPtrPlus2_w      = Input(new FtqPtr)
415b92f8445Sssszwic    val pfPtr_w            = Input(new FtqPtr)
416b92f8445Sssszwic    val pfPtrPlus1_w       = Input(new FtqPtr)
417c5c5edaeSJenius    val commPtr_w          = Input(new FtqPtr)
4186bf9b30dSLingrui98    val commPtrPlus1_w     = Input(new FtqPtr)
419c5c5edaeSJenius    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
420c5c5edaeSJenius    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
4216bf9b30dSLingrui98    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
422b92f8445Sssszwic    val pfPtr_rdata        = Output(new Ftq_RF_Components)
423b92f8445Sssszwic    val pfPtrPlus1_rdata   = Output(new Ftq_RF_Components)
424c5c5edaeSJenius    val commPtr_rdata      = Output(new Ftq_RF_Components)
4256bf9b30dSLingrui98    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
426c5c5edaeSJenius
427c5c5edaeSJenius    val wen   = Input(Bool())
428c5c5edaeSJenius    val waddr = Input(UInt(log2Ceil(FtqSize).W))
429c5c5edaeSJenius    val wdata = Input(new Ftq_RF_Components)
430c5c5edaeSJenius  })
431c5c5edaeSJenius
4326bf9b30dSLingrui98  val num_pc_read = numOtherReads + 5
433*cf7d6b7aSMuzi  val mem         = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, num_pc_read, 1, "FtqPC"))
434c5c5edaeSJenius  mem.io.wen(0)   := io.wen
435c5c5edaeSJenius  mem.io.waddr(0) := io.waddr
436c5c5edaeSJenius  mem.io.wdata(0) := io.wdata
437c5c5edaeSJenius
4386bf9b30dSLingrui98  // read one cycle ahead for ftq local reads
439*cf7d6b7aSMuzi  val raddr_vec = VecInit(Seq(
440*cf7d6b7aSMuzi    io.ifuPtr_w.value,
441*cf7d6b7aSMuzi    io.ifuPtrPlus1_w.value,
442*cf7d6b7aSMuzi    io.ifuPtrPlus2_w.value,
443*cf7d6b7aSMuzi    io.pfPtr_w.value,
444*cf7d6b7aSMuzi    io.pfPtrPlus1_w.value,
445*cf7d6b7aSMuzi    io.commPtrPlus1_w.value,
446*cf7d6b7aSMuzi    io.commPtr_w.value
447*cf7d6b7aSMuzi  ))
448c5c5edaeSJenius
449c5c5edaeSJenius  mem.io.raddr := raddr_vec
450c5c5edaeSJenius
451b92f8445Sssszwic  io.ifuPtr_rdata       := mem.io.rdata.dropRight(6).last
452b92f8445Sssszwic  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(5).last
453b92f8445Sssszwic  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(4).last
454b92f8445Sssszwic  io.pfPtr_rdata        := mem.io.rdata.dropRight(3).last
455b92f8445Sssszwic  io.pfPtrPlus1_rdata   := mem.io.rdata.dropRight(2).last
4566bf9b30dSLingrui98  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
457c5c5edaeSJenius  io.commPtr_rdata      := mem.io.rdata.last
458c5c5edaeSJenius}
459c5c5edaeSJenius
46009c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
461e30430c2SJay    with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
462e30430c2SJay    with HasICacheParameters {
46309c6f1ddSLingrui98  val io = IO(new Bundle {
46409c6f1ddSLingrui98    val fromBpu     = Flipped(new BpuToFtqIO)
46509c6f1ddSLingrui98    val fromIfu     = Flipped(new IfuToFtqIO)
46609c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
46709c6f1ddSLingrui98
46809c6f1ddSLingrui98    val toBpu       = new FtqToBpuIO
46909c6f1ddSLingrui98    val toIfu       = new FtqToIfuIO
470c5c5edaeSJenius    val toICache    = new FtqToICacheIO
47109c6f1ddSLingrui98    val toBackend   = new FtqToCtrlIO
472b92f8445Sssszwic    val toPrefetch  = new FtqToPrefetchIO
473b92f8445Sssszwic    val icacheFlush = Output(Bool())
4747052722fSJay
47509c6f1ddSLingrui98    val bpuInfo = new Bundle {
47609c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
47709c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
47809c6f1ddSLingrui98    }
4791d1e6d4dSJenius
4801d1e6d4dSJenius    val mmioCommitRead = Flipped(new mmioCommitRead)
481d2b20d1aSTang Haojin
482d2b20d1aSTang Haojin    // for perf
483d2b20d1aSTang Haojin    val ControlBTBMissBubble = Output(Bool())
484d2b20d1aSTang Haojin    val TAGEMissBubble       = Output(Bool())
485d2b20d1aSTang Haojin    val SCMissBubble         = Output(Bool())
486d2b20d1aSTang Haojin    val ITTAGEMissBubble     = Output(Bool())
487d2b20d1aSTang Haojin    val RASMissBubble        = Output(Bool())
48809c6f1ddSLingrui98  })
48909c6f1ddSLingrui98  io.bpuInfo := DontCare
49009c6f1ddSLingrui98
491d2b20d1aSTang Haojin  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
492d2b20d1aSTang Haojin  // only driven by clock, not valid-ready
493d2b20d1aSTang Haojin  topdown_stage                  := io.fromBpu.resp.bits.topdown_info
494d2b20d1aSTang Haojin  io.toIfu.req.bits.topdown_info := topdown_stage
495d2b20d1aSTang Haojin
496d2b20d1aSTang Haojin  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
497d2b20d1aSTang Haojin
49842dddaceSXuan Hu  // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception
49942dddaceSXuan Hu  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju
50042dddaceSXuan Hu  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0)
501bace178aSGao-Zeyu
502bace178aSGao-Zeyu  val aheadValid         = ftqIdxAhead.map(_.valid).reduce(_ | _) && !io.fromBackend.redirect.valid
503bace178aSGao-Zeyu  val realAhdValid       = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
504d2b20d1aSTang Haojin  val backendRedirect    = Wire(Valid(new BranchPredictionRedirect))
5051c6fc24aSEaston Man  val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect))
5061c6fc24aSEaston Man  backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid))
5071c6fc24aSEaston Man  backendRedirectReg.bits  := RegEnable(backendRedirect.bits, backendRedirect.valid)
508bace178aSGao-Zeyu  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
509bace178aSGao-Zeyu  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
51009c6f1ddSLingrui98
511df5b4b8eSYinan Xu  val stage2Flush  = backendRedirect.valid
51209c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
51309c6f1ddSLingrui98  val ifuFlush     = Wire(Bool())
51409c6f1ddSLingrui98
51509c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
51609c6f1ddSLingrui98
51709c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
51809c6f1ddSLingrui98  val flushToIfu             = !allowToIfu
519bace178aSGao-Zeyu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
520bace178aSGao-Zeyu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
52109c6f1ddSLingrui98
522f56177cbSJenius  def copyNum                                              = 5
523b92f8445Sssszwic  val bpuPtr, ifuPtr, pfPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U))
524c9bc5480SLingrui98  val ifuPtrPlus1                                          = RegInit(FtqPtr(false.B, 1.U))
5256bf9b30dSLingrui98  val ifuPtrPlus2                                          = RegInit(FtqPtr(false.B, 2.U))
526b92f8445Sssszwic  val pfPtrPlus1                                           = RegInit(FtqPtr(false.B, 1.U))
5276bf9b30dSLingrui98  val commPtrPlus1                                         = RegInit(FtqPtr(false.B, 1.U))
528f56177cbSJenius  val copied_ifu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
529dc270d3bSJenius  val copied_bpu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
5306bf9b30dSLingrui98  require(FtqSize >= 4)
531c5c5edaeSJenius  val ifuPtr_write       = WireInit(ifuPtr)
532c5c5edaeSJenius  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
5336bf9b30dSLingrui98  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
534b92f8445Sssszwic  val pfPtr_write        = WireInit(pfPtr)
535b92f8445Sssszwic  val pfPtrPlus1_write   = WireInit(pfPtrPlus1)
536c5c5edaeSJenius  val ifuWbPtr_write     = WireInit(ifuWbPtr)
537c5c5edaeSJenius  val commPtr_write      = WireInit(commPtr)
5386bf9b30dSLingrui98  val commPtrPlus1_write = WireInit(commPtrPlus1)
53989cc69c1STang Haojin  val robCommPtr_write   = WireInit(robCommPtr)
540c5c5edaeSJenius  ifuPtr       := ifuPtr_write
541c5c5edaeSJenius  ifuPtrPlus1  := ifuPtrPlus1_write
5426bf9b30dSLingrui98  ifuPtrPlus2  := ifuPtrPlus2_write
543b92f8445Sssszwic  pfPtr        := pfPtr_write
544b92f8445Sssszwic  pfPtrPlus1   := pfPtrPlus1_write
545c5c5edaeSJenius  ifuWbPtr     := ifuWbPtr_write
546c5c5edaeSJenius  commPtr      := commPtr_write
547f83ef67eSLingrui98  commPtrPlus1 := commPtrPlus1_write
548f56177cbSJenius  copied_ifu_ptr.map { ptr =>
549f56177cbSJenius    ptr := ifuPtr_write
550f56177cbSJenius    dontTouch(ptr)
551f56177cbSJenius  }
55289cc69c1STang Haojin  robCommPtr := robCommPtr_write
55309c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
55443aca6c2SGuokai Chen  val canCommit    = Wire(Bool())
55509c6f1ddSLingrui98
556c1b28b66STang Haojin  // Instruction page fault and instruction access fault are sent from backend with redirect requests.
557c1b28b66STang Haojin  // When IPF and IAF are sent, backendPcFaultIfuPtr points to the FTQ entry whose first instruction
558c1b28b66STang Haojin  // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write.
559c1b28b66STang Haojin  // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this
560c1b28b66STang Haojin  // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests.
561c1b28b66STang Haojin  val backendIpf        = RegInit(false.B)
562c1b28b66STang Haojin  val backendIgpf       = RegInit(false.B)
563c1b28b66STang Haojin  val backendIaf        = RegInit(false.B)
564c1b28b66STang Haojin  val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U))
565c1b28b66STang Haojin  when(fromBackendRedirect.valid) {
566c1b28b66STang Haojin    backendIpf  := fromBackendRedirect.bits.cfiUpdate.backendIPF
567c1b28b66STang Haojin    backendIgpf := fromBackendRedirect.bits.cfiUpdate.backendIGPF
568c1b28b66STang Haojin    backendIaf  := fromBackendRedirect.bits.cfiUpdate.backendIAF
569*cf7d6b7aSMuzi    when(
570*cf7d6b7aSMuzi      fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || fromBackendRedirect.bits.cfiUpdate.backendIAF
571*cf7d6b7aSMuzi    ) {
572c1b28b66STang Haojin      backendPcFaultPtr := ifuWbPtr_write
573c1b28b66STang Haojin    }
574c1b28b66STang Haojin  }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) {
575c1b28b66STang Haojin    backendIpf  := false.B
576c1b28b66STang Haojin    backendIgpf := false.B
577c1b28b66STang Haojin    backendIaf  := false.B
578c1b28b66STang Haojin  }
579c1b28b66STang Haojin
58009c6f1ddSLingrui98  // **********************************************************************
58109c6f1ddSLingrui98  // **************************** enq from bpu ****************************
58209c6f1ddSLingrui98  // **********************************************************************
58343aca6c2SGuokai Chen  val new_entry_ready = validEntries < FtqSize.U || canCommit
58409c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
58509c6f1ddSLingrui98
58609c6f1ddSLingrui98  val bpu_s2_resp     = io.fromBpu.resp.bits.s2
587cb4f77ceSLingrui98  val bpu_s3_resp     = io.fromBpu.resp.bits.s3
588adc0b8dfSGuokai Chen  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
589adc0b8dfSGuokai Chen  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
59009c6f1ddSLingrui98
59109c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
592935edac4STang Haojin  val enq_fire    = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
593935edac4STang Haojin  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
59409c6f1ddSLingrui98
595b37e4b45SLingrui98  val bpu_in_resp     = io.fromBpu.resp.bits.selectedResp
596adc0b8dfSGuokai Chen  val bpu_in_stage    = io.fromBpu.resp.bits.selectedRespIdxForFtq
59709c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
59809c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
59909c6f1ddSLingrui98
600b92f8445Sssszwic  // read ports:      pfReq1 + pfReq2 ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
601b92f8445Sssszwic  val ftq_pc_mem = Module(new FtqPcMemWrapper(2))
6026bf9b30dSLingrui98  // resp from uBTB
603c5c5edaeSJenius  ftq_pc_mem.io.wen   := bpu_in_fire
604c5c5edaeSJenius  ftq_pc_mem.io.waddr := bpu_in_resp_idx
605c5c5edaeSJenius  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
60609c6f1ddSLingrui98
60709c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
608*cf7d6b7aSMuzi  val ftq_redirect_mem = Module(new SyncDataModuleTemplate(
609*cf7d6b7aSMuzi    new Ftq_Redirect_SRAMEntry,
610*cf7d6b7aSMuzi    FtqSize,
611*cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum + 1,
612*cf7d6b7aSMuzi    1,
613*cf7d6b7aSMuzi    hasRen = true
614*cf7d6b7aSMuzi  ))
61509c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
616deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
617deb3a97eSGao-Zeyu  ftq_redirect_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
618deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_spec_info
619deb3a97eSGao-Zeyu  println(f"ftq redirect MEM: entry ${ftq_redirect_mem.io.wdata(0).getWidth} * ${FtqSize} * 3")
62009c6f1ddSLingrui98
62109c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
62209c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
623adc0b8dfSGuokai Chen  ftq_meta_1r_sram.io.wen             := io.fromBpu.resp.bits.lastStage.valid(3)
62409c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr           := io.fromBpu.resp.bits.lastStage.ftq_idx.value
625c2d1ec7dSLingrui98  ftq_meta_1r_sram.io.wdata.meta      := io.fromBpu.resp.bits.last_stage_meta
626deb3a97eSGao-Zeyu  ftq_meta_1r_sram.io.wdata.ftb_entry := io.fromBpu.resp.bits.last_stage_ftb_entry
62795a47398SGao-Zeyu  //                                                            ifuRedirect + backendRedirect (commit moved to ftq_meta_1r_sram)
628*cf7d6b7aSMuzi  val ftb_entry_mem = Module(new SyncDataModuleTemplate(
629*cf7d6b7aSMuzi    new FTBEntry_FtqMem,
630*cf7d6b7aSMuzi    FtqSize,
631*cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum,
632*cf7d6b7aSMuzi    1,
633*cf7d6b7aSMuzi    hasRen = true
634*cf7d6b7aSMuzi  ))
635adc0b8dfSGuokai Chen  ftb_entry_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
63609c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
637c2d1ec7dSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
63809c6f1ddSLingrui98
63909c6f1ddSLingrui98  // multi-write
640b0ed7239SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
6416bf9b30dSLingrui98  val newest_entry_target          = Reg(UInt(VAddrBits.W))
6421c6fc24aSEaston Man  val newest_entry_target_modified = RegInit(false.B)
6436bf9b30dSLingrui98  val newest_entry_ptr             = Reg(new FtqPtr)
6441c6fc24aSEaston Man  val newest_entry_ptr_modified    = RegInit(false.B)
64509c6f1ddSLingrui98  val cfiIndex_vec                 = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
64609c6f1ddSLingrui98  val mispredict_vec               = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
64709c6f1ddSLingrui98  val pred_stage                   = Reg(Vec(FtqSize, UInt(2.W)))
648209a4cafSSteve Gou  val pred_s1_cycle                = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
64909c6f1ddSLingrui98
65091346769SMuzi  val c_empty :: c_toCommit :: c_committed :: c_flushed :: Nil = Enum(4)
6511c6fc24aSEaston Man  val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) {
65291346769SMuzi    VecInit(Seq.fill(PredictWidth)(c_empty))
65309c6f1ddSLingrui98  }))
6541c6fc24aSEaston Man  val commitStateQueueEnable = WireInit(VecInit(Seq.fill(FtqSize)(false.B)))
6551c6fc24aSEaston Man  val commitStateQueueNext   = WireInit(commitStateQueueReg)
6561c6fc24aSEaston Man
6571c6fc24aSEaston Man  for (f <- 0 until FtqSize) {
6581c6fc24aSEaston Man    when(commitStateQueueEnable(f)) {
6591c6fc24aSEaston Man      commitStateQueueReg(f) := commitStateQueueNext(f)
6601c6fc24aSEaston Man    }
6611c6fc24aSEaston Man  }
66209c6f1ddSLingrui98
66309c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
66409c6f1ddSLingrui98  val entry_fetch_status         = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
66509c6f1ddSLingrui98
66609c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
66709c6f1ddSLingrui98  val entry_hit_status                         = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
66809c6f1ddSLingrui98
669f63797a4SLingrui98  // modify registers one cycle later to cut critical path
670f63797a4SLingrui98  val last_cycle_bpu_in       = RegNext(bpu_in_fire)
6711c6fc24aSEaston Man  val last_cycle_bpu_in_ptr   = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
6726bf9b30dSLingrui98  val last_cycle_bpu_in_idx   = last_cycle_bpu_in_ptr.value
6731c6fc24aSEaston Man  val last_cycle_bpu_target   = RegEnable(bpu_in_resp.getTarget(3), bpu_in_fire)
6741c6fc24aSEaston Man  val last_cycle_cfiIndex     = RegEnable(bpu_in_resp.cfiIndex(3), bpu_in_fire)
6751c6fc24aSEaston Man  val last_cycle_bpu_in_stage = RegEnable(bpu_in_stage, bpu_in_fire)
676f56177cbSJenius
6777be982afSLingrui98  def extra_copyNum_for_commitStateQueue = 2
6781c6fc24aSEaston Man  val copied_last_cycle_bpu_in =
6791c6fc24aSEaston Man    VecInit(Seq.fill(copyNum + extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
6801c6fc24aSEaston Man  val copied_last_cycle_bpu_in_ptr_for_ftq =
6811c6fc24aSEaston Man    VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
682f56177cbSJenius
6831c6fc24aSEaston Man  newest_entry_target_modified := false.B
6841c6fc24aSEaston Man  newest_entry_ptr_modified    := false.B
685f63797a4SLingrui98  when(last_cycle_bpu_in) {
686f63797a4SLingrui98    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
687f63797a4SLingrui98    cfiIndex_vec(last_cycle_bpu_in_idx)       := last_cycle_cfiIndex
688f63797a4SLingrui98    pred_stage(last_cycle_bpu_in_idx)         := last_cycle_bpu_in_stage
6896bf9b30dSLingrui98
690b0ed7239SLingrui98    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
6911c6fc24aSEaston Man    newest_entry_target_modified         := true.B
6926bf9b30dSLingrui98    newest_entry_target                  := last_cycle_bpu_target
6931c6fc24aSEaston Man    newest_entry_ptr_modified            := true.B
6946bf9b30dSLingrui98    newest_entry_ptr                     := last_cycle_bpu_in_ptr
69509c6f1ddSLingrui98  }
69609c6f1ddSLingrui98
6977be982afSLingrui98  // reduce fanout by delay write for a cycle
6987be982afSLingrui98  when(RegNext(last_cycle_bpu_in)) {
6991c6fc24aSEaston Man    mispredict_vec(RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)) :=
7001c6fc24aSEaston Man      WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
7017be982afSLingrui98  }
7027be982afSLingrui98
703209a4cafSSteve Gou  // record s1 pred cycles
704*cf7d6b7aSMuzi  pred_s1_cycle.map { vec =>
705209a4cafSSteve Gou    when(bpu_in_fire && (bpu_in_stage === BP_S1)) {
706209a4cafSSteve Gou      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
707209a4cafSSteve Gou    }
708*cf7d6b7aSMuzi  }
709209a4cafSSteve Gou
7107be982afSLingrui98  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
7117be982afSLingrui98  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
7127be982afSLingrui98  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
7137be982afSLingrui98    case ((in, ptr), i) =>
7147be982afSLingrui98      when(in) {
7157be982afSLingrui98        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
7167be982afSLingrui98        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
7177be982afSLingrui98        for (j <- 0 until perSetEntries) {
7189361b0c5SLingrui98          when(ptr.value === (i * perSetEntries + j).U) {
71991346769SMuzi            commitStateQueueNext(i * perSetEntries + j) := VecInit(Seq.fill(PredictWidth)(c_empty))
7201c6fc24aSEaston Man            // Clock gating optimization, use 1 gate cell to control a row
7211c6fc24aSEaston Man            commitStateQueueEnable(i * perSetEntries + j) := true.B
7227be982afSLingrui98          }
7237be982afSLingrui98        }
7247be982afSLingrui98      }
7259361b0c5SLingrui98  }
7267be982afSLingrui98
72709c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
728dc270d3bSJenius  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
729c9bc5480SLingrui98  when(io.toIfu.req.fire && allowToIfu) {
730c5c5edaeSJenius    ifuPtr_write      := ifuPtrPlus1
7316bf9b30dSLingrui98    ifuPtrPlus1_write := ifuPtrPlus2
7326bf9b30dSLingrui98    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
733c9bc5480SLingrui98  }
734b92f8445Sssszwic  when(io.toPrefetch.req.fire && allowToIfu) {
735b92f8445Sssszwic    pfPtr_write      := pfPtrPlus1
736b92f8445Sssszwic    pfPtrPlus1_write := pfPtrPlus1 + 1.U
737b92f8445Sssszwic  }
73809c6f1ddSLingrui98
73909c6f1ddSLingrui98  // only use ftb result to assign hit status
740adc0b8dfSGuokai Chen  when(bpu_s2_resp.valid(3)) {
741adc0b8dfSGuokai Chen    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
74209c6f1ddSLingrui98  }
74309c6f1ddSLingrui98
7442f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid      := bpu_s2_redirect
74509c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits       := bpu_s2_resp.ftq_idx
746b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.valid := bpu_s2_redirect
747b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.bits  := bpu_s2_resp.ftq_idx
748adc0b8dfSGuokai Chen  when(bpu_s2_redirect) {
74909c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
750dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
75109c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
75209c6f1ddSLingrui98    when(!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
753c5c5edaeSJenius      ifuPtr_write      := bpu_s2_resp.ftq_idx
754c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
7556bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
75609c6f1ddSLingrui98    }
757b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s2_resp.ftq_idx)) {
758b92f8445Sssszwic      pfPtr_write      := bpu_s2_resp.ftq_idx
759b92f8445Sssszwic      pfPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
760b92f8445Sssszwic    }
76109c6f1ddSLingrui98  }
76209c6f1ddSLingrui98
763cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid      := bpu_s3_redirect
764cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits       := bpu_s3_resp.ftq_idx
765b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.valid := bpu_s3_redirect
766b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.bits  := bpu_s3_resp.ftq_idx
767adc0b8dfSGuokai Chen  when(bpu_s3_redirect) {
768cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
769dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
770cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
771cb4f77ceSLingrui98    when(!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
772c5c5edaeSJenius      ifuPtr_write      := bpu_s3_resp.ftq_idx
773c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
7746bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
775cb4f77ceSLingrui98    }
776b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s3_resp.ftq_idx)) {
777b92f8445Sssszwic      pfPtr_write      := bpu_s3_resp.ftq_idx
778b92f8445Sssszwic      pfPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
779b92f8445Sssszwic    }
780cb4f77ceSLingrui98  }
781cb4f77ceSLingrui98
78209c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
783b92f8445Sssszwic  XSError(isBefore(bpuPtr, pfPtr) && !isFull(bpuPtr, pfPtr), "\npfPtr is before bpuPtr!\n")
7842448f137SGuokai Chen  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
78509c6f1ddSLingrui98
786*cf7d6b7aSMuzi  (0 until copyNum).map(i => XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n"))
787dc270d3bSJenius
78809c6f1ddSLingrui98  // ****************************************************************
78909c6f1ddSLingrui98  // **************************** to ifu ****************************
79009c6f1ddSLingrui98  // ****************************************************************
791f22cf846SJenius  // 0  for ifu, and 1-4 for ICache
792935edac4STang Haojin  val bpu_in_bypass_buf         = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
793935edac4STang Haojin  val copied_bpu_in_bypass_buf  = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
794f56177cbSJenius  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
7951c6fc24aSEaston Man  val bpu_in_bypass_ptr         = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
79609c6f1ddSLingrui98  val last_cycle_to_ifu_fire    = RegNext(io.toIfu.req.fire)
797b92f8445Sssszwic  val last_cycle_to_pf_fire     = RegNext(io.toPrefetch.req.fire)
79809c6f1ddSLingrui98
7991c6fc24aSEaston Man  val copied_bpu_in_bypass_ptr      = VecInit(Seq.fill(copyNum)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
800f56177cbSJenius  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
80188bc4f90SLingrui98
80209c6f1ddSLingrui98  // read pc and target
8036bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
8046bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
8056bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
806b92f8445Sssszwic  ftq_pc_mem.io.pfPtr_w        := pfPtr_write
807b92f8445Sssszwic  ftq_pc_mem.io.pfPtrPlus1_w   := pfPtrPlus1_write
8086bf9b30dSLingrui98  ftq_pc_mem.io.commPtr_w      := commPtr_write
8096bf9b30dSLingrui98  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
810c5c5edaeSJenius
8115ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
812f63797a4SLingrui98
813f56177cbSJenius  val toICachePcBundle               = Wire(Vec(copyNum, new Ftq_RF_Components))
814dc270d3bSJenius  val toICacheEntryToSend            = Wire(Vec(copyNum, Bool()))
8153e1dbb17SMuzi  val nextCycleToPrefetchPcBundle    = Wire(new Ftq_RF_Components)
8163e1dbb17SMuzi  val nextCycleToPrefetchEntryToSend = Wire(Bool())
8173e1dbb17SMuzi  val toPrefetchPcBundle             = RegNext(nextCycleToPrefetchPcBundle)
8183e1dbb17SMuzi  val toPrefetchEntryToSend          = RegNext(nextCycleToPrefetchEntryToSend)
819b37e4b45SLingrui98  val toIfuPcBundle                  = Wire(new Ftq_RF_Components)
820f63797a4SLingrui98  val entry_is_to_send               = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
821f63797a4SLingrui98  val entry_ftq_offset               = WireInit(cfiIndex_vec(ifuPtr.value))
8226bf9b30dSLingrui98  val entry_next_addr                = Wire(UInt(VAddrBits.W))
823b004fa13SJenius
824f56177cbSJenius  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
825f56177cbSJenius  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
826b0ed7239SLingrui98  val diff_entry_next_addr   = WireInit(update_target(ifuPtr.value)) // TODO: remove this
827f63797a4SLingrui98
828*cf7d6b7aSMuzi  val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(
829*cf7d6b7aSMuzi    entry_fetch_status(ifuPtrPlus1.value) === f_to_send
830*cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1)))
831*cf7d6b7aSMuzi  val copied_ifu_ptr_to_send = VecInit(Seq.fill(copyNum)(RegNext(
832*cf7d6b7aSMuzi    entry_fetch_status(ifuPtr.value) === f_to_send
833*cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr)))
834dc270d3bSJenius
835f56177cbSJenius  for (i <- 0 until copyNum) {
836f56177cbSJenius    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)) {
837f56177cbSJenius      toICachePcBundle(i)    := copied_bpu_in_bypass_buf(i)
838dc270d3bSJenius      toICacheEntryToSend(i) := true.B
839f56177cbSJenius    }.elsewhen(copied_last_cycle_to_ifu_fire(i)) {
840f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_plus1_rdata(i)
841dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i)
842f56177cbSJenius    }.otherwise {
843f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_ptr_rdata(i)
844dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i)
845f56177cbSJenius    }
846f56177cbSJenius  }
847f56177cbSJenius
8483e1dbb17SMuzi  // Calculate requests sent to prefetcher one cycle in advance to cut critical path
8493e1dbb17SMuzi  when(bpu_in_fire && bpu_in_resp_ptr === pfPtr_write) {
8503e1dbb17SMuzi    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.wdata
8513e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := true.B
8523e1dbb17SMuzi  }.elsewhen(io.toPrefetch.req.fire) {
8533e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtrPlus1_rdata
8543e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtrPlus1.value) === f_to_send ||
8553e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtrPlus1
856b92f8445Sssszwic  }.otherwise {
8573e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtr_rdata
8583e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtr.value) === f_to_send ||
8593e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr // reduce potential bubbles
860b92f8445Sssszwic  }
861b92f8445Sssszwic
862873dc383SLingrui98  // TODO: reconsider target address bypass logic
86309c6f1ddSLingrui98  when(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
86488bc4f90SLingrui98    toIfuPcBundle        := bpu_in_bypass_buf_for_ifu
865f678dd91SSteve Gou    entry_is_to_send     := true.B
8666bf9b30dSLingrui98    entry_next_addr      := last_cycle_bpu_target
867f63797a4SLingrui98    entry_ftq_offset     := last_cycle_cfiIndex
868b0ed7239SLingrui98    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
86909c6f1ddSLingrui98  }.elsewhen(last_cycle_to_ifu_fire) {
870c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
871c5c5edaeSJenius    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
872*cf7d6b7aSMuzi      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1) // reduce potential bubbles
873*cf7d6b7aSMuzi    entry_next_addr := Mux(
874*cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
87588bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
876*cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))
877*cf7d6b7aSMuzi    ) // ifuPtr+2
878c5c5edaeSJenius  }.otherwise {
879c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
88028f2cf58SLingrui98    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
88128f2cf58SLingrui98      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
882*cf7d6b7aSMuzi    entry_next_addr := Mux(
883*cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
88488bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
885*cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))
886*cf7d6b7aSMuzi    ) // ifuPtr+1
88709c6f1ddSLingrui98  }
88809c6f1ddSLingrui98
889f678dd91SSteve Gou  io.toIfu.req.valid              := entry_is_to_send && ifuPtr =/= bpuPtr
890f63797a4SLingrui98  io.toIfu.req.bits.nextStartAddr := entry_next_addr
891f63797a4SLingrui98  io.toIfu.req.bits.ftqOffset     := entry_ftq_offset
892b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
893c5c5edaeSJenius
894c5c5edaeSJenius  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
895*cf7d6b7aSMuzi  io.toICache.req.bits.readValid.zipWithIndex.map { case (copy, i) =>
896*cf7d6b7aSMuzi    copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)
897*cf7d6b7aSMuzi  }
898b92f8445Sssszwic  io.toICache.req.bits.pcMemRead.zipWithIndex.foreach { case (copy, i) =>
899b92f8445Sssszwic    copy.fromFtqPcBundle(toICachePcBundle(i))
900b92f8445Sssszwic    copy.ftqIdx := ifuPtr
901b92f8445Sssszwic  }
902c1b28b66STang Haojin  io.toICache.req.bits.backendIpf  := backendIpf && backendPcFaultPtr === ifuPtr
903c1b28b66STang Haojin  io.toICache.req.bits.backendIgpf := backendIgpf && backendPcFaultPtr === ifuPtr
904c1b28b66STang Haojin  io.toICache.req.bits.backendIaf  := backendIaf && backendPcFaultPtr === ifuPtr
905b92f8445Sssszwic
906b92f8445Sssszwic  io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
907b92f8445Sssszwic  io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle)
908b92f8445Sssszwic  io.toPrefetch.req.bits.ftqIdx := pfPtr
909b004fa13SJenius  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
910b004fa13SJenius  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
911b004fa13SJenius  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
912b004fa13SJenius  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
913b004fa13SJenius  // }
914f22cf846SJenius
915b0ed7239SLingrui98  // TODO: remove this
916*cf7d6b7aSMuzi  XSError(
917*cf7d6b7aSMuzi    io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
918*cf7d6b7aSMuzi    p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n"
919*cf7d6b7aSMuzi  )
920b0ed7239SLingrui98
92109c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
922b37e4b45SLingrui98  when(toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
92309c6f1ddSLingrui98    when(io.toIfu.req.fire &&
924cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
925*cf7d6b7aSMuzi      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) {
92609c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
927352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
92809c6f1ddSLingrui98    }
929*cf7d6b7aSMuzi    XSDebug(
930*cf7d6b7aSMuzi      true.B,
931*cf7d6b7aSMuzi      "fallThruError! start:%x, fallThru:%x\n",
932*cf7d6b7aSMuzi      io.toIfu.req.bits.startAddr,
933*cf7d6b7aSMuzi      io.toIfu.req.bits.nextStartAddr
934*cf7d6b7aSMuzi    )
93509c6f1ddSLingrui98  }
93609c6f1ddSLingrui98
937*cf7d6b7aSMuzi  XSPerfAccumulate(
938*cf7d6b7aSMuzi    f"fall_through_error_to_ifu",
939*cf7d6b7aSMuzi    toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
940*cf7d6b7aSMuzi      io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
941*cf7d6b7aSMuzi  )
942a60a2901SLingrui98
94309c6f1ddSLingrui98  val ifu_req_should_be_flushed =
944cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
945cb4f77ceSLingrui98      io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
94609c6f1ddSLingrui98
94709c6f1ddSLingrui98  when(io.toIfu.req.fire && !ifu_req_should_be_flushed) {
94809c6f1ddSLingrui98    entry_fetch_status(ifuPtr.value) := f_sent
94909c6f1ddSLingrui98  }
95009c6f1ddSLingrui98
95109c6f1ddSLingrui98  // *********************************************************************
95209c6f1ddSLingrui98  // **************************** wb from ifu ****************************
95309c6f1ddSLingrui98  // *********************************************************************
95409c6f1ddSLingrui98  val pdWb         = io.fromIfu.pdWb
95509c6f1ddSLingrui98  val pds          = pdWb.bits.pd
95609c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
95709c6f1ddSLingrui98  val ifu_wb_idx   = pdWb.bits.ftqIdx.value
95809c6f1ddSLingrui98  // read ports:                                                         commit update
959*cf7d6b7aSMuzi  val ftq_pd_mem =
960*cf7d6b7aSMuzi    Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum + 1, 1, hasRen = true))
96109c6f1ddSLingrui98  ftq_pd_mem.io.wen(0)   := ifu_wb_valid
96209c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
96309c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
96409c6f1ddSLingrui98
96509c6f1ddSLingrui98  val hit_pd_valid       = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
96609c6f1ddSLingrui98  val hit_pd_mispred     = hit_pd_valid && pdWb.bits.misOffset.valid
96709c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init = false.B)
968005e809bSJiuyang Liu  val pd_reg             = RegEnable(pds, pdWb.valid)
969005e809bSJiuyang Liu  val start_pc_reg       = RegEnable(pdWb.bits.pc(0), pdWb.valid)
970005e809bSJiuyang Liu  val wb_idx_reg         = RegEnable(ifu_wb_idx, pdWb.valid)
97109c6f1ddSLingrui98
97209c6f1ddSLingrui98  when(ifu_wb_valid) {
97309c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map {
97409c6f1ddSLingrui98      case (v, inRange) => v && inRange
97509c6f1ddSLingrui98    })
9761c6fc24aSEaston Man    commitStateQueueEnable(ifu_wb_idx) := true.B
9771c6fc24aSEaston Man    (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map {
9781c6fc24aSEaston Man      case (qe, v) => when(v) {
97991346769SMuzi          qe := c_toCommit
9801c6fc24aSEaston Man        }
98109c6f1ddSLingrui98    }
98209c6f1ddSLingrui98  }
98309c6f1ddSLingrui98
984c5c5edaeSJenius  when(ifu_wb_valid) {
985c5c5edaeSJenius    ifuWbPtr_write := ifuWbPtr + 1.U
986c5c5edaeSJenius  }
98709c6f1ddSLingrui98
988f21bbcb2SGuokai Chen  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
989f21bbcb2SGuokai Chen
9901c6fc24aSEaston Man  ftb_entry_mem.io.ren.get.head := ifu_wb_valid
99109c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head   := ifu_wb_idx
99209c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
99309c6f1ddSLingrui98  when(RegNext(hit_pd_valid)) {
99409c6f1ddSLingrui98    // check for false hit
99509c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
996eeb5ff92SLingrui98    val brSlots        = pred_ftb_entry.brSlots
997eeb5ff92SLingrui98    val tailSlot       = pred_ftb_entry.tailSlot
99809c6f1ddSLingrui98    // we check cfis that bpu predicted
99909c6f1ddSLingrui98
1000eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
1001eeb5ff92SLingrui98    val br_false_hit =
1002eeb5ff92SLingrui98      brSlots.map {
1003eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
1004eeb5ff92SLingrui98      }.reduce(_ || _) ||
1005b37e4b45SLingrui98        (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
1006eeb5ff92SLingrui98          !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
1007eeb5ff92SLingrui98
1008eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
100909c6f1ddSLingrui98    val jmp_pd    = pd_reg(jmpOffset)
101009c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
101109c6f1ddSLingrui98      ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) ||
101209c6f1ddSLingrui98        (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
101309c6f1ddSLingrui98        (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
1014*cf7d6b7aSMuzi        (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)))
101509c6f1ddSLingrui98
101609c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
101765fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
101865fddcf0Szoujr
1019352db50aSLingrui98    // assert(!has_false_hit)
102009c6f1ddSLingrui98  }
102109c6f1ddSLingrui98
102209c6f1ddSLingrui98  when(has_false_hit) {
102309c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
102409c6f1ddSLingrui98  }
102509c6f1ddSLingrui98
102609c6f1ddSLingrui98  // *******************************************************************************
102709c6f1ddSLingrui98  // **************************** redirect from backend ****************************
102809c6f1ddSLingrui98  // *******************************************************************************
102909c6f1ddSLingrui98
103009c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
103195a47398SGao-Zeyu  // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1)
1032bace178aSGao-Zeyu  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
1033deb3a97eSGao-Zeyu  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem))
1034c776f0d5Smy-mayfly
1035c776f0d5Smy-mayfly  val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry))
103695a47398SGao-Zeyu  for (i <- 1 until FtqRedirectAheadNum) {
103795a47398SGao-Zeyu    ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid
103895a47398SGao-Zeyu    ftq_redirect_mem.io.raddr(i + IfuRedirectNum)   := ftqIdxAhead(i).bits.value
103995a47398SGao-Zeyu    ftb_entry_mem.io.ren.get(i + IfuRedirectNum)    := ftqIdxAhead(i).valid
104095a47398SGao-Zeyu    ftb_entry_mem.io.raddr(i + IfuRedirectNum)      := ftqIdxAhead(i).bits.value
1041c776f0d5Smy-mayfly
1042c776f0d5Smy-mayfly    ftq_pd_mem.io.ren.get(i) := ftqIdxAhead(i).valid
1043c776f0d5Smy-mayfly    ftq_pd_mem.io.raddr(i)   := ftqIdxAhead(i).bits.value
10449342624fSGao-Zeyu  }
104595a47398SGao-Zeyu  ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1046*cf7d6b7aSMuzi  ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux(
1047*cf7d6b7aSMuzi    aheadValid,
1048*cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1049*cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1050*cf7d6b7aSMuzi  )
105195a47398SGao-Zeyu  ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1052*cf7d6b7aSMuzi  ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux(
1053*cf7d6b7aSMuzi    aheadValid,
1054*cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1055*cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1056*cf7d6b7aSMuzi  )
1057bace178aSGao-Zeyu
1058c776f0d5Smy-mayfly  ftq_pd_mem.io.ren.get(0) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1059c776f0d5Smy-mayfly  ftq_pd_mem.io.raddr(0)   := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1060c776f0d5Smy-mayfly
1061bace178aSGao-Zeyu  for (i <- 0 until FtqRedirectAheadNum) {
106295a47398SGao-Zeyu    ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum)
106395a47398SGao-Zeyu    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum)
1064c776f0d5Smy-mayfly
1065c776f0d5Smy-mayfly    ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i)
1066bace178aSGao-Zeyu  }
1067*cf7d6b7aSMuzi  val stage3CfiInfo =
1068*cf7d6b7aSMuzi    Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum))
1069c776f0d5Smy-mayfly  val stage3PdInfo       = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0))
107009c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
107109c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
1072c776f0d5Smy-mayfly  backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset)
107309c6f1ddSLingrui98
107495a47398SGao-Zeyu  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum))
107509c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
107609c6f1ddSLingrui98
1077d2b20d1aSTang Haojin  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
1078d2b20d1aSTang Haojin  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
10793711cf36S小造xu_zh  // FIXME: not portable
1080abdc3a32Sxu_zh  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
1081*cf7d6b7aSMuzi  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(
1082*cf7d6b7aSMuzi    r_ftb_entry.brSlots(0).offset === r_ftqOffset,
1083*cf7d6b7aSMuzi    sc_disagree(0),
1084*cf7d6b7aSMuzi    sc_disagree(1)
1085*cf7d6b7aSMuzi  )
1086d2b20d1aSTang Haojin
108709c6f1ddSLingrui98  when(entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
108809c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
108909c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
1090eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
109109c6f1ddSLingrui98
109209c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
1093eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
109409c6f1ddSLingrui98  }.otherwise {
109509c6f1ddSLingrui98    backendRedirectCfi.shift       := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
109609c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
109709c6f1ddSLingrui98  }
109809c6f1ddSLingrui98
109909c6f1ddSLingrui98  // ***************************************************************************
110009c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
110109c6f1ddSLingrui98  // ***************************************************************************
1102d2b20d1aSTang Haojin  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
110309c6f1ddSLingrui98  fromIfuRedirect.valid              := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
110409c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx        := pdWb.bits.ftqIdx
110509c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset     := pdWb.bits.misOffset.bits
110609c6f1ddSLingrui98  fromIfuRedirect.bits.level         := RedirectLevel.flushAfter
1107d2b20d1aSTang Haojin  fromIfuRedirect.bits.BTBMissBubble := true.B
1108d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsMemVio := false.B
1109d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsCtrl   := false.B
111009c6f1ddSLingrui98
111109c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
111209c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc        := pdWb.bits.pc(pdWb.bits.misOffset.bits)
111309c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd        := pdWb.bits.pd(pdWb.bits.misOffset.bits)
111409c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
111509c6f1ddSLingrui98  ifuRedirectCfiUpdate.target    := pdWb.bits.target
111609c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken     := pdWb.bits.cfiOffset.valid
111709c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
111809c6f1ddSLingrui98
11191c6fc24aSEaston Man  val ifuRedirectReg   = RegNextWithEnable(fromIfuRedirect, hasInit = true)
112009c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
112109c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
112209c6f1ddSLingrui98
112316a171eeSEaston Man  ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid
1124deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.head   := fromIfuRedirect.bits.ftqIdx.value
112509c6f1ddSLingrui98
112609c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
1127deb3a97eSGao-Zeyu  toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head)
1128f1267a13SEaston Man  when(ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
1129c89b4642SGuokai Chen    toBpuCfi.target := toBpuCfi.topAddr
113009c6f1ddSLingrui98  }
113109c6f1ddSLingrui98
1132d2b20d1aSTang Haojin  when(ifuRedirectReg.valid) {
1133d2b20d1aSTang Haojin    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
1134d2b20d1aSTang Haojin  }.elsewhen(RegNext(pdWb.valid)) {
1135d2b20d1aSTang Haojin    // if pdWb and no redirect, set to false
1136d2b20d1aSTang Haojin    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
1137d2b20d1aSTang Haojin  }
1138d2b20d1aSTang Haojin
11396022c595SsinceforYy  // **********************************************************************
11406022c595SsinceforYy  // ***************************** to backend *****************************
11416022c595SsinceforYy  // **********************************************************************
11426022c595SsinceforYy  // to backend pc mem / target
11436022c595SsinceforYy  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
1144f533cba7SHuSipeng  io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)
11456022c595SsinceforYy  io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in)
11466022c595SsinceforYy
11476022c595SsinceforYy  // num cycle is fixed
11486022c595SsinceforYy  val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid)
11496022c595SsinceforYy  io.toBackend.newest_entry_en     := RegNext(newest_entry_en)
11506022c595SsinceforYy  io.toBackend.newest_entry_ptr    := RegEnable(newest_entry_ptr, newest_entry_en)
11516022c595SsinceforYy  io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en)
11526022c595SsinceforYy
115309c6f1ddSLingrui98  // *********************************************************************
115409c6f1ddSLingrui98  // **************************** wb from exu ****************************
115509c6f1ddSLingrui98  // *********************************************************************
115609c6f1ddSLingrui98
1157d2b20d1aSTang Haojin  backendRedirect.valid := io.fromBackend.redirect.valid
1158d2b20d1aSTang Haojin  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1159d2b20d1aSTang Haojin  backendRedirect.bits.BTBMissBubble := false.B
1160d2b20d1aSTang Haojin
116109c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
11626bf9b30dSLingrui98    val ftqPtr    = wb.bits.ftqIdx
116309c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
116409c6f1ddSLingrui98    val taken     = wb.bits.cfiUpdate.taken
116509c6f1ddSLingrui98    val mispred   = wb.bits.cfiUpdate.isMisPred
11666bf9b30dSLingrui98    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
116709c6f1ddSLingrui98  }
116809c6f1ddSLingrui98
116909c6f1ddSLingrui98  // fix mispredict entry
117009c6f1ddSLingrui98  val lastIsMispredict = RegNext(
1171*cf7d6b7aSMuzi    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter,
1172*cf7d6b7aSMuzi    init = false.B
117309c6f1ddSLingrui98  )
117409c6f1ddSLingrui98
117509c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
11766bf9b30dSLingrui98    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
11776bf9b30dSLingrui98    val r_idx                                          = r_ptr.value
117809c6f1ddSLingrui98    val cfiIndex_bits_wen                              = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
117909c6f1ddSLingrui98    val cfiIndex_valid_wen                             = r_valid && r_offset === cfiIndex_vec(r_idx).bits
118009c6f1ddSLingrui98    when(cfiIndex_bits_wen || cfiIndex_valid_wen) {
118109c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
11823f88c020SGuokai Chen    }.elsewhen(r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
11833f88c020SGuokai Chen      cfiIndex_vec(r_idx).valid := false.B
118409c6f1ddSLingrui98    }
118509c6f1ddSLingrui98    when(cfiIndex_bits_wen) {
118609c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
118709c6f1ddSLingrui98    }
11881c6fc24aSEaston Man    newest_entry_target_modified := true.B
11896bf9b30dSLingrui98    newest_entry_target          := redirect.bits.cfiUpdate.target
11901c6fc24aSEaston Man    newest_entry_ptr_modified    := true.B
1191873dc383SLingrui98    newest_entry_ptr             := r_ptr
11921c6fc24aSEaston Man
1193b0ed7239SLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
119409c6f1ddSLingrui98    if (isBackend) {
119509c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
119609c6f1ddSLingrui98    }
119709c6f1ddSLingrui98  }
119809c6f1ddSLingrui98
1199bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1200bace178aSGao-Zeyu    updateCfiInfo(fromBackendRedirect)
120109c6f1ddSLingrui98  }.elsewhen(ifuRedirectToBpu.valid) {
120209c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend = false)
120309c6f1ddSLingrui98  }
120409c6f1ddSLingrui98
1205bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1206bace178aSGao-Zeyu    when(fromBackendRedirect.bits.ControlRedirectBubble) {
1207d2b20d1aSTang Haojin      when(fromBackendRedirect.bits.ControlBTBMissBubble) {
1208d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1209d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1210d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.TAGEMissBubble) {
1211d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id)                  := true.B
1212d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1213d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.SCMissBubble) {
1214d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.SCMissBubble.id)                  := true.B
1215d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1216d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.ITTAGEMissBubble) {
1217d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id)                  := true.B
1218d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1219d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.RASMissBubble) {
1220d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.RASMissBubble.id)                  := true.B
1221d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1222d2b20d1aSTang Haojin      }
1223d2b20d1aSTang Haojin
12249342624fSGao-Zeyu    }.elsewhen(backendRedirect.bits.MemVioRedirectBubble) {
1225d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id)                  := true.B
1226d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1227d2b20d1aSTang Haojin    }.otherwise {
1228d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id)                  := true.B
1229d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1230d2b20d1aSTang Haojin    }
1231d2b20d1aSTang Haojin  }.elsewhen(ifuRedirectReg.valid) {
1232d2b20d1aSTang Haojin    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1233d2b20d1aSTang Haojin    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1234d2b20d1aSTang Haojin  }
1235d2b20d1aSTang Haojin
1236d2b20d1aSTang Haojin  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1237d2b20d1aSTang Haojin  io.TAGEMissBubble       := fromBackendRedirect.bits.TAGEMissBubble
1238d2b20d1aSTang Haojin  io.SCMissBubble         := fromBackendRedirect.bits.SCMissBubble
1239d2b20d1aSTang Haojin  io.ITTAGEMissBubble     := fromBackendRedirect.bits.ITTAGEMissBubble
1240d2b20d1aSTang Haojin  io.RASMissBubble        := fromBackendRedirect.bits.RASMissBubble
1241d2b20d1aSTang Haojin
124209c6f1ddSLingrui98  // ***********************************************************************************
124309c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
124409c6f1ddSLingrui98  // ***********************************************************************************
124509c6f1ddSLingrui98
1246df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
124709c6f1ddSLingrui98
124809c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
1249b92f8445Sssszwic  io.icacheFlush := redirectVec.map(r => r.valid).reduce(_ || _)
1250b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid)
1251b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid)
125209c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_ || _)) {
1253*cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
125409c6f1ddSLingrui98    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
12552f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
125609c6f1ddSLingrui98    val next                       = idx + 1.U
125709c6f1ddSLingrui98    bpuPtr := next
1258dc270d3bSJenius    copied_bpu_ptr.map(_ := next)
1259c5c5edaeSJenius    ifuPtr_write      := next
1260c5c5edaeSJenius    ifuWbPtr_write    := next
1261c5c5edaeSJenius    ifuPtrPlus1_write := idx + 2.U
12626bf9b30dSLingrui98    ifuPtrPlus2_write := idx + 3.U
1263b92f8445Sssszwic    pfPtr_write       := next
1264b92f8445Sssszwic    pfPtrPlus1_write  := idx + 2.U
12653f88c020SGuokai Chen  }
12663f88c020SGuokai Chen  when(RegNext(redirectVec.map(r => r.valid).reduce(_ || _))) {
1267*cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
12683f88c020SGuokai Chen    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
12693f88c020SGuokai Chen    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
12703f88c020SGuokai Chen    when(RegNext(notIfu)) {
12711c6fc24aSEaston Man      commitStateQueueEnable(RegNext(idx.value)) := true.B
1272*cf7d6b7aSMuzi      commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach { case (s, i) =>
127391346769SMuzi        when(i.U > RegNext(offset)) {
127491346769SMuzi          s := c_empty
127591346769SMuzi        }
127691346769SMuzi        when(i.U === RegNext(offset) && RegNext(flushItSelf)) {
127791346769SMuzi          s := c_flushed
127809c6f1ddSLingrui98        }
127909c6f1ddSLingrui98      }
128009c6f1ddSLingrui98    }
1281*cf7d6b7aSMuzi  }
12823f88c020SGuokai Chen
128309c6f1ddSLingrui98  // only the valid bit is actually needed
1284df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
128509c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
1286d2b20d1aSTang Haojin  io.toIfu.topdown_redirect := fromBackendRedirect
128709c6f1ddSLingrui98
128809c6f1ddSLingrui98  // commit
12899aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
129009c6f1ddSLingrui98    when(c.valid) {
12911c6fc24aSEaston Man      commitStateQueueEnable(c.bits.ftqIdx.value)                 := true.B
129291346769SMuzi      commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed
129388825c5cSYinan Xu      // TODO: remove this
129488825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
1295c3abb8b6SYinan Xu      when(c.bits.commitType === 4.U) {
129691346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed
1297c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
129891346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed
1299c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
130088825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13011c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
130291346769SMuzi        commitStateQueueNext(index)(0) := c_committed
1303c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
130488825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13051c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
130691346769SMuzi        commitStateQueueNext(index)(1) := c_committed
130788825c5cSYinan Xu      }
130809c6f1ddSLingrui98    }
130909c6f1ddSLingrui98  }
131009c6f1ddSLingrui98
131109c6f1ddSLingrui98  // ****************************************************************
131209c6f1ddSLingrui98  // **************************** to bpu ****************************
131309c6f1ddSLingrui98  // ****************************************************************
131409c6f1ddSLingrui98
1315fd3aa057SYuandongliang  io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid
131651981c77SbugGenerator  io.toBpu.redirect       := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1317209a4cafSSteve Gou  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_ => 0.U(64.W)))
1318*cf7d6b7aSMuzi  val redirect_latency =
1319*cf7d6b7aSMuzi    GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1320209a4cafSSteve Gou  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1321*cf7d6b7aSMuzi  XSPerfHistogram(
1322*cf7d6b7aSMuzi    "ifu_redirect_latency",
1323*cf7d6b7aSMuzi    redirect_latency,
1324*cf7d6b7aSMuzi    !fromBackendRedirect.valid && ifuRedirectToBpu.valid,
1325*cf7d6b7aSMuzi    0,
1326*cf7d6b7aSMuzi    60,
1327*cf7d6b7aSMuzi    1
1328*cf7d6b7aSMuzi  )
132909c6f1ddSLingrui98
1330*cf7d6b7aSMuzi  XSError(
1331*cf7d6b7aSMuzi    io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr),
1332*cf7d6b7aSMuzi    "Ftq received a redirect after its commit, check backend or replay"
1333*cf7d6b7aSMuzi  )
133409c6f1ddSLingrui98
133502f21c16SLingrui98  val may_have_stall_from_bpu = Wire(Bool())
133602f21c16SLingrui98  val bpu_ftb_update_stall    = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
133702f21c16SLingrui98  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
13389230e379SMuzi
13399230e379SMuzi  val validInstructions       = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed)
13409230e379SMuzi  val lastInstructionStatus   = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse))
13419230e379SMuzi  val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed
13429230e379SMuzi  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13439230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13449230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed)
13459230e379SMuzi  val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13469230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13479230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed ||
13489230e379SMuzi      firstInstructionFlushed)
134991346769SMuzi
135091346769SMuzi  when(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) {
1351*cf7d6b7aSMuzi    robCommPtr_write := ParallelPriorityMux(
1352*cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.valid).reverse,
1353*cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse
1354*cf7d6b7aSMuzi    )
13559230e379SMuzi  }.elsewhen(isAfter(commPtr, robCommPtr)) {
135691346769SMuzi    robCommPtr_write := commPtr
135791346769SMuzi  }.otherwise {
135891346769SMuzi    robCommPtr_write := robCommPtr
135991346769SMuzi  }
136009c6f1ddSLingrui98
1361ba5ba1dcSmy-mayfly  /**
1362ba5ba1dcSmy-mayfly    *************************************************************************************
1363ba5ba1dcSmy-mayfly    * MMIO instruction fetch is allowed only if MMIO is the oldest instruction.
1364ba5ba1dcSmy-mayfly    *************************************************************************************
1365ba5ba1dcSmy-mayfly    */
13661d1e6d4dSJenius  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
13679230e379SMuzi  val mmioLastCommit = isAfter(commPtr, mmioReadPtr) ||
13689230e379SMuzi    commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed
13691d1e6d4dSJenius  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
13701d1e6d4dSJenius
137109c6f1ddSLingrui98  // commit reads
1372c5c5edaeSJenius  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
137381101dc4SLingrui98  val commit_target =
1374*cf7d6b7aSMuzi    Mux(
1375*cf7d6b7aSMuzi      RegNext(commPtr === newest_entry_ptr),
13761c6fc24aSEaston Man      RegEnable(newest_entry_target, newest_entry_target_modified),
1377*cf7d6b7aSMuzi      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)
1378*cf7d6b7aSMuzi    )
13791c6fc24aSEaston Man  ftq_pd_mem.io.ren.get.last := canCommit
138009c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last   := commPtr.value
138109c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
138216a171eeSEaston Man  ftq_redirect_mem.io.ren.get.last := canCommit
1383deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.last   := commPtr.value
1384deb3a97eSGao-Zeyu  val commit_spec_meta = ftq_redirect_mem.io.rdata.last
138509c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0)   := canCommit
138609c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1387deb3a97eSGao-Zeyu  val commit_meta      = ftq_meta_1r_sram.io.rdata(0).meta
1388deb3a97eSGao-Zeyu  val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry
138909c6f1ddSLingrui98
139009c6f1ddSLingrui98  // need one cycle to read mem and srams
13911c6fc24aSEaston Man  val do_commit_ptr = RegEnable(commPtr, canCommit)
13925371700eSzoujr  val do_commit     = RegNext(canCommit, init = false.B)
13939230e379SMuzi  when(canMoveCommPtr) {
13946bf9b30dSLingrui98    commPtr_write      := commPtrPlus1
13956bf9b30dSLingrui98    commPtrPlus1_write := commPtrPlus1 + 1.U
13966bf9b30dSLingrui98  }
13971c6fc24aSEaston Man  val commit_state   = RegEnable(commitStateQueueReg(commPtr.value), canCommit)
13985371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1399d4fcfc3eSGuokai Chen  val do_commit_cfi  = WireInit(cfiIndex_vec(do_commit_ptr.value))
14003f88c020SGuokai Chen  //
14013f88c020SGuokai Chen  // when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
14023f88c020SGuokai Chen  //  can_commit_cfi.valid := false.B
14033f88c020SGuokai Chen  // }
14041c6fc24aSEaston Man  val commit_cfi = RegEnable(can_commit_cfi, canCommit)
140591346769SMuzi  val debug_cfi  = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid
140609c6f1ddSLingrui98
1407*cf7d6b7aSMuzi  val commit_mispredict: Vec[Bool] =
1408*cf7d6b7aSMuzi    VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map {
140991346769SMuzi      case (mis, state) => mis && state === c_committed
141009c6f1ddSLingrui98    })
141191346769SMuzi  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth]
14125371700eSzoujr  val can_commit_hit     = entry_hit_status(commPtr.value)
14131c6fc24aSEaston Man  val commit_hit         = RegEnable(can_commit_hit, canCommit)
14141c6fc24aSEaston Man  val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this
14151c6fc24aSEaston Man  val commit_stage       = RegEnable(pred_stage(commPtr.value), canCommit)
141609c6f1ddSLingrui98  val commit_valid       = commit_hit === h_hit || commit_cfi.valid           // hit or taken
141709c6f1ddSLingrui98
14185371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
141902f21c16SLingrui98  switch(bpu_ftb_update_stall) {
142002f21c16SLingrui98    is(0.U) {
142102f21c16SLingrui98      when(can_commit_cfi.valid && !to_bpu_hit && canCommit) {
142202f21c16SLingrui98        bpu_ftb_update_stall := 2.U // 2-cycle stall
142302f21c16SLingrui98      }
142402f21c16SLingrui98    }
142502f21c16SLingrui98    is(2.U) {
142602f21c16SLingrui98      bpu_ftb_update_stall := 1.U
142702f21c16SLingrui98    }
142802f21c16SLingrui98    is(1.U) {
142902f21c16SLingrui98      bpu_ftb_update_stall := 0.U
143002f21c16SLingrui98    }
143102f21c16SLingrui98    is(3.U) {
143202f21c16SLingrui98      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
143302f21c16SLingrui98    }
143402f21c16SLingrui98  }
143509c6f1ddSLingrui98
1436b0ed7239SLingrui98  // TODO: remove this
1437b0ed7239SLingrui98  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1438b0ed7239SLingrui98
1439b2f6ed0aSSteve Gou  // update latency stats
1440b2f6ed0aSSteve Gou  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1441b2f6ed0aSSteve Gou  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1442b2f6ed0aSSteve Gou
144309c6f1ddSLingrui98  io.toBpu.update       := DontCare
144409c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
144509c6f1ddSLingrui98  val update = io.toBpu.update.bits
144609c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
144709c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
1448deb3a97eSGao-Zeyu  update.meta        := commit_meta
1449803124a6SLingrui98  update.cfi_idx     := commit_cfi
14508ffcd86aSLingrui98  update.full_target := commit_target
1451edc18578SLingrui98  update.from_stage  := commit_stage
1452c2d1ec7dSLingrui98  update.spec_info   := commit_spec_meta
14533f88c020SGuokai Chen  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
145409c6f1ddSLingrui98
145509c6f1ddSLingrui98  val commit_real_hit  = commit_hit === h_hit
145609c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
145709c6f1ddSLingrui98
145809c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
145909c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
146009c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
146109c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
146209c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
146309c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
146409c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
146509c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
146609c6f1ddSLingrui98
146709c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
146809c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
146909c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
147009c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
1471edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1472803124a6SLingrui98  update.br_taken_mask     := ftbEntryGen.taken_mask
1473cc2d1573SEaston Man  update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1474cc2d1573SEaston Man    case (valid, offset) => valid && commit_instCommited(offset)
1475cc2d1573SEaston Man  }
1476803124a6SLingrui98  update.jmp_taken := ftbEntryGen.jmp_taken
1477b37e4b45SLingrui98
1478803124a6SLingrui98  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1479803124a6SLingrui98  // update.full_pred.jalr_target := commit_target
1480803124a6SLingrui98  // update.full_pred.hit := true.B
1481803124a6SLingrui98  // when (update.full_pred.is_jalr) {
1482803124a6SLingrui98  //   update.full_pred.targets.last := commit_target
1483803124a6SLingrui98  // }
148409c6f1ddSLingrui98
148509c6f1ddSLingrui98  // ******************************************************************************
148609c6f1ddSLingrui98  // **************************** commit perf counters ****************************
148709c6f1ddSLingrui98  // ******************************************************************************
148809c6f1ddSLingrui98
148991346769SMuzi  val commit_inst_mask        = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt
149009c6f1ddSLingrui98  val commit_mispred_mask     = commit_mispredict.asUInt
149109c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
149209c6f1ddSLingrui98
149309c6f1ddSLingrui98  val commit_br_mask  = commit_pd.brMask.asUInt
149409c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1495*cf7d6b7aSMuzi  val commit_cfi_mask = commit_br_mask | commit_jmp_mask
149609c6f1ddSLingrui98
149709c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
149809c6f1ddSLingrui98
149909c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
150009c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
150109c6f1ddSLingrui98
150209c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
150309c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
150409c6f1ddSLingrui98
1505b92f8445Sssszwic  val hartId           = p(XSCoreParamsKey).HartId
1506c686adcdSYinan Xu  val isWriteFTQTable  = Constantin.createRecord(s"isWriteFTQTable$hartId")
1507c686adcdSYinan Xu  val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle)
150809c6f1ddSLingrui98  // Cfi Info
150909c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
151009c6f1ddSLingrui98    val pc      = commit_pc_bundle.startAddr + (i * instBytes).U
151191346769SMuzi    val v       = commit_state(i) === c_committed
151209c6f1ddSLingrui98    val isBr    = commit_pd.brMask(i)
151309c6f1ddSLingrui98    val isJmp   = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
151409c6f1ddSLingrui98    val isCfi   = isBr || isJmp
151509c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
151609c6f1ddSLingrui98    val misPred = commit_mispredict(i)
1517c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
1518c2ad24ebSLingrui98    val histPtr   = commit_spec_meta.histPtr
1519deb3a97eSGao-Zeyu    val predCycle = commit_meta(63, 0)
152009c6f1ddSLingrui98    val target    = commit_target
152109c6f1ddSLingrui98
1522*cf7d6b7aSMuzi    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1523*cf7d6b7aSMuzi      v && offset === i.U
1524*cf7d6b7aSMuzi    })))
1525*cf7d6b7aSMuzi    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1526*cf7d6b7aSMuzi      v && offset === i.U
1527*cf7d6b7aSMuzi    }.reduce(_ || _)
1528*cf7d6b7aSMuzi    val addIntoHist =
1529*cf7d6b7aSMuzi      ((commit_hit === h_hit) && inFtbEntry) || (!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)
1530*cf7d6b7aSMuzi    XSDebug(
1531*cf7d6b7aSMuzi      v && do_commit && isCfi,
1532*cf7d6b7aSMuzi      p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1533c2ad24ebSLingrui98        p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
153409c6f1ddSLingrui98        p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1535*cf7d6b7aSMuzi        p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n"
1536*cf7d6b7aSMuzi    )
153751532d8bSGuokai Chen
153851532d8bSGuokai Chen    val logbundle = Wire(new FtqDebugBundle)
153951532d8bSGuokai Chen    logbundle.pc        := pc
154051532d8bSGuokai Chen    logbundle.target    := target
154151532d8bSGuokai Chen    logbundle.isBr      := isBr
154251532d8bSGuokai Chen    logbundle.isJmp     := isJmp
154351532d8bSGuokai Chen    logbundle.isCall    := isJmp && commit_pd.hasCall
154451532d8bSGuokai Chen    logbundle.isRet     := isJmp && commit_pd.hasRet
154551532d8bSGuokai Chen    logbundle.misPred   := misPred
154651532d8bSGuokai Chen    logbundle.isTaken   := isTaken
154751532d8bSGuokai Chen    logbundle.predStage := commit_stage
154851532d8bSGuokai Chen
154951532d8bSGuokai Chen    ftqBranchTraceDB.log(
155051532d8bSGuokai Chen      data = logbundle /* hardware of type T */,
1551da3bf434SMaxpicca-Li      en = isWriteFTQTable.orR && v && do_commit && isCfi,
155251532d8bSGuokai Chen      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
155351532d8bSGuokai Chen      clock = clock,
155451532d8bSGuokai Chen      reset = reset
155551532d8bSGuokai Chen    )
155609c6f1ddSLingrui98  }
155709c6f1ddSLingrui98
155809c6f1ddSLingrui98  val enq           = io.fromBpu.resp
15592e1be6e1SSteve Gou  val perf_redirect = backendRedirect
156009c6f1ddSLingrui98
156109c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
156209c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
156309c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
156409c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
156509c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
156609c6f1ddSLingrui98
156709c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
156809c6f1ddSLingrui98
156909c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
157009c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
157112cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1572*cf7d6b7aSMuzi  XSPerfAccumulate(
1573*cf7d6b7aSMuzi    "bpu_to_ifu_bubble_when_ftq_full",
1574*cf7d6b7aSMuzi    (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready
1575*cf7d6b7aSMuzi  )
157609c6f1ddSLingrui98
1577bace178aSGao-Zeyu  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_ | _))
15789342624fSGao-Zeyu  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
15799342624fSGao-Zeyu  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
15809342624fSGao-Zeyu
158109c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
158209c6f1ddSLingrui98  val to_ifu   = io.toIfu.req.bits
158309c6f1ddSLingrui98
1584209a4cafSSteve Gou  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth + 1, 1)
158509c6f1ddSLingrui98
158609c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
158709c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
158809c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
158909c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
159009c6f1ddSLingrui98
159109c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
159209c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
159309c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
159409c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
159509c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
159609c6f1ddSLingrui98
159709c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
159809c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
159909c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
160009c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
160109c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
160209c6f1ddSLingrui98
16031d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
16041d7e5011SLingrui98
1605*cf7d6b7aSMuzi  def pred_stage_map(src: UInt, name: String) =
16061d7e5011SLingrui98    (0 until numBpStages).map(i =>
16071d7e5011SLingrui98      f"${name}_stage_${i + 1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
16081d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_ + _)
16091d7e5011SLingrui98
16101d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs, "mispredict")
16111d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
16121d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
16131d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights, "correct")
16141d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
16151d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
16161d7e5011SLingrui98
161709c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
161809c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
161909c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
162065fddcf0Szoujr  // assert(!ftb_false_hit)
162109c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
162209c6f1ddSLingrui98
162309c6f1ddSLingrui98  val ftb_new_entry                = u(ftbEntryGen.is_init_entry)
1624b37e4b45SLingrui98  val ftb_new_entry_only_br        = ftb_new_entry && !update_ftb_entry.jmpValid
1625b37e4b45SLingrui98  val ftb_new_entry_only_jmp       = ftb_new_entry && !update_ftb_entry.brValids(0)
1626b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
162709c6f1ddSLingrui98
162809c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
162909c6f1ddSLingrui98
1630*cf7d6b7aSMuzi  val ftb_modified_entry =
1631*cf7d6b7aSMuzi    u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
163209c6f1ddSLingrui98  val ftb_modified_entry_new_br               = u(ftbEntryGen.is_new_br)
1633d2b20d1aSTang Haojin  val ftb_modified_entry_ifu_redirected       = u(ifuRedirected(do_commit_ptr.value))
163409c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
163509c6f1ddSLingrui98  val ftb_modified_entry_br_full              = ftb_modified_entry && ftbEntryGen.is_br_full
163609c6f1ddSLingrui98  val ftb_modified_entry_always_taken         = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
163709c6f1ddSLingrui98
1638209a4cafSSteve Gou  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1639209a4cafSSteve Gou  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1640209a4cafSSteve Gou  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth + 1, 1)
1641209a4cafSSteve Gou  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth + 1, 1)
1642209a4cafSSteve Gou  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1643209a4cafSSteve Gou  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth + 1, 1)
164409c6f1ddSLingrui98
1645209a4cafSSteve Gou  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize + 1, 1)
164609c6f1ddSLingrui98
164709c6f1ddSLingrui98  val perfCountsMap = Map(
164809c6f1ddSLingrui98    "BpInstr"                         -> PopCount(mbpInstrs),
164909c6f1ddSLingrui98    "BpBInstr"                        -> PopCount(mbpBRights | mbpBWrongs),
165009c6f1ddSLingrui98    "BpRight"                         -> PopCount(mbpRights),
165109c6f1ddSLingrui98    "BpWrong"                         -> PopCount(mbpWrongs),
165209c6f1ddSLingrui98    "BpBRight"                        -> PopCount(mbpBRights),
165309c6f1ddSLingrui98    "BpBWrong"                        -> PopCount(mbpBWrongs),
165409c6f1ddSLingrui98    "BpJRight"                        -> PopCount(mbpJRights),
165509c6f1ddSLingrui98    "BpJWrong"                        -> PopCount(mbpJWrongs),
165609c6f1ddSLingrui98    "BpIRight"                        -> PopCount(mbpIRights),
165709c6f1ddSLingrui98    "BpIWrong"                        -> PopCount(mbpIWrongs),
165809c6f1ddSLingrui98    "BpCRight"                        -> PopCount(mbpCRights),
165909c6f1ddSLingrui98    "BpCWrong"                        -> PopCount(mbpCWrongs),
166009c6f1ddSLingrui98    "BpRRight"                        -> PopCount(mbpRRights),
166109c6f1ddSLingrui98    "BpRWrong"                        -> PopCount(mbpRWrongs),
166209c6f1ddSLingrui98    "ftb_false_hit"                   -> PopCount(ftb_false_hit),
166309c6f1ddSLingrui98    "ftb_hit"                         -> PopCount(ftb_hit),
166409c6f1ddSLingrui98    "ftb_new_entry"                   -> PopCount(ftb_new_entry),
166509c6f1ddSLingrui98    "ftb_new_entry_only_br"           -> PopCount(ftb_new_entry_only_br),
166609c6f1ddSLingrui98    "ftb_new_entry_only_jmp"          -> PopCount(ftb_new_entry_only_jmp),
166709c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp"    -> PopCount(ftb_new_entry_has_br_and_jmp),
166809c6f1ddSLingrui98    "ftb_old_entry"                   -> PopCount(ftb_old_entry),
166909c6f1ddSLingrui98    "ftb_modified_entry"              -> PopCount(ftb_modified_entry),
167009c6f1ddSLingrui98    "ftb_modified_entry_new_br"       -> PopCount(ftb_modified_entry_new_br),
167109c6f1ddSLingrui98    "ftb_jalr_target_modified"        -> PopCount(ftb_modified_entry_jalr_target_modified),
167209c6f1ddSLingrui98    "ftb_modified_entry_br_full"      -> PopCount(ftb_modified_entry_br_full),
167309c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1674209a4cafSSteve Gou  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
16751d7e5011SLingrui98    correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
167609c6f1ddSLingrui98
167709c6f1ddSLingrui98  for ((key, value) <- perfCountsMap) {
167809c6f1ddSLingrui98    XSPerfAccumulate(key, value)
167909c6f1ddSLingrui98  }
168009c6f1ddSLingrui98
168109c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
168209c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
168309c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
168409c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
168509c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1686*cf7d6b7aSMuzi  XSDebug(
1687*cf7d6b7aSMuzi    true.B,
1688*cf7d6b7aSMuzi    p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1689*cf7d6b7aSMuzi      p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n"
1690*cf7d6b7aSMuzi  )
169109c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
169209c6f1ddSLingrui98
169309c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
169409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
169509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
169609c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
169709c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
169809c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
169909c6f1ddSLingrui98  //           !taken),
170009c6f1ddSLingrui98  //         !taken),
170109c6f1ddSLingrui98  //       false.B)
170209c6f1ddSLingrui98  //     }
170309c6f1ddSLingrui98  //   }
170409c6f1ddSLingrui98
170509c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
170609c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
170709c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
170809c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
170909c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
171009c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
171109c6f1ddSLingrui98  //           !taken),
171209c6f1ddSLingrui98  //         !taken),
171309c6f1ddSLingrui98  //       false.B)
171409c6f1ddSLingrui98  //     }
171509c6f1ddSLingrui98  //   }
171609c6f1ddSLingrui98
171709c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
171809c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
171909c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
172009c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
172109c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
172209c6f1ddSLingrui98  //       false.B)
172309c6f1ddSLingrui98  //     }
172409c6f1ddSLingrui98  //   }
172509c6f1ddSLingrui98
172609c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
172709c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
172809c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
172909c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
173009c6f1ddSLingrui98  //         isWrong ^ (!taken),
173109c6f1ddSLingrui98  //           false.B)
173209c6f1ddSLingrui98  //     }
173309c6f1ddSLingrui98  //   }
173409c6f1ddSLingrui98
173509c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
173609c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
173709c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
173809c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
173909c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
174009c6f1ddSLingrui98  //           false.B)
174109c6f1ddSLingrui98  //     }
174209c6f1ddSLingrui98  //   }
174309c6f1ddSLingrui98
174409c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
174509c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
174609c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
174709c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
174809c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
174909c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
175009c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
175109c6f1ddSLingrui98
175209c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
175309c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
175409c6f1ddSLingrui98
175509c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
175609c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
17571ca0e4f3SYinan Xu
1758cd365d4cSrvcoresjw  val perfEvents = Seq(
1759cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect),
1760cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect),
1761cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready),
1762cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1763cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)),
1764cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid),
1765cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid),
1766cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn),
1767cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)),
1768cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)),
1769cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)),
1770cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)),
1771cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)),
1772cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)),
1773cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)),
1774cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)),
1775cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)),
1776cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)),
1777cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)),
1778cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)),
1779cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)),
1780cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)),
1781cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)),
1782*cf7d6b7aSMuzi    ("ftb_hit                ", PopCount(ftb_hit))
1783cd365d4cSrvcoresjw  )
17841ca0e4f3SYinan Xu  generatePerfEvent()
178509c6f1ddSLingrui98}
1786