xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision dcf4211fdfa7d9d8d407df645ca54eaf823b7c9c)
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._
21cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
223c02ee8fSwakafaimport utility._
23cf7d6b7aSMuziimport utility.ChiselDB
24cf7d6b7aSMuziimport utils._
2509c6f1ddSLingrui98import xiangshan._
261ca0e4f3SYinan Xuimport xiangshan.backend.CtrlToFtqIO
272e1be6e1SSteve Gouimport xiangshan.backend.decode.ImmUnion
28cf7d6b7aSMuziimport 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  }
55cf7d6b7aSMuzi  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)
91cf7d6b7aSMuzi    Cat(
92cf7d6b7aSMuzi      getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth) + instOffsetBits), nextLineAddr, startAddr)),
93cf7d6b7aSMuzi      getOffset(startAddr) + offset,
94cf7d6b7aSMuzi      0.U(instOffsetBits.W)
95cf7d6b7aSMuzi    )
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  }
107cf7d6b7aSMuzi  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
126cf7d6b7aSMuzi    this.jmpInfo.bits := ParallelPriorityMux(
127cf7d6b7aSMuzi      pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
128cf7d6b7aSMuzi      pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))
129cf7d6b7aSMuzi    )
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)
193cf7d6b7aSMuzi  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())
253*dcf4211fSYuandongliang    val is_strong_bias_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)
287*dcf4211fSYuandongliang    init_entry.strong_bias(0) := true.B // set to strong bias 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)
295*dcf4211fSYuandongliang    init_entry.strong_bias(numBr - 1) := new_jmp_is_jalr // set strong bias for the jalr on init
296eeb5ff92SLingrui98  }
297eeb5ff92SLingrui98
29809c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
299a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
300a60a2901SLingrui98  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos - instOffsetBits), true.B)
30109c6f1ddSLingrui98  init_entry.isJalr  := new_jmp_is_jalr
30209c6f1ddSLingrui98  init_entry.isCall  := new_jmp_is_call
30309c6f1ddSLingrui98  init_entry.isRet   := new_jmp_is_ret
304f4ebc4b2SLingrui98  // that means fall thru points to the middle of an inst
305ae409b75SSteve Gou  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask(pd.jmpOffset)
30609c6f1ddSLingrui98
30709c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
30809c6f1ddSLingrui98  val oe              = io.old_entry
309eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
31009c6f1ddSLingrui98  val br_recorded     = br_recorded_vec.asUInt.orR
31109c6f1ddSLingrui98  val is_new_br       = cfi_is_br && !br_recorded
31209c6f1ddSLingrui98  val new_br_offset   = io.cfiIndex.bits
31309c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
314eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
31509c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map {
316cf7d6b7aSMuzi    i =>
317cf7d6b7aSMuzi      i match {
318eeb5ff92SLingrui98        case 0 =>
319eeb5ff92SLingrui98          !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
320eeb5ff92SLingrui98        case idx =>
321eeb5ff92SLingrui98          allBrSlotsVec(idx - 1).valid && new_br_offset > allBrSlotsVec(idx - 1).offset &&
322eeb5ff92SLingrui98          (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
32309c6f1ddSLingrui98      }
32409c6f1ddSLingrui98  })
32509c6f1ddSLingrui98
32609c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
32709c6f1ddSLingrui98  for (i <- 0 until numBr) {
328eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
329eeb5ff92SLingrui98    when(new_br_insert_onehot(i)) {
330eeb5ff92SLingrui98      slot.valid  := true.B
331eeb5ff92SLingrui98      slot.offset := new_br_offset
332b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr - 1)
333*dcf4211fSYuandongliang      old_entry_modified.strong_bias(i) := true.B
334eeb5ff92SLingrui98    }.elsewhen(new_br_offset > oe.allSlotsForBr(i).offset) {
335*dcf4211fSYuandongliang      old_entry_modified.strong_bias(i) := false.B
336eeb5ff92SLingrui98      // all other fields remain unchanged
337eeb5ff92SLingrui98    }.otherwise {
338eeb5ff92SLingrui98      // case i == 0, remain unchanged
339eeb5ff92SLingrui98      if (i != 0) {
340b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr - 1).B && !oe.brSlots.last.valid
341eeb5ff92SLingrui98        when(!noNeedToMoveFromFormerSlot) {
342eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i - 1))
343*dcf4211fSYuandongliang          old_entry_modified.strong_bias(i) := oe.strong_bias(i)
34409c6f1ddSLingrui98        }
345eeb5ff92SLingrui98      }
346eeb5ff92SLingrui98    }
347eeb5ff92SLingrui98  }
34809c6f1ddSLingrui98
349eeb5ff92SLingrui98  // two circumstances:
350eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
351eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
352eeb5ff92SLingrui98  //        the previous last br or the new br
353eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
354eeb5ff92SLingrui98  val pft_need_to_change  = is_new_br && may_have_to_replace
35509c6f1ddSLingrui98  // it should either be the given last br or the new br
35609c6f1ddSLingrui98  when(pft_need_to_change) {
357eeb5ff92SLingrui98    val new_pft_offset =
358cf7d6b7aSMuzi      Mux(!new_br_insert_onehot.asUInt.orR, new_br_offset, oe.allSlotsForBr.last.offset)
359eeb5ff92SLingrui98
360710a8720SLingrui98    // set jmp to invalid
36109c6f1ddSLingrui98    old_entry_modified.pftAddr              := getLower(io.start_addr) + new_pft_offset
36209c6f1ddSLingrui98    old_entry_modified.carry                := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
363f4ebc4b2SLingrui98    old_entry_modified.last_may_be_rvi_call := false.B
36409c6f1ddSLingrui98    old_entry_modified.isCall               := false.B
36509c6f1ddSLingrui98    old_entry_modified.isRet                := false.B
366eeb5ff92SLingrui98    old_entry_modified.isJalr               := false.B
36709c6f1ddSLingrui98  }
36809c6f1ddSLingrui98
36909c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
370710a8720SLingrui98  val old_target      = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
371b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
372eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3733bcae573SLingrui98  when(jalr_target_modified) {
37409c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
375*dcf4211fSYuandongliang    old_entry_jmp_target_modified.strong_bias := 0.U.asTypeOf(Vec(numBr, Bool()))
37609c6f1ddSLingrui98  }
37709c6f1ddSLingrui98
378*dcf4211fSYuandongliang  val old_entry_strong_bias    = WireInit(oe)
379*dcf4211fSYuandongliang  val strong_bias_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
38009c6f1ddSLingrui98  for (i <- 0 until numBr) {
381*dcf4211fSYuandongliang    when(br_recorded_vec(0)) {
382*dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(0) :=
383*dcf4211fSYuandongliang        oe.strong_bias(0) && io.cfiIndex.valid && oe.brValids(0) && io.cfiIndex.bits === oe.brOffset(0)
384*dcf4211fSYuandongliang    }.elsewhen(br_recorded_vec(numBr - 1)) {
385*dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(0) := false.B
386*dcf4211fSYuandongliang      old_entry_strong_bias.strong_bias(numBr - 1) :=
387*dcf4211fSYuandongliang        oe.strong_bias(numBr - 1) && io.cfiIndex.valid && oe.brValids(numBr - 1) && io.cfiIndex.bits === oe.brOffset(
388*dcf4211fSYuandongliang          numBr - 1
389*dcf4211fSYuandongliang        )
39009c6f1ddSLingrui98    }
391*dcf4211fSYuandongliang    strong_bias_modified_vec(i) := oe.strong_bias(i) && oe.brValids(i) && !old_entry_strong_bias.strong_bias(i)
392*dcf4211fSYuandongliang  }
393*dcf4211fSYuandongliang  val strong_bias_modified = strong_bias_modified_vec.reduce(_ || _)
39409c6f1ddSLingrui98
39509c6f1ddSLingrui98  val derived_from_old_entry =
396*dcf4211fSYuandongliang    Mux(is_new_br, old_entry_modified, Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_strong_bias))
39709c6f1ddSLingrui98
39809c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
39909c6f1ddSLingrui98
40009c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
40109c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map {
40209c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
40309c6f1ddSLingrui98  })
404803124a6SLingrui98  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
40509c6f1ddSLingrui98  for (i <- 0 until numBr) {
40609c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
40709c6f1ddSLingrui98  }
40809c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
40909c6f1ddSLingrui98
41009c6f1ddSLingrui98  // for perf counters
41109c6f1ddSLingrui98  io.is_init_entry           := !hit
412*dcf4211fSYuandongliang  io.is_old_entry            := hit && !is_new_br && !jalr_target_modified && !strong_bias_modified
41309c6f1ddSLingrui98  io.is_new_br               := hit && is_new_br
4143bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
415*dcf4211fSYuandongliang  io.is_strong_bias_modified := hit && strong_bias_modified
416eeb5ff92SLingrui98  io.is_br_full              := hit && is_new_br && may_have_to_replace
41709c6f1ddSLingrui98}
41809c6f1ddSLingrui98
419c5c5edaeSJeniusclass FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
420c5c5edaeSJenius  val io = IO(new Bundle {
421c5c5edaeSJenius    val ifuPtr_w           = Input(new FtqPtr)
422c5c5edaeSJenius    val ifuPtrPlus1_w      = Input(new FtqPtr)
4236bf9b30dSLingrui98    val ifuPtrPlus2_w      = Input(new FtqPtr)
424b92f8445Sssszwic    val pfPtr_w            = Input(new FtqPtr)
425b92f8445Sssszwic    val pfPtrPlus1_w       = Input(new FtqPtr)
426c5c5edaeSJenius    val commPtr_w          = Input(new FtqPtr)
4276bf9b30dSLingrui98    val commPtrPlus1_w     = Input(new FtqPtr)
428c5c5edaeSJenius    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
429c5c5edaeSJenius    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
4306bf9b30dSLingrui98    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
431b92f8445Sssszwic    val pfPtr_rdata        = Output(new Ftq_RF_Components)
432b92f8445Sssszwic    val pfPtrPlus1_rdata   = Output(new Ftq_RF_Components)
433c5c5edaeSJenius    val commPtr_rdata      = Output(new Ftq_RF_Components)
4346bf9b30dSLingrui98    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
435c5c5edaeSJenius
436c5c5edaeSJenius    val wen   = Input(Bool())
437c5c5edaeSJenius    val waddr = Input(UInt(log2Ceil(FtqSize).W))
438c5c5edaeSJenius    val wdata = Input(new Ftq_RF_Components)
439c5c5edaeSJenius  })
440c5c5edaeSJenius
4416bf9b30dSLingrui98  val num_pc_read = numOtherReads + 5
442cf7d6b7aSMuzi  val mem         = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, num_pc_read, 1, "FtqPC"))
443c5c5edaeSJenius  mem.io.wen(0)   := io.wen
444c5c5edaeSJenius  mem.io.waddr(0) := io.waddr
445c5c5edaeSJenius  mem.io.wdata(0) := io.wdata
446c5c5edaeSJenius
4476bf9b30dSLingrui98  // read one cycle ahead for ftq local reads
448cf7d6b7aSMuzi  val raddr_vec = VecInit(Seq(
449cf7d6b7aSMuzi    io.ifuPtr_w.value,
450cf7d6b7aSMuzi    io.ifuPtrPlus1_w.value,
451cf7d6b7aSMuzi    io.ifuPtrPlus2_w.value,
452cf7d6b7aSMuzi    io.pfPtr_w.value,
453cf7d6b7aSMuzi    io.pfPtrPlus1_w.value,
454cf7d6b7aSMuzi    io.commPtrPlus1_w.value,
455cf7d6b7aSMuzi    io.commPtr_w.value
456cf7d6b7aSMuzi  ))
457c5c5edaeSJenius
458c5c5edaeSJenius  mem.io.raddr := raddr_vec
459c5c5edaeSJenius
460b92f8445Sssszwic  io.ifuPtr_rdata       := mem.io.rdata.dropRight(6).last
461b92f8445Sssszwic  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(5).last
462b92f8445Sssszwic  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(4).last
463b92f8445Sssszwic  io.pfPtr_rdata        := mem.io.rdata.dropRight(3).last
464b92f8445Sssszwic  io.pfPtrPlus1_rdata   := mem.io.rdata.dropRight(2).last
4656bf9b30dSLingrui98  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
466c5c5edaeSJenius  io.commPtr_rdata      := mem.io.rdata.last
467c5c5edaeSJenius}
468c5c5edaeSJenius
46909c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
470e30430c2SJay    with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
471e30430c2SJay    with HasICacheParameters {
47209c6f1ddSLingrui98  val io = IO(new Bundle {
47309c6f1ddSLingrui98    val fromBpu     = Flipped(new BpuToFtqIO)
47409c6f1ddSLingrui98    val fromIfu     = Flipped(new IfuToFtqIO)
47509c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
47609c6f1ddSLingrui98
47709c6f1ddSLingrui98    val toBpu       = new FtqToBpuIO
47809c6f1ddSLingrui98    val toIfu       = new FtqToIfuIO
479c5c5edaeSJenius    val toICache    = new FtqToICacheIO
48009c6f1ddSLingrui98    val toBackend   = new FtqToCtrlIO
481b92f8445Sssszwic    val toPrefetch  = new FtqToPrefetchIO
482b92f8445Sssszwic    val icacheFlush = Output(Bool())
4837052722fSJay
48409c6f1ddSLingrui98    val bpuInfo = new Bundle {
48509c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
48609c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
48709c6f1ddSLingrui98    }
4881d1e6d4dSJenius
4891d1e6d4dSJenius    val mmioCommitRead = Flipped(new mmioCommitRead)
490d2b20d1aSTang Haojin
491d2b20d1aSTang Haojin    // for perf
492d2b20d1aSTang Haojin    val ControlBTBMissBubble = Output(Bool())
493d2b20d1aSTang Haojin    val TAGEMissBubble       = Output(Bool())
494d2b20d1aSTang Haojin    val SCMissBubble         = Output(Bool())
495d2b20d1aSTang Haojin    val ITTAGEMissBubble     = Output(Bool())
496d2b20d1aSTang Haojin    val RASMissBubble        = Output(Bool())
49709c6f1ddSLingrui98  })
49809c6f1ddSLingrui98  io.bpuInfo := DontCare
49909c6f1ddSLingrui98
500d2b20d1aSTang Haojin  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
501d2b20d1aSTang Haojin  // only driven by clock, not valid-ready
502d2b20d1aSTang Haojin  topdown_stage                  := io.fromBpu.resp.bits.topdown_info
503d2b20d1aSTang Haojin  io.toIfu.req.bits.topdown_info := topdown_stage
504d2b20d1aSTang Haojin
505d2b20d1aSTang Haojin  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
506d2b20d1aSTang Haojin
50742dddaceSXuan Hu  // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception
50842dddaceSXuan Hu  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju
50942dddaceSXuan Hu  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0)
510bace178aSGao-Zeyu
511bace178aSGao-Zeyu  val aheadValid         = ftqIdxAhead.map(_.valid).reduce(_ | _) && !io.fromBackend.redirect.valid
512bace178aSGao-Zeyu  val realAhdValid       = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
513d2b20d1aSTang Haojin  val backendRedirect    = Wire(Valid(new BranchPredictionRedirect))
5141c6fc24aSEaston Man  val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect))
5151c6fc24aSEaston Man  backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid))
5161c6fc24aSEaston Man  backendRedirectReg.bits  := RegEnable(backendRedirect.bits, backendRedirect.valid)
517bace178aSGao-Zeyu  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
518bace178aSGao-Zeyu  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
51909c6f1ddSLingrui98
520df5b4b8eSYinan Xu  val stage2Flush  = backendRedirect.valid
52109c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
52209c6f1ddSLingrui98  val ifuFlush     = Wire(Bool())
52309c6f1ddSLingrui98
52409c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
52509c6f1ddSLingrui98
52609c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
52709c6f1ddSLingrui98  val flushToIfu             = !allowToIfu
528bace178aSGao-Zeyu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
529bace178aSGao-Zeyu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
53009c6f1ddSLingrui98
531f56177cbSJenius  def copyNum                                              = 5
532b92f8445Sssszwic  val bpuPtr, ifuPtr, pfPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U))
533c9bc5480SLingrui98  val ifuPtrPlus1                                          = RegInit(FtqPtr(false.B, 1.U))
5346bf9b30dSLingrui98  val ifuPtrPlus2                                          = RegInit(FtqPtr(false.B, 2.U))
535b92f8445Sssszwic  val pfPtrPlus1                                           = RegInit(FtqPtr(false.B, 1.U))
5366bf9b30dSLingrui98  val commPtrPlus1                                         = RegInit(FtqPtr(false.B, 1.U))
537f56177cbSJenius  val copied_ifu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
538dc270d3bSJenius  val copied_bpu_ptr                                       = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
5396bf9b30dSLingrui98  require(FtqSize >= 4)
540c5c5edaeSJenius  val ifuPtr_write       = WireInit(ifuPtr)
541c5c5edaeSJenius  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
5426bf9b30dSLingrui98  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
543b92f8445Sssszwic  val pfPtr_write        = WireInit(pfPtr)
544b92f8445Sssszwic  val pfPtrPlus1_write   = WireInit(pfPtrPlus1)
545c5c5edaeSJenius  val ifuWbPtr_write     = WireInit(ifuWbPtr)
546c5c5edaeSJenius  val commPtr_write      = WireInit(commPtr)
5476bf9b30dSLingrui98  val commPtrPlus1_write = WireInit(commPtrPlus1)
54889cc69c1STang Haojin  val robCommPtr_write   = WireInit(robCommPtr)
549c5c5edaeSJenius  ifuPtr       := ifuPtr_write
550c5c5edaeSJenius  ifuPtrPlus1  := ifuPtrPlus1_write
5516bf9b30dSLingrui98  ifuPtrPlus2  := ifuPtrPlus2_write
552b92f8445Sssszwic  pfPtr        := pfPtr_write
553b92f8445Sssszwic  pfPtrPlus1   := pfPtrPlus1_write
554c5c5edaeSJenius  ifuWbPtr     := ifuWbPtr_write
555c5c5edaeSJenius  commPtr      := commPtr_write
556f83ef67eSLingrui98  commPtrPlus1 := commPtrPlus1_write
557f56177cbSJenius  copied_ifu_ptr.map { ptr =>
558f56177cbSJenius    ptr := ifuPtr_write
559f56177cbSJenius    dontTouch(ptr)
560f56177cbSJenius  }
56189cc69c1STang Haojin  robCommPtr := robCommPtr_write
56209c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
56343aca6c2SGuokai Chen  val canCommit    = Wire(Bool())
56409c6f1ddSLingrui98
565c1b28b66STang Haojin  // Instruction page fault and instruction access fault are sent from backend with redirect requests.
566c1b28b66STang Haojin  // When IPF and IAF are sent, backendPcFaultIfuPtr points to the FTQ entry whose first instruction
567c1b28b66STang Haojin  // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write.
568c1b28b66STang Haojin  // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this
569c1b28b66STang Haojin  // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests.
570c1b28b66STang Haojin  val backendIpf        = RegInit(false.B)
571c1b28b66STang Haojin  val backendIgpf       = RegInit(false.B)
572c1b28b66STang Haojin  val backendIaf        = RegInit(false.B)
573c1b28b66STang Haojin  val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U))
574c1b28b66STang Haojin  when(fromBackendRedirect.valid) {
575c1b28b66STang Haojin    backendIpf  := fromBackendRedirect.bits.cfiUpdate.backendIPF
576c1b28b66STang Haojin    backendIgpf := fromBackendRedirect.bits.cfiUpdate.backendIGPF
577c1b28b66STang Haojin    backendIaf  := fromBackendRedirect.bits.cfiUpdate.backendIAF
578cf7d6b7aSMuzi    when(
579cf7d6b7aSMuzi      fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || fromBackendRedirect.bits.cfiUpdate.backendIAF
580cf7d6b7aSMuzi    ) {
581c1b28b66STang Haojin      backendPcFaultPtr := ifuWbPtr_write
582c1b28b66STang Haojin    }
583c1b28b66STang Haojin  }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) {
584c1b28b66STang Haojin    backendIpf  := false.B
585c1b28b66STang Haojin    backendIgpf := false.B
586c1b28b66STang Haojin    backendIaf  := false.B
587c1b28b66STang Haojin  }
588c1b28b66STang Haojin
58909c6f1ddSLingrui98  // **********************************************************************
59009c6f1ddSLingrui98  // **************************** enq from bpu ****************************
59109c6f1ddSLingrui98  // **********************************************************************
59243aca6c2SGuokai Chen  val new_entry_ready = validEntries < FtqSize.U || canCommit
59309c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
59409c6f1ddSLingrui98
59509c6f1ddSLingrui98  val bpu_s2_resp     = io.fromBpu.resp.bits.s2
596cb4f77ceSLingrui98  val bpu_s3_resp     = io.fromBpu.resp.bits.s3
597adc0b8dfSGuokai Chen  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
598adc0b8dfSGuokai Chen  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
59909c6f1ddSLingrui98
60009c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
601935edac4STang Haojin  val enq_fire    = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
602935edac4STang Haojin  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
60309c6f1ddSLingrui98
604b37e4b45SLingrui98  val bpu_in_resp     = io.fromBpu.resp.bits.selectedResp
605adc0b8dfSGuokai Chen  val bpu_in_stage    = io.fromBpu.resp.bits.selectedRespIdxForFtq
60609c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
60709c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
60809c6f1ddSLingrui98
609b92f8445Sssszwic  // read ports:      pfReq1 + pfReq2 ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
610b92f8445Sssszwic  val ftq_pc_mem = Module(new FtqPcMemWrapper(2))
6116bf9b30dSLingrui98  // resp from uBTB
612c5c5edaeSJenius  ftq_pc_mem.io.wen   := bpu_in_fire
613c5c5edaeSJenius  ftq_pc_mem.io.waddr := bpu_in_resp_idx
614c5c5edaeSJenius  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
61509c6f1ddSLingrui98
61609c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
617cf7d6b7aSMuzi  val ftq_redirect_mem = Module(new SyncDataModuleTemplate(
618cf7d6b7aSMuzi    new Ftq_Redirect_SRAMEntry,
619cf7d6b7aSMuzi    FtqSize,
620cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum + 1,
621cf7d6b7aSMuzi    1,
622cf7d6b7aSMuzi    hasRen = true
623cf7d6b7aSMuzi  ))
62409c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
625deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
626deb3a97eSGao-Zeyu  ftq_redirect_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
627deb3a97eSGao-Zeyu  ftq_redirect_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_spec_info
628deb3a97eSGao-Zeyu  println(f"ftq redirect MEM: entry ${ftq_redirect_mem.io.wdata(0).getWidth} * ${FtqSize} * 3")
62909c6f1ddSLingrui98
63009c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
63109c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
632adc0b8dfSGuokai Chen  ftq_meta_1r_sram.io.wen             := io.fromBpu.resp.bits.lastStage.valid(3)
63309c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr           := io.fromBpu.resp.bits.lastStage.ftq_idx.value
634c2d1ec7dSLingrui98  ftq_meta_1r_sram.io.wdata.meta      := io.fromBpu.resp.bits.last_stage_meta
635deb3a97eSGao-Zeyu  ftq_meta_1r_sram.io.wdata.ftb_entry := io.fromBpu.resp.bits.last_stage_ftb_entry
63695a47398SGao-Zeyu  //                                                            ifuRedirect + backendRedirect (commit moved to ftq_meta_1r_sram)
637cf7d6b7aSMuzi  val ftb_entry_mem = Module(new SyncDataModuleTemplate(
638cf7d6b7aSMuzi    new FTBEntry_FtqMem,
639cf7d6b7aSMuzi    FtqSize,
640cf7d6b7aSMuzi    IfuRedirectNum + FtqRedirectAheadNum,
641cf7d6b7aSMuzi    1,
642cf7d6b7aSMuzi    hasRen = true
643cf7d6b7aSMuzi  ))
644adc0b8dfSGuokai Chen  ftb_entry_mem.io.wen(0)   := io.fromBpu.resp.bits.lastStage.valid(3)
64509c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
646c2d1ec7dSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
64709c6f1ddSLingrui98
64809c6f1ddSLingrui98  // multi-write
649b0ed7239SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
6506bf9b30dSLingrui98  val newest_entry_target          = Reg(UInt(VAddrBits.W))
6511c6fc24aSEaston Man  val newest_entry_target_modified = RegInit(false.B)
6526bf9b30dSLingrui98  val newest_entry_ptr             = Reg(new FtqPtr)
6531c6fc24aSEaston Man  val newest_entry_ptr_modified    = RegInit(false.B)
65409c6f1ddSLingrui98  val cfiIndex_vec                 = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
65509c6f1ddSLingrui98  val mispredict_vec               = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
65609c6f1ddSLingrui98  val pred_stage                   = Reg(Vec(FtqSize, UInt(2.W)))
657209a4cafSSteve Gou  val pred_s1_cycle                = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
65809c6f1ddSLingrui98
65991346769SMuzi  val c_empty :: c_toCommit :: c_committed :: c_flushed :: Nil = Enum(4)
6601c6fc24aSEaston Man  val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) {
66191346769SMuzi    VecInit(Seq.fill(PredictWidth)(c_empty))
66209c6f1ddSLingrui98  }))
6631c6fc24aSEaston Man  val commitStateQueueEnable = WireInit(VecInit(Seq.fill(FtqSize)(false.B)))
6641c6fc24aSEaston Man  val commitStateQueueNext   = WireInit(commitStateQueueReg)
6651c6fc24aSEaston Man
6661c6fc24aSEaston Man  for (f <- 0 until FtqSize) {
6671c6fc24aSEaston Man    when(commitStateQueueEnable(f)) {
6681c6fc24aSEaston Man      commitStateQueueReg(f) := commitStateQueueNext(f)
6691c6fc24aSEaston Man    }
6701c6fc24aSEaston Man  }
67109c6f1ddSLingrui98
67209c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
67309c6f1ddSLingrui98  val entry_fetch_status         = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
67409c6f1ddSLingrui98
67509c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
67609c6f1ddSLingrui98  val entry_hit_status                         = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
67709c6f1ddSLingrui98
678f63797a4SLingrui98  // modify registers one cycle later to cut critical path
679f63797a4SLingrui98  val last_cycle_bpu_in       = RegNext(bpu_in_fire)
6801c6fc24aSEaston Man  val last_cycle_bpu_in_ptr   = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
6816bf9b30dSLingrui98  val last_cycle_bpu_in_idx   = last_cycle_bpu_in_ptr.value
6821c6fc24aSEaston Man  val last_cycle_bpu_target   = RegEnable(bpu_in_resp.getTarget(3), bpu_in_fire)
6831c6fc24aSEaston Man  val last_cycle_cfiIndex     = RegEnable(bpu_in_resp.cfiIndex(3), bpu_in_fire)
6841c6fc24aSEaston Man  val last_cycle_bpu_in_stage = RegEnable(bpu_in_stage, bpu_in_fire)
685f56177cbSJenius
6867be982afSLingrui98  def extra_copyNum_for_commitStateQueue = 2
6871c6fc24aSEaston Man  val copied_last_cycle_bpu_in =
6881c6fc24aSEaston Man    VecInit(Seq.fill(copyNum + extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
6891c6fc24aSEaston Man  val copied_last_cycle_bpu_in_ptr_for_ftq =
6901c6fc24aSEaston Man    VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
691f56177cbSJenius
6921c6fc24aSEaston Man  newest_entry_target_modified := false.B
6931c6fc24aSEaston Man  newest_entry_ptr_modified    := false.B
694f63797a4SLingrui98  when(last_cycle_bpu_in) {
695f63797a4SLingrui98    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
696f63797a4SLingrui98    cfiIndex_vec(last_cycle_bpu_in_idx)       := last_cycle_cfiIndex
697f63797a4SLingrui98    pred_stage(last_cycle_bpu_in_idx)         := last_cycle_bpu_in_stage
6986bf9b30dSLingrui98
699b0ed7239SLingrui98    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
7001c6fc24aSEaston Man    newest_entry_target_modified         := true.B
7016bf9b30dSLingrui98    newest_entry_target                  := last_cycle_bpu_target
7021c6fc24aSEaston Man    newest_entry_ptr_modified            := true.B
7036bf9b30dSLingrui98    newest_entry_ptr                     := last_cycle_bpu_in_ptr
70409c6f1ddSLingrui98  }
70509c6f1ddSLingrui98
7067be982afSLingrui98  // reduce fanout by delay write for a cycle
7077be982afSLingrui98  when(RegNext(last_cycle_bpu_in)) {
7081c6fc24aSEaston Man    mispredict_vec(RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)) :=
7091c6fc24aSEaston Man      WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
7107be982afSLingrui98  }
7117be982afSLingrui98
712209a4cafSSteve Gou  // record s1 pred cycles
713cf7d6b7aSMuzi  pred_s1_cycle.map { vec =>
714209a4cafSSteve Gou    when(bpu_in_fire && (bpu_in_stage === BP_S1)) {
715209a4cafSSteve Gou      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
716209a4cafSSteve Gou    }
717cf7d6b7aSMuzi  }
718209a4cafSSteve Gou
7197be982afSLingrui98  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
7207be982afSLingrui98  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
7217be982afSLingrui98  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
7227be982afSLingrui98    case ((in, ptr), i) =>
7237be982afSLingrui98      when(in) {
7247be982afSLingrui98        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
7257be982afSLingrui98        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
7267be982afSLingrui98        for (j <- 0 until perSetEntries) {
7279361b0c5SLingrui98          when(ptr.value === (i * perSetEntries + j).U) {
72891346769SMuzi            commitStateQueueNext(i * perSetEntries + j) := VecInit(Seq.fill(PredictWidth)(c_empty))
7291c6fc24aSEaston Man            // Clock gating optimization, use 1 gate cell to control a row
7301c6fc24aSEaston Man            commitStateQueueEnable(i * perSetEntries + j) := true.B
7317be982afSLingrui98          }
7327be982afSLingrui98        }
7337be982afSLingrui98      }
7349361b0c5SLingrui98  }
7357be982afSLingrui98
73609c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
737dc270d3bSJenius  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
738c9bc5480SLingrui98  when(io.toIfu.req.fire && allowToIfu) {
739c5c5edaeSJenius    ifuPtr_write      := ifuPtrPlus1
7406bf9b30dSLingrui98    ifuPtrPlus1_write := ifuPtrPlus2
7416bf9b30dSLingrui98    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
742c9bc5480SLingrui98  }
743b92f8445Sssszwic  when(io.toPrefetch.req.fire && allowToIfu) {
744b92f8445Sssszwic    pfPtr_write      := pfPtrPlus1
745b92f8445Sssszwic    pfPtrPlus1_write := pfPtrPlus1 + 1.U
746b92f8445Sssszwic  }
74709c6f1ddSLingrui98
74809c6f1ddSLingrui98  // only use ftb result to assign hit status
749adc0b8dfSGuokai Chen  when(bpu_s2_resp.valid(3)) {
750adc0b8dfSGuokai Chen    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
75109c6f1ddSLingrui98  }
75209c6f1ddSLingrui98
7532f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid      := bpu_s2_redirect
75409c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits       := bpu_s2_resp.ftq_idx
755b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.valid := bpu_s2_redirect
756b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s2.bits  := bpu_s2_resp.ftq_idx
757adc0b8dfSGuokai Chen  when(bpu_s2_redirect) {
75809c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
759dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
76009c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
76109c6f1ddSLingrui98    when(!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
762c5c5edaeSJenius      ifuPtr_write      := bpu_s2_resp.ftq_idx
763c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
7646bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
76509c6f1ddSLingrui98    }
766b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s2_resp.ftq_idx)) {
767b92f8445Sssszwic      pfPtr_write      := bpu_s2_resp.ftq_idx
768b92f8445Sssszwic      pfPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
769b92f8445Sssszwic    }
77009c6f1ddSLingrui98  }
77109c6f1ddSLingrui98
772cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid      := bpu_s3_redirect
773cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits       := bpu_s3_resp.ftq_idx
774b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.valid := bpu_s3_redirect
775b92f8445Sssszwic  io.toPrefetch.flushFromBpu.s3.bits  := bpu_s3_resp.ftq_idx
776adc0b8dfSGuokai Chen  when(bpu_s3_redirect) {
777cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
778dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
779cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
780cb4f77ceSLingrui98    when(!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
781c5c5edaeSJenius      ifuPtr_write      := bpu_s3_resp.ftq_idx
782c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
7836bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
784cb4f77ceSLingrui98    }
785b92f8445Sssszwic    when(!isBefore(pfPtr, bpu_s3_resp.ftq_idx)) {
786b92f8445Sssszwic      pfPtr_write      := bpu_s3_resp.ftq_idx
787b92f8445Sssszwic      pfPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
788b92f8445Sssszwic    }
789cb4f77ceSLingrui98  }
790cb4f77ceSLingrui98
79109c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
792b92f8445Sssszwic  XSError(isBefore(bpuPtr, pfPtr) && !isFull(bpuPtr, pfPtr), "\npfPtr is before bpuPtr!\n")
7932448f137SGuokai Chen  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
79409c6f1ddSLingrui98
795cf7d6b7aSMuzi  (0 until copyNum).map(i => XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n"))
796dc270d3bSJenius
79709c6f1ddSLingrui98  // ****************************************************************
79809c6f1ddSLingrui98  // **************************** to ifu ****************************
79909c6f1ddSLingrui98  // ****************************************************************
800f22cf846SJenius  // 0  for ifu, and 1-4 for ICache
801935edac4STang Haojin  val bpu_in_bypass_buf         = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
802935edac4STang Haojin  val copied_bpu_in_bypass_buf  = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
803f56177cbSJenius  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
8041c6fc24aSEaston Man  val bpu_in_bypass_ptr         = RegEnable(bpu_in_resp_ptr, bpu_in_fire)
80509c6f1ddSLingrui98  val last_cycle_to_ifu_fire    = RegNext(io.toIfu.req.fire)
806b92f8445Sssszwic  val last_cycle_to_pf_fire     = RegNext(io.toPrefetch.req.fire)
80709c6f1ddSLingrui98
8081c6fc24aSEaston Man  val copied_bpu_in_bypass_ptr      = VecInit(Seq.fill(copyNum)(RegEnable(bpu_in_resp_ptr, bpu_in_fire)))
809f56177cbSJenius  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
81088bc4f90SLingrui98
81109c6f1ddSLingrui98  // read pc and target
8126bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
8136bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
8146bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
815b92f8445Sssszwic  ftq_pc_mem.io.pfPtr_w        := pfPtr_write
816b92f8445Sssszwic  ftq_pc_mem.io.pfPtrPlus1_w   := pfPtrPlus1_write
8176bf9b30dSLingrui98  ftq_pc_mem.io.commPtr_w      := commPtr_write
8186bf9b30dSLingrui98  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
819c5c5edaeSJenius
8205ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
821f63797a4SLingrui98
822f56177cbSJenius  val toICachePcBundle               = Wire(Vec(copyNum, new Ftq_RF_Components))
823dc270d3bSJenius  val toICacheEntryToSend            = Wire(Vec(copyNum, Bool()))
8243e1dbb17SMuzi  val nextCycleToPrefetchPcBundle    = Wire(new Ftq_RF_Components)
8253e1dbb17SMuzi  val nextCycleToPrefetchEntryToSend = Wire(Bool())
8263e1dbb17SMuzi  val toPrefetchPcBundle             = RegNext(nextCycleToPrefetchPcBundle)
8273e1dbb17SMuzi  val toPrefetchEntryToSend          = RegNext(nextCycleToPrefetchEntryToSend)
828b37e4b45SLingrui98  val toIfuPcBundle                  = Wire(new Ftq_RF_Components)
829f63797a4SLingrui98  val entry_is_to_send               = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
830f63797a4SLingrui98  val entry_ftq_offset               = WireInit(cfiIndex_vec(ifuPtr.value))
8316bf9b30dSLingrui98  val entry_next_addr                = Wire(UInt(VAddrBits.W))
832b004fa13SJenius
833f56177cbSJenius  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
834f56177cbSJenius  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
835b0ed7239SLingrui98  val diff_entry_next_addr   = WireInit(update_target(ifuPtr.value)) // TODO: remove this
836f63797a4SLingrui98
837cf7d6b7aSMuzi  val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(
838cf7d6b7aSMuzi    entry_fetch_status(ifuPtrPlus1.value) === f_to_send
839cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1)))
840cf7d6b7aSMuzi  val copied_ifu_ptr_to_send = VecInit(Seq.fill(copyNum)(RegNext(
841cf7d6b7aSMuzi    entry_fetch_status(ifuPtr.value) === f_to_send
842cf7d6b7aSMuzi  ) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr)))
843dc270d3bSJenius
844f56177cbSJenius  for (i <- 0 until copyNum) {
845f56177cbSJenius    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)) {
846f56177cbSJenius      toICachePcBundle(i)    := copied_bpu_in_bypass_buf(i)
847dc270d3bSJenius      toICacheEntryToSend(i) := true.B
848f56177cbSJenius    }.elsewhen(copied_last_cycle_to_ifu_fire(i)) {
849f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_plus1_rdata(i)
850dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i)
851f56177cbSJenius    }.otherwise {
852f56177cbSJenius      toICachePcBundle(i)    := pc_mem_ifu_ptr_rdata(i)
853dc270d3bSJenius      toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i)
854f56177cbSJenius    }
855f56177cbSJenius  }
856f56177cbSJenius
8573e1dbb17SMuzi  // Calculate requests sent to prefetcher one cycle in advance to cut critical path
8583e1dbb17SMuzi  when(bpu_in_fire && bpu_in_resp_ptr === pfPtr_write) {
8593e1dbb17SMuzi    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.wdata
8603e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := true.B
8613e1dbb17SMuzi  }.elsewhen(io.toPrefetch.req.fire) {
8623e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtrPlus1_rdata
8633e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtrPlus1.value) === f_to_send ||
8643e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtrPlus1
865b92f8445Sssszwic  }.otherwise {
8663e1dbb17SMuzi    nextCycleToPrefetchPcBundle := ftq_pc_mem.io.pfPtr_rdata
8673e1dbb17SMuzi    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtr.value) === f_to_send ||
8683e1dbb17SMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr // reduce potential bubbles
869b92f8445Sssszwic  }
870b92f8445Sssszwic
871873dc383SLingrui98  // TODO: reconsider target address bypass logic
87209c6f1ddSLingrui98  when(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
87388bc4f90SLingrui98    toIfuPcBundle        := bpu_in_bypass_buf_for_ifu
874f678dd91SSteve Gou    entry_is_to_send     := true.B
8756bf9b30dSLingrui98    entry_next_addr      := last_cycle_bpu_target
876f63797a4SLingrui98    entry_ftq_offset     := last_cycle_cfiIndex
877b0ed7239SLingrui98    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
87809c6f1ddSLingrui98  }.elsewhen(last_cycle_to_ifu_fire) {
879c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
880c5c5edaeSJenius    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
881cf7d6b7aSMuzi      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1) // reduce potential bubbles
882cf7d6b7aSMuzi    entry_next_addr := Mux(
883cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
88488bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
885cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))
886cf7d6b7aSMuzi    ) // ifuPtr+2
887c5c5edaeSJenius  }.otherwise {
888c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
88928f2cf58SLingrui98    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
89028f2cf58SLingrui98      RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
891cf7d6b7aSMuzi    entry_next_addr := Mux(
892cf7d6b7aSMuzi      last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtrPlus1,
89388bc4f90SLingrui98      bpu_in_bypass_buf_for_ifu.startAddr,
894cf7d6b7aSMuzi      Mux(ifuPtr === newest_entry_ptr, newest_entry_target, RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))
895cf7d6b7aSMuzi    ) // ifuPtr+1
89609c6f1ddSLingrui98  }
89709c6f1ddSLingrui98
898f678dd91SSteve Gou  io.toIfu.req.valid              := entry_is_to_send && ifuPtr =/= bpuPtr
899f63797a4SLingrui98  io.toIfu.req.bits.nextStartAddr := entry_next_addr
900f63797a4SLingrui98  io.toIfu.req.bits.ftqOffset     := entry_ftq_offset
901b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
902c5c5edaeSJenius
903c5c5edaeSJenius  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
904cf7d6b7aSMuzi  io.toICache.req.bits.readValid.zipWithIndex.map { case (copy, i) =>
905cf7d6b7aSMuzi    copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)
906cf7d6b7aSMuzi  }
907b92f8445Sssszwic  io.toICache.req.bits.pcMemRead.zipWithIndex.foreach { case (copy, i) =>
908b92f8445Sssszwic    copy.fromFtqPcBundle(toICachePcBundle(i))
909b92f8445Sssszwic    copy.ftqIdx := ifuPtr
910b92f8445Sssszwic  }
911c1b28b66STang Haojin  io.toICache.req.bits.backendIpf  := backendIpf && backendPcFaultPtr === ifuPtr
912c1b28b66STang Haojin  io.toICache.req.bits.backendIgpf := backendIgpf && backendPcFaultPtr === ifuPtr
913c1b28b66STang Haojin  io.toICache.req.bits.backendIaf  := backendIaf && backendPcFaultPtr === ifuPtr
914b92f8445Sssszwic
915b92f8445Sssszwic  io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
916b92f8445Sssszwic  io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle)
917b92f8445Sssszwic  io.toPrefetch.req.bits.ftqIdx := pfPtr
918b004fa13SJenius  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
919b004fa13SJenius  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
920b004fa13SJenius  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
921b004fa13SJenius  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
922b004fa13SJenius  // }
923f22cf846SJenius
924b0ed7239SLingrui98  // TODO: remove this
925cf7d6b7aSMuzi  XSError(
926cf7d6b7aSMuzi    io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
927cf7d6b7aSMuzi    p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n"
928cf7d6b7aSMuzi  )
929b0ed7239SLingrui98
93009c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
931b37e4b45SLingrui98  when(toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
93209c6f1ddSLingrui98    when(io.toIfu.req.fire &&
933cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
934cf7d6b7aSMuzi      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) {
93509c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
936352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
93709c6f1ddSLingrui98    }
938cf7d6b7aSMuzi    XSDebug(
939cf7d6b7aSMuzi      true.B,
940cf7d6b7aSMuzi      "fallThruError! start:%x, fallThru:%x\n",
941cf7d6b7aSMuzi      io.toIfu.req.bits.startAddr,
942cf7d6b7aSMuzi      io.toIfu.req.bits.nextStartAddr
943cf7d6b7aSMuzi    )
94409c6f1ddSLingrui98  }
94509c6f1ddSLingrui98
946cf7d6b7aSMuzi  XSPerfAccumulate(
947cf7d6b7aSMuzi    f"fall_through_error_to_ifu",
948cf7d6b7aSMuzi    toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
949cf7d6b7aSMuzi      io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
950cf7d6b7aSMuzi  )
951a60a2901SLingrui98
95209c6f1ddSLingrui98  val ifu_req_should_be_flushed =
953cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
954cb4f77ceSLingrui98      io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
95509c6f1ddSLingrui98
95609c6f1ddSLingrui98  when(io.toIfu.req.fire && !ifu_req_should_be_flushed) {
95709c6f1ddSLingrui98    entry_fetch_status(ifuPtr.value) := f_sent
95809c6f1ddSLingrui98  }
95909c6f1ddSLingrui98
96009c6f1ddSLingrui98  // *********************************************************************
96109c6f1ddSLingrui98  // **************************** wb from ifu ****************************
96209c6f1ddSLingrui98  // *********************************************************************
96309c6f1ddSLingrui98  val pdWb         = io.fromIfu.pdWb
96409c6f1ddSLingrui98  val pds          = pdWb.bits.pd
96509c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
96609c6f1ddSLingrui98  val ifu_wb_idx   = pdWb.bits.ftqIdx.value
96709c6f1ddSLingrui98  // read ports:                                                         commit update
968cf7d6b7aSMuzi  val ftq_pd_mem =
969cf7d6b7aSMuzi    Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum + 1, 1, hasRen = true))
97009c6f1ddSLingrui98  ftq_pd_mem.io.wen(0)   := ifu_wb_valid
97109c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
97209c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
97309c6f1ddSLingrui98
97409c6f1ddSLingrui98  val hit_pd_valid       = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
97509c6f1ddSLingrui98  val hit_pd_mispred     = hit_pd_valid && pdWb.bits.misOffset.valid
97609c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init = false.B)
977005e809bSJiuyang Liu  val pd_reg             = RegEnable(pds, pdWb.valid)
978005e809bSJiuyang Liu  val start_pc_reg       = RegEnable(pdWb.bits.pc(0), pdWb.valid)
979005e809bSJiuyang Liu  val wb_idx_reg         = RegEnable(ifu_wb_idx, pdWb.valid)
98009c6f1ddSLingrui98
98109c6f1ddSLingrui98  when(ifu_wb_valid) {
98209c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map {
98309c6f1ddSLingrui98      case (v, inRange) => v && inRange
98409c6f1ddSLingrui98    })
9851c6fc24aSEaston Man    commitStateQueueEnable(ifu_wb_idx) := true.B
9861c6fc24aSEaston Man    (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map {
9871c6fc24aSEaston Man      case (qe, v) => when(v) {
98891346769SMuzi          qe := c_toCommit
9891c6fc24aSEaston Man        }
99009c6f1ddSLingrui98    }
99109c6f1ddSLingrui98  }
99209c6f1ddSLingrui98
993c5c5edaeSJenius  when(ifu_wb_valid) {
994c5c5edaeSJenius    ifuWbPtr_write := ifuWbPtr + 1.U
995c5c5edaeSJenius  }
99609c6f1ddSLingrui98
997f21bbcb2SGuokai Chen  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
998f21bbcb2SGuokai Chen
9991c6fc24aSEaston Man  ftb_entry_mem.io.ren.get.head := ifu_wb_valid
100009c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head   := ifu_wb_idx
100109c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
100209c6f1ddSLingrui98  when(RegNext(hit_pd_valid)) {
100309c6f1ddSLingrui98    // check for false hit
100409c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
1005eeb5ff92SLingrui98    val brSlots        = pred_ftb_entry.brSlots
1006eeb5ff92SLingrui98    val tailSlot       = pred_ftb_entry.tailSlot
100709c6f1ddSLingrui98    // we check cfis that bpu predicted
100809c6f1ddSLingrui98
1009eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
1010eeb5ff92SLingrui98    val br_false_hit =
1011eeb5ff92SLingrui98      brSlots.map {
1012eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
1013eeb5ff92SLingrui98      }.reduce(_ || _) ||
1014b37e4b45SLingrui98        (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
1015eeb5ff92SLingrui98          !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
1016eeb5ff92SLingrui98
1017eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
101809c6f1ddSLingrui98    val jmp_pd    = pd_reg(jmpOffset)
101909c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
102009c6f1ddSLingrui98      ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) ||
102109c6f1ddSLingrui98        (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
102209c6f1ddSLingrui98        (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
1023cf7d6b7aSMuzi        (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)))
102409c6f1ddSLingrui98
102509c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
102665fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
102765fddcf0Szoujr
1028352db50aSLingrui98    // assert(!has_false_hit)
102909c6f1ddSLingrui98  }
103009c6f1ddSLingrui98
103109c6f1ddSLingrui98  when(has_false_hit) {
103209c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
103309c6f1ddSLingrui98  }
103409c6f1ddSLingrui98
103509c6f1ddSLingrui98  // *******************************************************************************
103609c6f1ddSLingrui98  // **************************** redirect from backend ****************************
103709c6f1ddSLingrui98  // *******************************************************************************
103809c6f1ddSLingrui98
103909c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
104095a47398SGao-Zeyu  // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1)
1041bace178aSGao-Zeyu  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
1042deb3a97eSGao-Zeyu  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem))
1043c776f0d5Smy-mayfly
1044c776f0d5Smy-mayfly  val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry))
104595a47398SGao-Zeyu  for (i <- 1 until FtqRedirectAheadNum) {
104695a47398SGao-Zeyu    ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid
104795a47398SGao-Zeyu    ftq_redirect_mem.io.raddr(i + IfuRedirectNum)   := ftqIdxAhead(i).bits.value
104895a47398SGao-Zeyu    ftb_entry_mem.io.ren.get(i + IfuRedirectNum)    := ftqIdxAhead(i).valid
104995a47398SGao-Zeyu    ftb_entry_mem.io.raddr(i + IfuRedirectNum)      := ftqIdxAhead(i).bits.value
1050c776f0d5Smy-mayfly
1051c776f0d5Smy-mayfly    ftq_pd_mem.io.ren.get(i) := ftqIdxAhead(i).valid
1052c776f0d5Smy-mayfly    ftq_pd_mem.io.raddr(i)   := ftqIdxAhead(i).bits.value
10539342624fSGao-Zeyu  }
105495a47398SGao-Zeyu  ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1055cf7d6b7aSMuzi  ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux(
1056cf7d6b7aSMuzi    aheadValid,
1057cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1058cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1059cf7d6b7aSMuzi  )
106095a47398SGao-Zeyu  ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1061cf7d6b7aSMuzi  ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux(
1062cf7d6b7aSMuzi    aheadValid,
1063cf7d6b7aSMuzi    ftqIdxAhead(0).bits.value,
1064cf7d6b7aSMuzi    backendRedirect.bits.ftqIdx.value
1065cf7d6b7aSMuzi  )
1066bace178aSGao-Zeyu
1067c776f0d5Smy-mayfly  ftq_pd_mem.io.ren.get(0) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1068c776f0d5Smy-mayfly  ftq_pd_mem.io.raddr(0)   := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1069c776f0d5Smy-mayfly
1070bace178aSGao-Zeyu  for (i <- 0 until FtqRedirectAheadNum) {
107195a47398SGao-Zeyu    ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum)
107295a47398SGao-Zeyu    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum)
1073c776f0d5Smy-mayfly
1074c776f0d5Smy-mayfly    ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i)
1075bace178aSGao-Zeyu  }
1076cf7d6b7aSMuzi  val stage3CfiInfo =
1077cf7d6b7aSMuzi    Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum))
1078c776f0d5Smy-mayfly  val stage3PdInfo       = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0))
107909c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
108009c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
1081c776f0d5Smy-mayfly  backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset)
108209c6f1ddSLingrui98
108395a47398SGao-Zeyu  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum))
108409c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
108509c6f1ddSLingrui98
1086d2b20d1aSTang Haojin  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
1087d2b20d1aSTang Haojin  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
10883711cf36S小造xu_zh  // FIXME: not portable
1089abdc3a32Sxu_zh  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
1090cf7d6b7aSMuzi  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(
1091cf7d6b7aSMuzi    r_ftb_entry.brSlots(0).offset === r_ftqOffset,
1092cf7d6b7aSMuzi    sc_disagree(0),
1093cf7d6b7aSMuzi    sc_disagree(1)
1094cf7d6b7aSMuzi  )
1095d2b20d1aSTang Haojin
109609c6f1ddSLingrui98  when(entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
109709c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
109809c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
1099eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
110009c6f1ddSLingrui98
110109c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
1102eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
110309c6f1ddSLingrui98  }.otherwise {
110409c6f1ddSLingrui98    backendRedirectCfi.shift       := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
110509c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
110609c6f1ddSLingrui98  }
110709c6f1ddSLingrui98
110809c6f1ddSLingrui98  // ***************************************************************************
110909c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
111009c6f1ddSLingrui98  // ***************************************************************************
1111d2b20d1aSTang Haojin  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
111209c6f1ddSLingrui98  fromIfuRedirect.valid              := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
111309c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx        := pdWb.bits.ftqIdx
111409c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset     := pdWb.bits.misOffset.bits
111509c6f1ddSLingrui98  fromIfuRedirect.bits.level         := RedirectLevel.flushAfter
1116d2b20d1aSTang Haojin  fromIfuRedirect.bits.BTBMissBubble := true.B
1117d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsMemVio := false.B
1118d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsCtrl   := false.B
111909c6f1ddSLingrui98
112009c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
112109c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc        := pdWb.bits.pc(pdWb.bits.misOffset.bits)
112209c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd        := pdWb.bits.pd(pdWb.bits.misOffset.bits)
112309c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
112409c6f1ddSLingrui98  ifuRedirectCfiUpdate.target    := pdWb.bits.target
112509c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken     := pdWb.bits.cfiOffset.valid
112609c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
112709c6f1ddSLingrui98
11281c6fc24aSEaston Man  val ifuRedirectReg   = RegNextWithEnable(fromIfuRedirect, hasInit = true)
112909c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
113009c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
113109c6f1ddSLingrui98
113216a171eeSEaston Man  ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid
1133deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.head   := fromIfuRedirect.bits.ftqIdx.value
113409c6f1ddSLingrui98
113509c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
1136deb3a97eSGao-Zeyu  toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head)
1137f1267a13SEaston Man  when(ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
1138c89b4642SGuokai Chen    toBpuCfi.target := toBpuCfi.topAddr
113909c6f1ddSLingrui98  }
114009c6f1ddSLingrui98
1141d2b20d1aSTang Haojin  when(ifuRedirectReg.valid) {
1142d2b20d1aSTang Haojin    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
1143d2b20d1aSTang Haojin  }.elsewhen(RegNext(pdWb.valid)) {
1144d2b20d1aSTang Haojin    // if pdWb and no redirect, set to false
1145d2b20d1aSTang Haojin    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
1146d2b20d1aSTang Haojin  }
1147d2b20d1aSTang Haojin
11486022c595SsinceforYy  // **********************************************************************
11496022c595SsinceforYy  // ***************************** to backend *****************************
11506022c595SsinceforYy  // **********************************************************************
11516022c595SsinceforYy  // to backend pc mem / target
11526022c595SsinceforYy  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
1153f533cba7SHuSipeng  io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)
11546022c595SsinceforYy  io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in)
11556022c595SsinceforYy
11566022c595SsinceforYy  // num cycle is fixed
11576022c595SsinceforYy  val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid)
11586022c595SsinceforYy  io.toBackend.newest_entry_en     := RegNext(newest_entry_en)
11596022c595SsinceforYy  io.toBackend.newest_entry_ptr    := RegEnable(newest_entry_ptr, newest_entry_en)
11606022c595SsinceforYy  io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en)
11616022c595SsinceforYy
116209c6f1ddSLingrui98  // *********************************************************************
116309c6f1ddSLingrui98  // **************************** wb from exu ****************************
116409c6f1ddSLingrui98  // *********************************************************************
116509c6f1ddSLingrui98
1166d2b20d1aSTang Haojin  backendRedirect.valid := io.fromBackend.redirect.valid
1167d2b20d1aSTang Haojin  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1168d2b20d1aSTang Haojin  backendRedirect.bits.BTBMissBubble := false.B
1169d2b20d1aSTang Haojin
117009c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
11716bf9b30dSLingrui98    val ftqPtr    = wb.bits.ftqIdx
117209c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
117309c6f1ddSLingrui98    val taken     = wb.bits.cfiUpdate.taken
117409c6f1ddSLingrui98    val mispred   = wb.bits.cfiUpdate.isMisPred
11756bf9b30dSLingrui98    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
117609c6f1ddSLingrui98  }
117709c6f1ddSLingrui98
117809c6f1ddSLingrui98  // fix mispredict entry
117909c6f1ddSLingrui98  val lastIsMispredict = RegNext(
1180cf7d6b7aSMuzi    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter,
1181cf7d6b7aSMuzi    init = false.B
118209c6f1ddSLingrui98  )
118309c6f1ddSLingrui98
118409c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
11856bf9b30dSLingrui98    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
11866bf9b30dSLingrui98    val r_idx                                          = r_ptr.value
118709c6f1ddSLingrui98    val cfiIndex_bits_wen                              = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
118809c6f1ddSLingrui98    val cfiIndex_valid_wen                             = r_valid && r_offset === cfiIndex_vec(r_idx).bits
118909c6f1ddSLingrui98    when(cfiIndex_bits_wen || cfiIndex_valid_wen) {
119009c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
11913f88c020SGuokai Chen    }.elsewhen(r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
11923f88c020SGuokai Chen      cfiIndex_vec(r_idx).valid := false.B
119309c6f1ddSLingrui98    }
119409c6f1ddSLingrui98    when(cfiIndex_bits_wen) {
119509c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
119609c6f1ddSLingrui98    }
11971c6fc24aSEaston Man    newest_entry_target_modified := true.B
11986bf9b30dSLingrui98    newest_entry_target          := redirect.bits.cfiUpdate.target
11991c6fc24aSEaston Man    newest_entry_ptr_modified    := true.B
1200873dc383SLingrui98    newest_entry_ptr             := r_ptr
12011c6fc24aSEaston Man
1202b0ed7239SLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
120309c6f1ddSLingrui98    if (isBackend) {
120409c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
120509c6f1ddSLingrui98    }
120609c6f1ddSLingrui98  }
120709c6f1ddSLingrui98
1208bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1209bace178aSGao-Zeyu    updateCfiInfo(fromBackendRedirect)
121009c6f1ddSLingrui98  }.elsewhen(ifuRedirectToBpu.valid) {
121109c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend = false)
121209c6f1ddSLingrui98  }
121309c6f1ddSLingrui98
1214bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1215bace178aSGao-Zeyu    when(fromBackendRedirect.bits.ControlRedirectBubble) {
1216d2b20d1aSTang Haojin      when(fromBackendRedirect.bits.ControlBTBMissBubble) {
1217d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1218d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1219d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.TAGEMissBubble) {
1220d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id)                  := true.B
1221d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1222d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.SCMissBubble) {
1223d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.SCMissBubble.id)                  := true.B
1224d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1225d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.ITTAGEMissBubble) {
1226d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id)                  := true.B
1227d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1228d2b20d1aSTang Haojin      }.elsewhen(fromBackendRedirect.bits.RASMissBubble) {
1229d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.RASMissBubble.id)                  := true.B
1230d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1231d2b20d1aSTang Haojin      }
1232d2b20d1aSTang Haojin
12339342624fSGao-Zeyu    }.elsewhen(backendRedirect.bits.MemVioRedirectBubble) {
1234d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id)                  := true.B
1235d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1236d2b20d1aSTang Haojin    }.otherwise {
1237d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id)                  := true.B
1238d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1239d2b20d1aSTang Haojin    }
1240d2b20d1aSTang Haojin  }.elsewhen(ifuRedirectReg.valid) {
1241d2b20d1aSTang Haojin    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id)                  := true.B
1242d2b20d1aSTang Haojin    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1243d2b20d1aSTang Haojin  }
1244d2b20d1aSTang Haojin
1245d2b20d1aSTang Haojin  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1246d2b20d1aSTang Haojin  io.TAGEMissBubble       := fromBackendRedirect.bits.TAGEMissBubble
1247d2b20d1aSTang Haojin  io.SCMissBubble         := fromBackendRedirect.bits.SCMissBubble
1248d2b20d1aSTang Haojin  io.ITTAGEMissBubble     := fromBackendRedirect.bits.ITTAGEMissBubble
1249d2b20d1aSTang Haojin  io.RASMissBubble        := fromBackendRedirect.bits.RASMissBubble
1250d2b20d1aSTang Haojin
125109c6f1ddSLingrui98  // ***********************************************************************************
125209c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
125309c6f1ddSLingrui98  // ***********************************************************************************
125409c6f1ddSLingrui98
1255df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
125609c6f1ddSLingrui98
125709c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
1258b92f8445Sssszwic  io.icacheFlush := redirectVec.map(r => r.valid).reduce(_ || _)
1259b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid)
1260b92f8445Sssszwic  XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid)
126109c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_ || _)) {
1262cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
126309c6f1ddSLingrui98    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
12642f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
126509c6f1ddSLingrui98    val next                       = idx + 1.U
126609c6f1ddSLingrui98    bpuPtr := next
1267dc270d3bSJenius    copied_bpu_ptr.map(_ := next)
1268c5c5edaeSJenius    ifuPtr_write      := next
1269c5c5edaeSJenius    ifuWbPtr_write    := next
1270c5c5edaeSJenius    ifuPtrPlus1_write := idx + 2.U
12716bf9b30dSLingrui98    ifuPtrPlus2_write := idx + 3.U
1272b92f8445Sssszwic    pfPtr_write       := next
1273b92f8445Sssszwic    pfPtrPlus1_write  := idx + 2.U
12743f88c020SGuokai Chen  }
12753f88c020SGuokai Chen  when(RegNext(redirectVec.map(r => r.valid).reduce(_ || _))) {
1276cf7d6b7aSMuzi    val r                          = PriorityMux(redirectVec.map(r => r.valid -> r.bits))
12773f88c020SGuokai Chen    val notIfu                     = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _)
12783f88c020SGuokai Chen    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
12793f88c020SGuokai Chen    when(RegNext(notIfu)) {
12801c6fc24aSEaston Man      commitStateQueueEnable(RegNext(idx.value)) := true.B
1281cf7d6b7aSMuzi      commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach { case (s, i) =>
128291346769SMuzi        when(i.U > RegNext(offset)) {
128391346769SMuzi          s := c_empty
128491346769SMuzi        }
128591346769SMuzi        when(i.U === RegNext(offset) && RegNext(flushItSelf)) {
128691346769SMuzi          s := c_flushed
128709c6f1ddSLingrui98        }
128809c6f1ddSLingrui98      }
128909c6f1ddSLingrui98    }
1290cf7d6b7aSMuzi  }
12913f88c020SGuokai Chen
129209c6f1ddSLingrui98  // only the valid bit is actually needed
1293df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
129409c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
1295d2b20d1aSTang Haojin  io.toIfu.topdown_redirect := fromBackendRedirect
129609c6f1ddSLingrui98
129709c6f1ddSLingrui98  // commit
12989aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
129909c6f1ddSLingrui98    when(c.valid) {
13001c6fc24aSEaston Man      commitStateQueueEnable(c.bits.ftqIdx.value)                 := true.B
130191346769SMuzi      commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed
130288825c5cSYinan Xu      // TODO: remove this
130388825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
1304c3abb8b6SYinan Xu      when(c.bits.commitType === 4.U) {
130591346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed
1306c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
130791346769SMuzi        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed
1308c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
130988825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13101c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
131191346769SMuzi        commitStateQueueNext(index)(0) := c_committed
1312c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
131388825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
13141c6fc24aSEaston Man        commitStateQueueEnable(index)  := true.B
131591346769SMuzi        commitStateQueueNext(index)(1) := c_committed
131688825c5cSYinan Xu      }
131709c6f1ddSLingrui98    }
131809c6f1ddSLingrui98  }
131909c6f1ddSLingrui98
132009c6f1ddSLingrui98  // ****************************************************************
132109c6f1ddSLingrui98  // **************************** to bpu ****************************
132209c6f1ddSLingrui98  // ****************************************************************
132309c6f1ddSLingrui98
1324fd3aa057SYuandongliang  io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid
132551981c77SbugGenerator  io.toBpu.redirect       := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1326209a4cafSSteve Gou  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_ => 0.U(64.W)))
1327cf7d6b7aSMuzi  val redirect_latency =
1328cf7d6b7aSMuzi    GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1329209a4cafSSteve Gou  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1330cf7d6b7aSMuzi  XSPerfHistogram(
1331cf7d6b7aSMuzi    "ifu_redirect_latency",
1332cf7d6b7aSMuzi    redirect_latency,
1333cf7d6b7aSMuzi    !fromBackendRedirect.valid && ifuRedirectToBpu.valid,
1334cf7d6b7aSMuzi    0,
1335cf7d6b7aSMuzi    60,
1336cf7d6b7aSMuzi    1
1337cf7d6b7aSMuzi  )
133809c6f1ddSLingrui98
1339cf7d6b7aSMuzi  XSError(
1340cf7d6b7aSMuzi    io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr),
1341cf7d6b7aSMuzi    "Ftq received a redirect after its commit, check backend or replay"
1342cf7d6b7aSMuzi  )
134309c6f1ddSLingrui98
134402f21c16SLingrui98  val may_have_stall_from_bpu = Wire(Bool())
134502f21c16SLingrui98  val bpu_ftb_update_stall    = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
134602f21c16SLingrui98  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
13479230e379SMuzi
13489230e379SMuzi  val validInstructions       = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed)
13499230e379SMuzi  val lastInstructionStatus   = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse))
13509230e379SMuzi  val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed
13519230e379SMuzi  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13529230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13539230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed)
13549230e379SMuzi  val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
13559230e379SMuzi    (isAfter(robCommPtr, commPtr) ||
13569230e379SMuzi      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed ||
13579230e379SMuzi      firstInstructionFlushed)
135891346769SMuzi
135991346769SMuzi  when(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) {
1360cf7d6b7aSMuzi    robCommPtr_write := ParallelPriorityMux(
1361cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.valid).reverse,
1362cf7d6b7aSMuzi      io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse
1363cf7d6b7aSMuzi    )
13649230e379SMuzi  }.elsewhen(isAfter(commPtr, robCommPtr)) {
136591346769SMuzi    robCommPtr_write := commPtr
136691346769SMuzi  }.otherwise {
136791346769SMuzi    robCommPtr_write := robCommPtr
136891346769SMuzi  }
136909c6f1ddSLingrui98
1370ba5ba1dcSmy-mayfly  /**
1371ba5ba1dcSmy-mayfly    *************************************************************************************
1372ba5ba1dcSmy-mayfly    * MMIO instruction fetch is allowed only if MMIO is the oldest instruction.
1373ba5ba1dcSmy-mayfly    *************************************************************************************
1374ba5ba1dcSmy-mayfly    */
13751d1e6d4dSJenius  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
13769230e379SMuzi  val mmioLastCommit = isAfter(commPtr, mmioReadPtr) ||
13779230e379SMuzi    commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed
13781d1e6d4dSJenius  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
13791d1e6d4dSJenius
138009c6f1ddSLingrui98  // commit reads
1381c5c5edaeSJenius  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
138281101dc4SLingrui98  val commit_target =
1383cf7d6b7aSMuzi    Mux(
1384cf7d6b7aSMuzi      RegNext(commPtr === newest_entry_ptr),
13851c6fc24aSEaston Man      RegEnable(newest_entry_target, newest_entry_target_modified),
1386cf7d6b7aSMuzi      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)
1387cf7d6b7aSMuzi    )
13881c6fc24aSEaston Man  ftq_pd_mem.io.ren.get.last := canCommit
138909c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last   := commPtr.value
139009c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
139116a171eeSEaston Man  ftq_redirect_mem.io.ren.get.last := canCommit
1392deb3a97eSGao-Zeyu  ftq_redirect_mem.io.raddr.last   := commPtr.value
1393deb3a97eSGao-Zeyu  val commit_spec_meta = ftq_redirect_mem.io.rdata.last
139409c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0)   := canCommit
139509c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1396deb3a97eSGao-Zeyu  val commit_meta      = ftq_meta_1r_sram.io.rdata(0).meta
1397deb3a97eSGao-Zeyu  val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry
139809c6f1ddSLingrui98
139909c6f1ddSLingrui98  // need one cycle to read mem and srams
14001c6fc24aSEaston Man  val do_commit_ptr = RegEnable(commPtr, canCommit)
14015371700eSzoujr  val do_commit     = RegNext(canCommit, init = false.B)
14029230e379SMuzi  when(canMoveCommPtr) {
14036bf9b30dSLingrui98    commPtr_write      := commPtrPlus1
14046bf9b30dSLingrui98    commPtrPlus1_write := commPtrPlus1 + 1.U
14056bf9b30dSLingrui98  }
14061c6fc24aSEaston Man  val commit_state   = RegEnable(commitStateQueueReg(commPtr.value), canCommit)
14075371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1408d4fcfc3eSGuokai Chen  val do_commit_cfi  = WireInit(cfiIndex_vec(do_commit_ptr.value))
14093f88c020SGuokai Chen  //
14103f88c020SGuokai Chen  // when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
14113f88c020SGuokai Chen  //  can_commit_cfi.valid := false.B
14123f88c020SGuokai Chen  // }
14131c6fc24aSEaston Man  val commit_cfi = RegEnable(can_commit_cfi, canCommit)
141491346769SMuzi  val debug_cfi  = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid
141509c6f1ddSLingrui98
1416cf7d6b7aSMuzi  val commit_mispredict: Vec[Bool] =
1417cf7d6b7aSMuzi    VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map {
141891346769SMuzi      case (mis, state) => mis && state === c_committed
141909c6f1ddSLingrui98    })
142091346769SMuzi  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth]
14215371700eSzoujr  val can_commit_hit     = entry_hit_status(commPtr.value)
14221c6fc24aSEaston Man  val commit_hit         = RegEnable(can_commit_hit, canCommit)
14231c6fc24aSEaston Man  val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this
14241c6fc24aSEaston Man  val commit_stage       = RegEnable(pred_stage(commPtr.value), canCommit)
142509c6f1ddSLingrui98  val commit_valid       = commit_hit === h_hit || commit_cfi.valid           // hit or taken
142609c6f1ddSLingrui98
14275371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
142802f21c16SLingrui98  switch(bpu_ftb_update_stall) {
142902f21c16SLingrui98    is(0.U) {
143002f21c16SLingrui98      when(can_commit_cfi.valid && !to_bpu_hit && canCommit) {
143102f21c16SLingrui98        bpu_ftb_update_stall := 2.U // 2-cycle stall
143202f21c16SLingrui98      }
143302f21c16SLingrui98    }
143402f21c16SLingrui98    is(2.U) {
143502f21c16SLingrui98      bpu_ftb_update_stall := 1.U
143602f21c16SLingrui98    }
143702f21c16SLingrui98    is(1.U) {
143802f21c16SLingrui98      bpu_ftb_update_stall := 0.U
143902f21c16SLingrui98    }
144002f21c16SLingrui98    is(3.U) {
144102f21c16SLingrui98      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
144202f21c16SLingrui98    }
144302f21c16SLingrui98  }
144409c6f1ddSLingrui98
1445b0ed7239SLingrui98  // TODO: remove this
1446b0ed7239SLingrui98  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1447b0ed7239SLingrui98
1448b2f6ed0aSSteve Gou  // update latency stats
1449b2f6ed0aSSteve Gou  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1450b2f6ed0aSSteve Gou  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1451b2f6ed0aSSteve Gou
145209c6f1ddSLingrui98  io.toBpu.update       := DontCare
145309c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
145409c6f1ddSLingrui98  val update = io.toBpu.update.bits
145509c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
145609c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
1457deb3a97eSGao-Zeyu  update.meta        := commit_meta
1458803124a6SLingrui98  update.cfi_idx     := commit_cfi
14598ffcd86aSLingrui98  update.full_target := commit_target
1460edc18578SLingrui98  update.from_stage  := commit_stage
1461c2d1ec7dSLingrui98  update.spec_info   := commit_spec_meta
14623f88c020SGuokai Chen  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
146309c6f1ddSLingrui98
146409c6f1ddSLingrui98  val commit_real_hit  = commit_hit === h_hit
146509c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
146609c6f1ddSLingrui98
146709c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
146809c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
146909c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
147009c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
147109c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
147209c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
147309c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
147409c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
147509c6f1ddSLingrui98
147609c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
147709c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
147809c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
147909c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
1480edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1481803124a6SLingrui98  update.br_taken_mask     := ftbEntryGen.taken_mask
1482cc2d1573SEaston Man  update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1483cc2d1573SEaston Man    case (valid, offset) => valid && commit_instCommited(offset)
1484cc2d1573SEaston Man  }
1485803124a6SLingrui98  update.jmp_taken := ftbEntryGen.jmp_taken
1486b37e4b45SLingrui98
1487803124a6SLingrui98  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1488803124a6SLingrui98  // update.full_pred.jalr_target := commit_target
1489803124a6SLingrui98  // update.full_pred.hit := true.B
1490803124a6SLingrui98  // when (update.full_pred.is_jalr) {
1491803124a6SLingrui98  //   update.full_pred.targets.last := commit_target
1492803124a6SLingrui98  // }
149309c6f1ddSLingrui98
149409c6f1ddSLingrui98  // ******************************************************************************
149509c6f1ddSLingrui98  // **************************** commit perf counters ****************************
149609c6f1ddSLingrui98  // ******************************************************************************
149709c6f1ddSLingrui98
149891346769SMuzi  val commit_inst_mask        = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt
149909c6f1ddSLingrui98  val commit_mispred_mask     = commit_mispredict.asUInt
150009c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
150109c6f1ddSLingrui98
150209c6f1ddSLingrui98  val commit_br_mask  = commit_pd.brMask.asUInt
150309c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1504cf7d6b7aSMuzi  val commit_cfi_mask = commit_br_mask | commit_jmp_mask
150509c6f1ddSLingrui98
150609c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
150709c6f1ddSLingrui98
150809c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
150909c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
151009c6f1ddSLingrui98
151109c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
151209c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
151309c6f1ddSLingrui98
1514b92f8445Sssszwic  val hartId           = p(XSCoreParamsKey).HartId
1515c686adcdSYinan Xu  val isWriteFTQTable  = Constantin.createRecord(s"isWriteFTQTable$hartId")
1516c686adcdSYinan Xu  val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle)
151709c6f1ddSLingrui98  // Cfi Info
151809c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
151909c6f1ddSLingrui98    val pc      = commit_pc_bundle.startAddr + (i * instBytes).U
152091346769SMuzi    val v       = commit_state(i) === c_committed
152109c6f1ddSLingrui98    val isBr    = commit_pd.brMask(i)
152209c6f1ddSLingrui98    val isJmp   = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
152309c6f1ddSLingrui98    val isCfi   = isBr || isJmp
152409c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
152509c6f1ddSLingrui98    val misPred = commit_mispredict(i)
1526c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
1527c2ad24ebSLingrui98    val histPtr   = commit_spec_meta.histPtr
1528deb3a97eSGao-Zeyu    val predCycle = commit_meta(63, 0)
152909c6f1ddSLingrui98    val target    = commit_target
153009c6f1ddSLingrui98
1531cf7d6b7aSMuzi    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1532cf7d6b7aSMuzi      v && offset === i.U
1533cf7d6b7aSMuzi    })))
1534cf7d6b7aSMuzi    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) =>
1535cf7d6b7aSMuzi      v && offset === i.U
1536cf7d6b7aSMuzi    }.reduce(_ || _)
1537cf7d6b7aSMuzi    val addIntoHist =
1538cf7d6b7aSMuzi      ((commit_hit === h_hit) && inFtbEntry) || (!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)
1539cf7d6b7aSMuzi    XSDebug(
1540cf7d6b7aSMuzi      v && do_commit && isCfi,
1541cf7d6b7aSMuzi      p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1542c2ad24ebSLingrui98        p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
154309c6f1ddSLingrui98        p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1544cf7d6b7aSMuzi        p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n"
1545cf7d6b7aSMuzi    )
154651532d8bSGuokai Chen
154751532d8bSGuokai Chen    val logbundle = Wire(new FtqDebugBundle)
154851532d8bSGuokai Chen    logbundle.pc        := pc
154951532d8bSGuokai Chen    logbundle.target    := target
155051532d8bSGuokai Chen    logbundle.isBr      := isBr
155151532d8bSGuokai Chen    logbundle.isJmp     := isJmp
155251532d8bSGuokai Chen    logbundle.isCall    := isJmp && commit_pd.hasCall
155351532d8bSGuokai Chen    logbundle.isRet     := isJmp && commit_pd.hasRet
155451532d8bSGuokai Chen    logbundle.misPred   := misPred
155551532d8bSGuokai Chen    logbundle.isTaken   := isTaken
155651532d8bSGuokai Chen    logbundle.predStage := commit_stage
155751532d8bSGuokai Chen
155851532d8bSGuokai Chen    ftqBranchTraceDB.log(
155951532d8bSGuokai Chen      data = logbundle /* hardware of type T */,
1560da3bf434SMaxpicca-Li      en = isWriteFTQTable.orR && v && do_commit && isCfi,
156151532d8bSGuokai Chen      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
156251532d8bSGuokai Chen      clock = clock,
156351532d8bSGuokai Chen      reset = reset
156451532d8bSGuokai Chen    )
156509c6f1ddSLingrui98  }
156609c6f1ddSLingrui98
156709c6f1ddSLingrui98  val enq           = io.fromBpu.resp
15682e1be6e1SSteve Gou  val perf_redirect = backendRedirect
156909c6f1ddSLingrui98
157009c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
157109c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
157209c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
157309c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
157409c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
157509c6f1ddSLingrui98
157609c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
157709c6f1ddSLingrui98
157809c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
157909c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
158012cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1581cf7d6b7aSMuzi  XSPerfAccumulate(
1582cf7d6b7aSMuzi    "bpu_to_ifu_bubble_when_ftq_full",
1583cf7d6b7aSMuzi    (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready
1584cf7d6b7aSMuzi  )
158509c6f1ddSLingrui98
1586bace178aSGao-Zeyu  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_ | _))
15879342624fSGao-Zeyu  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
15889342624fSGao-Zeyu  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
15899342624fSGao-Zeyu
159009c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
159109c6f1ddSLingrui98  val to_ifu   = io.toIfu.req.bits
159209c6f1ddSLingrui98
1593209a4cafSSteve Gou  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth + 1, 1)
159409c6f1ddSLingrui98
159509c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
159609c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
159709c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
159809c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
159909c6f1ddSLingrui98
160009c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
160109c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
160209c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
160309c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
160409c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
160509c6f1ddSLingrui98
160609c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
160709c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
160809c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
160909c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
161009c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
161109c6f1ddSLingrui98
16121d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
16131d7e5011SLingrui98
1614cf7d6b7aSMuzi  def pred_stage_map(src: UInt, name: String) =
16151d7e5011SLingrui98    (0 until numBpStages).map(i =>
16161d7e5011SLingrui98      f"${name}_stage_${i + 1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
16171d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_ + _)
16181d7e5011SLingrui98
16191d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs, "mispredict")
16201d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
16211d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
16221d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights, "correct")
16231d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
16241d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
16251d7e5011SLingrui98
162609c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
162709c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
162809c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
162965fddcf0Szoujr  // assert(!ftb_false_hit)
163009c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
163109c6f1ddSLingrui98
163209c6f1ddSLingrui98  val ftb_new_entry                = u(ftbEntryGen.is_init_entry)
1633b37e4b45SLingrui98  val ftb_new_entry_only_br        = ftb_new_entry && !update_ftb_entry.jmpValid
1634b37e4b45SLingrui98  val ftb_new_entry_only_jmp       = ftb_new_entry && !update_ftb_entry.brValids(0)
1635b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
163609c6f1ddSLingrui98
163709c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
163809c6f1ddSLingrui98
1639cf7d6b7aSMuzi  val ftb_modified_entry =
1640*dcf4211fSYuandongliang    u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_strong_bias_modified)
164109c6f1ddSLingrui98  val ftb_modified_entry_new_br               = u(ftbEntryGen.is_new_br)
1642d2b20d1aSTang Haojin  val ftb_modified_entry_ifu_redirected       = u(ifuRedirected(do_commit_ptr.value))
164309c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
164409c6f1ddSLingrui98  val ftb_modified_entry_br_full              = ftb_modified_entry && ftbEntryGen.is_br_full
1645*dcf4211fSYuandongliang  val ftb_modified_entry_strong_bias          = ftb_modified_entry && ftbEntryGen.is_strong_bias_modified
164609c6f1ddSLingrui98
1647209a4cafSSteve Gou  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1648209a4cafSSteve Gou  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1649209a4cafSSteve Gou  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth + 1, 1)
1650209a4cafSSteve Gou  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth + 1, 1)
1651209a4cafSSteve Gou  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1652209a4cafSSteve Gou  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth + 1, 1)
165309c6f1ddSLingrui98
1654209a4cafSSteve Gou  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize + 1, 1)
165509c6f1ddSLingrui98
165609c6f1ddSLingrui98  val perfCountsMap = Map(
165709c6f1ddSLingrui98    "BpInstr"                        -> PopCount(mbpInstrs),
165809c6f1ddSLingrui98    "BpBInstr"                       -> PopCount(mbpBRights | mbpBWrongs),
165909c6f1ddSLingrui98    "BpRight"                        -> PopCount(mbpRights),
166009c6f1ddSLingrui98    "BpWrong"                        -> PopCount(mbpWrongs),
166109c6f1ddSLingrui98    "BpBRight"                       -> PopCount(mbpBRights),
166209c6f1ddSLingrui98    "BpBWrong"                       -> PopCount(mbpBWrongs),
166309c6f1ddSLingrui98    "BpJRight"                       -> PopCount(mbpJRights),
166409c6f1ddSLingrui98    "BpJWrong"                       -> PopCount(mbpJWrongs),
166509c6f1ddSLingrui98    "BpIRight"                       -> PopCount(mbpIRights),
166609c6f1ddSLingrui98    "BpIWrong"                       -> PopCount(mbpIWrongs),
166709c6f1ddSLingrui98    "BpCRight"                       -> PopCount(mbpCRights),
166809c6f1ddSLingrui98    "BpCWrong"                       -> PopCount(mbpCWrongs),
166909c6f1ddSLingrui98    "BpRRight"                       -> PopCount(mbpRRights),
167009c6f1ddSLingrui98    "BpRWrong"                       -> PopCount(mbpRWrongs),
167109c6f1ddSLingrui98    "ftb_false_hit"                  -> PopCount(ftb_false_hit),
167209c6f1ddSLingrui98    "ftb_hit"                        -> PopCount(ftb_hit),
167309c6f1ddSLingrui98    "ftb_new_entry"                  -> PopCount(ftb_new_entry),
167409c6f1ddSLingrui98    "ftb_new_entry_only_br"          -> PopCount(ftb_new_entry_only_br),
167509c6f1ddSLingrui98    "ftb_new_entry_only_jmp"         -> PopCount(ftb_new_entry_only_jmp),
167609c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp"   -> PopCount(ftb_new_entry_has_br_and_jmp),
167709c6f1ddSLingrui98    "ftb_old_entry"                  -> PopCount(ftb_old_entry),
167809c6f1ddSLingrui98    "ftb_modified_entry"             -> PopCount(ftb_modified_entry),
167909c6f1ddSLingrui98    "ftb_modified_entry_new_br"      -> PopCount(ftb_modified_entry_new_br),
168009c6f1ddSLingrui98    "ftb_jalr_target_modified"       -> PopCount(ftb_modified_entry_jalr_target_modified),
168109c6f1ddSLingrui98    "ftb_modified_entry_br_full"     -> PopCount(ftb_modified_entry_br_full),
1682*dcf4211fSYuandongliang    "ftb_modified_entry_strong_bias" -> PopCount(ftb_modified_entry_strong_bias)
1683209a4cafSSteve Gou  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
16841d7e5011SLingrui98    correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
168509c6f1ddSLingrui98
168609c6f1ddSLingrui98  for ((key, value) <- perfCountsMap) {
168709c6f1ddSLingrui98    XSPerfAccumulate(key, value)
168809c6f1ddSLingrui98  }
168909c6f1ddSLingrui98
169009c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
169109c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
169209c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
169309c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
169409c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1695cf7d6b7aSMuzi  XSDebug(
1696cf7d6b7aSMuzi    true.B,
1697cf7d6b7aSMuzi    p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1698cf7d6b7aSMuzi      p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n"
1699cf7d6b7aSMuzi  )
170009c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
170109c6f1ddSLingrui98
170209c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
170309c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
170409c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
170509c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
170609c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
170709c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
170809c6f1ddSLingrui98  //           !taken),
170909c6f1ddSLingrui98  //         !taken),
171009c6f1ddSLingrui98  //       false.B)
171109c6f1ddSLingrui98  //     }
171209c6f1ddSLingrui98  //   }
171309c6f1ddSLingrui98
171409c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
171509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
171609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
171709c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
171809c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
171909c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
172009c6f1ddSLingrui98  //           !taken),
172109c6f1ddSLingrui98  //         !taken),
172209c6f1ddSLingrui98  //       false.B)
172309c6f1ddSLingrui98  //     }
172409c6f1ddSLingrui98  //   }
172509c6f1ddSLingrui98
172609c6f1ddSLingrui98  //   def tageCheck(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,
173009c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
173109c6f1ddSLingrui98  //       false.B)
173209c6f1ddSLingrui98  //     }
173309c6f1ddSLingrui98  //   }
173409c6f1ddSLingrui98
173509c6f1ddSLingrui98  //   def loopCheck(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.isBr) && ans.hit.asBool,
173909c6f1ddSLingrui98  //         isWrong ^ (!taken),
174009c6f1ddSLingrui98  //           false.B)
174109c6f1ddSLingrui98  //     }
174209c6f1ddSLingrui98  //   }
174309c6f1ddSLingrui98
174409c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
174509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
174609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
174709c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
174809c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
174909c6f1ddSLingrui98  //           false.B)
175009c6f1ddSLingrui98  //     }
175109c6f1ddSLingrui98  //   }
175209c6f1ddSLingrui98
175309c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
175409c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
175509c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
175609c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
175709c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
175809c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
175909c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
176009c6f1ddSLingrui98
176109c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
176209c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
176309c6f1ddSLingrui98
176409c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
176509c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
17661ca0e4f3SYinan Xu
1767cd365d4cSrvcoresjw  val perfEvents = Seq(
1768cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect),
1769cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect),
1770cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready),
1771cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1772cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)),
1773cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid),
1774cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid),
1775cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn),
1776cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)),
1777cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)),
1778cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)),
1779cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)),
1780cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)),
1781cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)),
1782cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)),
1783cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)),
1784cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)),
1785cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)),
1786cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)),
1787cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)),
1788cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)),
1789cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)),
1790cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)),
1791cf7d6b7aSMuzi    ("ftb_hit                ", PopCount(ftb_hit))
1792cd365d4cSrvcoresjw  )
17931ca0e4f3SYinan Xu  generatePerfEvent()
179409c6f1ddSLingrui98}
1795