xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision a60a2901757ddbe9fd01bead0241fe3107ae3347)
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 chipsalliance.rocketchip.config.Parameters
2009c6f1ddSLingrui98import chisel3._
2109c6f1ddSLingrui98import chisel3.util._
221ca0e4f3SYinan Xuimport utils._
2309c6f1ddSLingrui98import xiangshan._
24e30430c2SJayimport xiangshan.frontend.icache._
251ca0e4f3SYinan Xuimport xiangshan.backend.CtrlToFtqIO
2609c6f1ddSLingrui98
2709c6f1ddSLingrui98class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr](
2809c6f1ddSLingrui98  p => p(XSCoreParamsKey).FtqSize
2909c6f1ddSLingrui98){
3009c6f1ddSLingrui98  override def cloneType = (new FtqPtr).asInstanceOf[this.type]
3109c6f1ddSLingrui98}
3209c6f1ddSLingrui98
3309c6f1ddSLingrui98object FtqPtr {
3409c6f1ddSLingrui98  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
3509c6f1ddSLingrui98    val ptr = Wire(new FtqPtr)
3609c6f1ddSLingrui98    ptr.flag := f
3709c6f1ddSLingrui98    ptr.value := v
3809c6f1ddSLingrui98    ptr
3909c6f1ddSLingrui98  }
4009c6f1ddSLingrui98  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
4109c6f1ddSLingrui98    apply(!ptr.flag, ptr.value)
4209c6f1ddSLingrui98  }
4309c6f1ddSLingrui98}
4409c6f1ddSLingrui98
4509c6f1ddSLingrui98class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
4609c6f1ddSLingrui98
4709c6f1ddSLingrui98  val io = IO(new Bundle() {
4809c6f1ddSLingrui98    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
4909c6f1ddSLingrui98    val ren = Input(Vec(numRead, Bool()))
5009c6f1ddSLingrui98    val rdata = Output(Vec(numRead, gen))
5109c6f1ddSLingrui98    val waddr = Input(UInt(log2Up(FtqSize).W))
5209c6f1ddSLingrui98    val wen = Input(Bool())
5309c6f1ddSLingrui98    val wdata = Input(gen)
5409c6f1ddSLingrui98  })
5509c6f1ddSLingrui98
5609c6f1ddSLingrui98  for(i <- 0 until numRead){
5709c6f1ddSLingrui98    val sram = Module(new SRAMTemplate(gen, FtqSize))
5809c6f1ddSLingrui98    sram.io.r.req.valid := io.ren(i)
5909c6f1ddSLingrui98    sram.io.r.req.bits.setIdx := io.raddr(i)
6009c6f1ddSLingrui98    io.rdata(i) := sram.io.r.resp.data(0)
6109c6f1ddSLingrui98    sram.io.w.req.valid := io.wen
6209c6f1ddSLingrui98    sram.io.w.req.bits.setIdx := io.waddr
6309c6f1ddSLingrui98    sram.io.w.req.bits.data := VecInit(io.wdata)
6409c6f1ddSLingrui98  }
6509c6f1ddSLingrui98
6609c6f1ddSLingrui98}
6709c6f1ddSLingrui98
6809c6f1ddSLingrui98class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
6909c6f1ddSLingrui98  val startAddr = UInt(VAddrBits.W)
70b37e4b45SLingrui98  val nextLineAddr = UInt(VAddrBits.W)
7109c6f1ddSLingrui98  val isNextMask = Vec(PredictWidth, Bool())
72b37e4b45SLingrui98  val fallThruError = Bool()
73b37e4b45SLingrui98  // val carry = Bool()
7409c6f1ddSLingrui98  def getPc(offset: UInt) = {
7585215037SLingrui98    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
7685215037SLingrui98    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits)
77b37e4b45SLingrui98    Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)),
7809c6f1ddSLingrui98        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
7909c6f1ddSLingrui98  }
8009c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
81a229ab6cSLingrui98    def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1)
8209c6f1ddSLingrui98    this.startAddr := resp.pc
83*a60a2901SLingrui98    this.nextLineAddr := resp.pc + (FetchWidth * 4 * 2).U // may be broken on other configs
8409c6f1ddSLingrui98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
8509c6f1ddSLingrui98      (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool()
8609c6f1ddSLingrui98    ))
87b37e4b45SLingrui98    this.fallThruError := resp.fallThruError
8809c6f1ddSLingrui98    this
8909c6f1ddSLingrui98  }
9009c6f1ddSLingrui98  override def toPrintable: Printable = {
91b37e4b45SLingrui98    p"startAddr:${Hexadecimal(startAddr)}"
9209c6f1ddSLingrui98  }
9309c6f1ddSLingrui98}
9409c6f1ddSLingrui98
9509c6f1ddSLingrui98class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
9609c6f1ddSLingrui98  val brMask = Vec(PredictWidth, Bool())
9709c6f1ddSLingrui98  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
9809c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
9909c6f1ddSLingrui98  val jalTarget = UInt(VAddrBits.W)
10009c6f1ddSLingrui98  val rvcMask = Vec(PredictWidth, Bool())
10109c6f1ddSLingrui98  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
10209c6f1ddSLingrui98  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
10309c6f1ddSLingrui98  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
10409c6f1ddSLingrui98  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
10509c6f1ddSLingrui98
10609c6f1ddSLingrui98  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
10709c6f1ddSLingrui98    val pds = pdWb.pd
10809c6f1ddSLingrui98    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
10909c6f1ddSLingrui98    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
11009c6f1ddSLingrui98    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
11109c6f1ddSLingrui98                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
11209c6f1ddSLingrui98    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
11309c6f1ddSLingrui98    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
11409c6f1ddSLingrui98    this.jalTarget := pdWb.jalTarget
11509c6f1ddSLingrui98  }
11609c6f1ddSLingrui98
11709c6f1ddSLingrui98  def toPd(offset: UInt) = {
11809c6f1ddSLingrui98    require(offset.getWidth == log2Ceil(PredictWidth))
11909c6f1ddSLingrui98    val pd = Wire(new PreDecodeInfo)
12009c6f1ddSLingrui98    pd.valid := true.B
12109c6f1ddSLingrui98    pd.isRVC := rvcMask(offset)
12209c6f1ddSLingrui98    val isBr = brMask(offset)
12309c6f1ddSLingrui98    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
12409c6f1ddSLingrui98    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
12509c6f1ddSLingrui98    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
12609c6f1ddSLingrui98    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
12709c6f1ddSLingrui98    pd
12809c6f1ddSLingrui98  }
12909c6f1ddSLingrui98}
13009c6f1ddSLingrui98
13109c6f1ddSLingrui98
13209c6f1ddSLingrui98
13309c6f1ddSLingrui98class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
13409c6f1ddSLingrui98  val rasSp = UInt(log2Ceil(RasSize).W)
13509c6f1ddSLingrui98  val rasEntry = new RASEntry
136b37e4b45SLingrui98  // val specCnt = Vec(numBr, UInt(10.W))
137c2ad24ebSLingrui98  // val ghist = new ShiftingGlobalHistory
138dd6c0695SLingrui98  val folded_hist = new AllFoldedHistories(foldedGHistInfos)
13967402d75SLingrui98  val afhob = new AllAheadFoldedHistoryOldestBits(foldedGHistInfos)
14067402d75SLingrui98  val lastBrNumOH = UInt((numBr+1).W)
14167402d75SLingrui98
142c2ad24ebSLingrui98  val histPtr = new CGHPtr
14309c6f1ddSLingrui98
14409c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
145b37e4b45SLingrui98    assert(!resp.is_minimal)
14609c6f1ddSLingrui98    this.rasSp := resp.rasSp
14709c6f1ddSLingrui98    this.rasEntry := resp.rasTop
148dd6c0695SLingrui98    this.folded_hist := resp.folded_hist
14967402d75SLingrui98    this.afhob := resp.afhob
15067402d75SLingrui98    this.lastBrNumOH := resp.lastBrNumOH
151c2ad24ebSLingrui98    this.histPtr := resp.histPtr
15209c6f1ddSLingrui98    this
15309c6f1ddSLingrui98  }
15409c6f1ddSLingrui98}
15509c6f1ddSLingrui98
15609c6f1ddSLingrui98class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
15709c6f1ddSLingrui98  val meta = UInt(MaxMetaLength.W)
15809c6f1ddSLingrui98}
15909c6f1ddSLingrui98
16009c6f1ddSLingrui98class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
16109c6f1ddSLingrui98  val target = UInt(VAddrBits.W)
16209c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
16309c6f1ddSLingrui98}
16409c6f1ddSLingrui98
165c2ad24ebSLingrui98// class FtqEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
166c2ad24ebSLingrui98//   val startAddr = UInt(VAddrBits.W)
167c2ad24ebSLingrui98//   val fallThruAddr = UInt(VAddrBits.W)
168c2ad24ebSLingrui98//   val isNextMask = Vec(PredictWidth, Bool())
16909c6f1ddSLingrui98
170c2ad24ebSLingrui98//   val meta = UInt(MaxMetaLength.W)
17109c6f1ddSLingrui98
172c2ad24ebSLingrui98//   val rasSp = UInt(log2Ceil(RasSize).W)
173c2ad24ebSLingrui98//   val rasEntry = new RASEntry
174c2ad24ebSLingrui98//   val hist = new ShiftingGlobalHistory
175c2ad24ebSLingrui98//   val specCnt = Vec(numBr, UInt(10.W))
17609c6f1ddSLingrui98
177c2ad24ebSLingrui98//   val valids = Vec(PredictWidth, Bool())
178c2ad24ebSLingrui98//   val brMask = Vec(PredictWidth, Bool())
179c2ad24ebSLingrui98//   // isJalr, isCall, isRet
180c2ad24ebSLingrui98//   val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
181c2ad24ebSLingrui98//   val jmpOffset = UInt(log2Ceil(PredictWidth).W)
18209c6f1ddSLingrui98
183c2ad24ebSLingrui98//   val mispredVec = Vec(PredictWidth, Bool())
184c2ad24ebSLingrui98//   val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
185c2ad24ebSLingrui98//   val target = UInt(VAddrBits.W)
186c2ad24ebSLingrui98// }
18709c6f1ddSLingrui98
18809c6f1ddSLingrui98class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
18909c6f1ddSLingrui98  val ptr = Output(new FtqPtr)
19009c6f1ddSLingrui98  val offset = Output(UInt(log2Ceil(PredictWidth).W))
19109c6f1ddSLingrui98  val data = Input(gen)
19209c6f1ddSLingrui98  def apply(ptr: FtqPtr, offset: UInt) = {
19309c6f1ddSLingrui98    this.ptr := ptr
19409c6f1ddSLingrui98    this.offset := offset
19509c6f1ddSLingrui98    this.data
19609c6f1ddSLingrui98  }
19709c6f1ddSLingrui98  override def cloneType = (new FtqRead(gen)).asInstanceOf[this.type]
19809c6f1ddSLingrui98}
19909c6f1ddSLingrui98
20009c6f1ddSLingrui98
20109c6f1ddSLingrui98class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
20209c6f1ddSLingrui98  val redirect = Valid(new BranchPredictionRedirect)
20309c6f1ddSLingrui98  val update = Valid(new BranchPredictionUpdate)
20409c6f1ddSLingrui98  val enq_ptr = Output(new FtqPtr)
20509c6f1ddSLingrui98}
20609c6f1ddSLingrui98
20709c6f1ddSLingrui98class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
20809c6f1ddSLingrui98  val req = Decoupled(new FetchRequestBundle)
20909c6f1ddSLingrui98  val redirect = Valid(new Redirect)
21009c6f1ddSLingrui98  val flushFromBpu = new Bundle {
21109c6f1ddSLingrui98    // when ifu pipeline is not stalled,
21209c6f1ddSLingrui98    // a packet from bpu s3 can reach f1 at most
21309c6f1ddSLingrui98    val s2 = Valid(new FtqPtr)
214cb4f77ceSLingrui98    val s3 = Valid(new FtqPtr)
21509c6f1ddSLingrui98    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
21609c6f1ddSLingrui98      src.valid && !isAfter(src.bits, idx_to_flush)
21709c6f1ddSLingrui98    }
21809c6f1ddSLingrui98    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
219cb4f77ceSLingrui98    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
22009c6f1ddSLingrui98  }
22109c6f1ddSLingrui98}
22209c6f1ddSLingrui98
22309c6f1ddSLingrui98trait HasBackendRedirectInfo extends HasXSParameter {
22409c6f1ddSLingrui98  def numRedirect = exuParameters.JmpCnt + exuParameters.AluCnt + 1
22509c6f1ddSLingrui98  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
22609c6f1ddSLingrui98}
22709c6f1ddSLingrui98
22809c6f1ddSLingrui98class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
22909c6f1ddSLingrui98  val pc_reads = Vec(1 + numRedirect + 1 + 1, Flipped(new FtqRead(UInt(VAddrBits.W))))
23009c6f1ddSLingrui98  val target_read = Flipped(new FtqRead(UInt(VAddrBits.W)))
23109c6f1ddSLingrui98  def getJumpPcRead = pc_reads.head
23209c6f1ddSLingrui98  def getRedirectPcRead = VecInit(pc_reads.tail.dropRight(2))
23309c6f1ddSLingrui98  def getMemPredPcRead = pc_reads.init.last
2349aca92b9SYinan Xu  def getRobFlushPcRead = pc_reads.last
23509c6f1ddSLingrui98}
23609c6f1ddSLingrui98
23709c6f1ddSLingrui98
23809c6f1ddSLingrui98class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
23909c6f1ddSLingrui98  val io = IO(new Bundle {
24009c6f1ddSLingrui98    val start_addr = Input(UInt(VAddrBits.W))
24109c6f1ddSLingrui98    val old_entry = Input(new FTBEntry)
24209c6f1ddSLingrui98    val pd = Input(new Ftq_pd_Entry)
24309c6f1ddSLingrui98    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
24409c6f1ddSLingrui98    val target = Input(UInt(VAddrBits.W))
24509c6f1ddSLingrui98    val hit = Input(Bool())
24609c6f1ddSLingrui98    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
24709c6f1ddSLingrui98
24809c6f1ddSLingrui98    val new_entry = Output(new FTBEntry)
24909c6f1ddSLingrui98    val new_br_insert_pos = Output(Vec(numBr, Bool()))
25009c6f1ddSLingrui98    val taken_mask = Output(Vec(numBr, Bool()))
25109c6f1ddSLingrui98    val mispred_mask = Output(Vec(numBr+1, Bool()))
25209c6f1ddSLingrui98
25309c6f1ddSLingrui98    // for perf counters
25409c6f1ddSLingrui98    val is_init_entry = Output(Bool())
25509c6f1ddSLingrui98    val is_old_entry = Output(Bool())
25609c6f1ddSLingrui98    val is_new_br = Output(Bool())
25709c6f1ddSLingrui98    val is_jalr_target_modified = Output(Bool())
25809c6f1ddSLingrui98    val is_always_taken_modified = Output(Bool())
25909c6f1ddSLingrui98    val is_br_full = Output(Bool())
26009c6f1ddSLingrui98  })
26109c6f1ddSLingrui98
26209c6f1ddSLingrui98  // no mispredictions detected at predecode
26309c6f1ddSLingrui98  val hit = io.hit
26409c6f1ddSLingrui98  val pd = io.pd
26509c6f1ddSLingrui98
26609c6f1ddSLingrui98  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
26709c6f1ddSLingrui98
26809c6f1ddSLingrui98
26909c6f1ddSLingrui98  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
27009c6f1ddSLingrui98  val entry_has_jmp = pd.jmpInfo.valid
27109c6f1ddSLingrui98  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
27209c6f1ddSLingrui98  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
27309c6f1ddSLingrui98  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
27409c6f1ddSLingrui98  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
27509c6f1ddSLingrui98  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
276*a60a2901SLingrui98  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
27709c6f1ddSLingrui98
27809c6f1ddSLingrui98  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
27909c6f1ddSLingrui98  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
28009c6f1ddSLingrui98
281*a60a2901SLingrui98  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
28209c6f1ddSLingrui98  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
28309c6f1ddSLingrui98  // if not hit, establish a new entry
28409c6f1ddSLingrui98  init_entry.valid := true.B
28509c6f1ddSLingrui98  // tag is left for ftb to assign
286eeb5ff92SLingrui98
287eeb5ff92SLingrui98  // case br
288eeb5ff92SLingrui98  val init_br_slot = init_entry.getSlotForBr(0)
289eeb5ff92SLingrui98  when (cfi_is_br) {
290eeb5ff92SLingrui98    init_br_slot.valid := true.B
291eeb5ff92SLingrui98    init_br_slot.offset := io.cfiIndex.bits
292b37e4b45SLingrui98    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
293eeb5ff92SLingrui98    init_entry.always_taken(0) := true.B // set to always taken on init
294eeb5ff92SLingrui98  }
295eeb5ff92SLingrui98
296eeb5ff92SLingrui98  // case jmp
297eeb5ff92SLingrui98  when (entry_has_jmp) {
298eeb5ff92SLingrui98    init_entry.tailSlot.offset := pd.jmpOffset
299eeb5ff92SLingrui98    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
300eeb5ff92SLingrui98    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
301eeb5ff92SLingrui98  }
302eeb5ff92SLingrui98
30309c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
304*a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
305*a60a2901SLingrui98  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
30609c6f1ddSLingrui98  init_entry.isJalr := new_jmp_is_jalr
30709c6f1ddSLingrui98  init_entry.isCall := new_jmp_is_call
30809c6f1ddSLingrui98  init_entry.isRet  := new_jmp_is_ret
309*a60a2901SLingrui98  init_entry.last_is_rvc := DontCare
31009c6f1ddSLingrui98
31109c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
31209c6f1ddSLingrui98  val oe = io.old_entry
313eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
31409c6f1ddSLingrui98  val br_recorded = br_recorded_vec.asUInt.orR
31509c6f1ddSLingrui98  val is_new_br = cfi_is_br && !br_recorded
31609c6f1ddSLingrui98  val new_br_offset = io.cfiIndex.bits
31709c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
318eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
31909c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map{
32009c6f1ddSLingrui98    i => i match {
321eeb5ff92SLingrui98      case 0 =>
322eeb5ff92SLingrui98        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
323eeb5ff92SLingrui98      case idx =>
324eeb5ff92SLingrui98        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
325eeb5ff92SLingrui98        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
32609c6f1ddSLingrui98    }
32709c6f1ddSLingrui98  })
32809c6f1ddSLingrui98
32909c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
33009c6f1ddSLingrui98  for (i <- 0 until numBr) {
331eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
332eeb5ff92SLingrui98    when (new_br_insert_onehot(i)) {
333eeb5ff92SLingrui98      slot.valid := true.B
334eeb5ff92SLingrui98      slot.offset := new_br_offset
335b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
336eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := true.B
337eeb5ff92SLingrui98    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
338eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := false.B
339eeb5ff92SLingrui98      // all other fields remain unchanged
340eeb5ff92SLingrui98    }.otherwise {
341eeb5ff92SLingrui98      // case i == 0, remain unchanged
342eeb5ff92SLingrui98      if (i != 0) {
343b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
344eeb5ff92SLingrui98        when (!noNeedToMoveFromFormerSlot) {
345eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
346eeb5ff92SLingrui98          old_entry_modified.always_taken(i) := oe.always_taken(i)
34709c6f1ddSLingrui98        }
348eeb5ff92SLingrui98      }
349eeb5ff92SLingrui98    }
350eeb5ff92SLingrui98  }
35109c6f1ddSLingrui98
352eeb5ff92SLingrui98  // two circumstances:
353eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
354eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
355eeb5ff92SLingrui98  //        the previous last br or the new br
356eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
357eeb5ff92SLingrui98  val pft_need_to_change = is_new_br && may_have_to_replace
35809c6f1ddSLingrui98  // it should either be the given last br or the new br
35909c6f1ddSLingrui98  when (pft_need_to_change) {
360eeb5ff92SLingrui98    val new_pft_offset =
361710a8720SLingrui98      Mux(!new_br_insert_onehot.asUInt.orR,
362710a8720SLingrui98        new_br_offset, oe.allSlotsForBr.last.offset)
363eeb5ff92SLingrui98
364710a8720SLingrui98    // set jmp to invalid
36509c6f1ddSLingrui98    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
36609c6f1ddSLingrui98    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
36709c6f1ddSLingrui98    old_entry_modified.isCall := false.B
36809c6f1ddSLingrui98    old_entry_modified.isRet := false.B
369eeb5ff92SLingrui98    old_entry_modified.isJalr := false.B
37009c6f1ddSLingrui98  }
37109c6f1ddSLingrui98
37209c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
373710a8720SLingrui98  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
374b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
375eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3763bcae573SLingrui98  when (jalr_target_modified) {
37709c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
37809c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
37909c6f1ddSLingrui98  }
38009c6f1ddSLingrui98
38109c6f1ddSLingrui98  val old_entry_always_taken = WireInit(oe)
38209c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
38309c6f1ddSLingrui98  for (i <- 0 until numBr) {
38409c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
38509c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
386710a8720SLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
38709c6f1ddSLingrui98  }
38809c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
38909c6f1ddSLingrui98
39009c6f1ddSLingrui98
39109c6f1ddSLingrui98
39209c6f1ddSLingrui98  val derived_from_old_entry =
39309c6f1ddSLingrui98    Mux(is_new_br, old_entry_modified,
3943bcae573SLingrui98      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
39509c6f1ddSLingrui98
39609c6f1ddSLingrui98
39709c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
39809c6f1ddSLingrui98
39909c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
40009c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
40109c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
40209c6f1ddSLingrui98  })
40309c6f1ddSLingrui98  for (i <- 0 until numBr) {
40409c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
40509c6f1ddSLingrui98  }
40609c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
40709c6f1ddSLingrui98
40809c6f1ddSLingrui98  // for perf counters
40909c6f1ddSLingrui98  io.is_init_entry := !hit
4103bcae573SLingrui98  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
41109c6f1ddSLingrui98  io.is_new_br := hit && is_new_br
4123bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
41309c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
414eeb5ff92SLingrui98  io.is_br_full := hit && is_new_br && may_have_to_replace
41509c6f1ddSLingrui98}
41609c6f1ddSLingrui98
41709c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
418e30430c2SJay  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
419e30430c2SJay  with HasICacheParameters{
42009c6f1ddSLingrui98  val io = IO(new Bundle {
42109c6f1ddSLingrui98    val fromBpu = Flipped(new BpuToFtqIO)
42209c6f1ddSLingrui98    val fromIfu = Flipped(new IfuToFtqIO)
42309c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
42409c6f1ddSLingrui98
42509c6f1ddSLingrui98    val toBpu = new FtqToBpuIO
42609c6f1ddSLingrui98    val toIfu = new FtqToIfuIO
42709c6f1ddSLingrui98    val toBackend = new FtqToCtrlIO
42809c6f1ddSLingrui98
4297052722fSJay    val toPrefetch = new FtqPrefechBundle
4307052722fSJay
43109c6f1ddSLingrui98    val bpuInfo = new Bundle {
43209c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
43309c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
43409c6f1ddSLingrui98    }
43509c6f1ddSLingrui98  })
43609c6f1ddSLingrui98  io.bpuInfo := DontCare
43709c6f1ddSLingrui98
438df5b4b8eSYinan Xu  val backendRedirect = io.fromBackend.redirect
439df5b4b8eSYinan Xu  val backendRedirectReg = RegNext(io.fromBackend.redirect)
44009c6f1ddSLingrui98
441df5b4b8eSYinan Xu  val stage2Flush = backendRedirect.valid
44209c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
44309c6f1ddSLingrui98  val ifuFlush = Wire(Bool())
44409c6f1ddSLingrui98
44509c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
44609c6f1ddSLingrui98
44709c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
44809c6f1ddSLingrui98  val flushToIfu = !allowToIfu
449df5b4b8eSYinan Xu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
450df5b4b8eSYinan Xu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
45109c6f1ddSLingrui98
452e30430c2SJay  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
45309c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
45409c6f1ddSLingrui98
45509c6f1ddSLingrui98  // **********************************************************************
45609c6f1ddSLingrui98  // **************************** enq from bpu ****************************
45709c6f1ddSLingrui98  // **********************************************************************
45809c6f1ddSLingrui98  val new_entry_ready = validEntries < FtqSize.U
45909c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
46009c6f1ddSLingrui98
46109c6f1ddSLingrui98  val bpu_s2_resp = io.fromBpu.resp.bits.s2
462cb4f77ceSLingrui98  val bpu_s3_resp = io.fromBpu.resp.bits.s3
46309c6f1ddSLingrui98  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
464cb4f77ceSLingrui98  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
46509c6f1ddSLingrui98
46609c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
46709c6f1ddSLingrui98  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
468cb4f77ceSLingrui98  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
46909c6f1ddSLingrui98
470b37e4b45SLingrui98  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
471b37e4b45SLingrui98  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx
47209c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
47309c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
47409c6f1ddSLingrui98
4759aca92b9SYinan Xu  // read ports:                            jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate
47609c6f1ddSLingrui98  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1))
47709c6f1ddSLingrui98  // resp from uBTB
47809c6f1ddSLingrui98  ftq_pc_mem.io.wen(0) := bpu_in_fire
47909c6f1ddSLingrui98  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
48009c6f1ddSLingrui98  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
48109c6f1ddSLingrui98
48209c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
48309c6f1ddSLingrui98  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
48409c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
48509c6f1ddSLingrui98  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
48609c6f1ddSLingrui98  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
48709c6f1ddSLingrui98  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
48849cbc998SLingrui98  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
48949cbc998SLingrui98  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
49009c6f1ddSLingrui98
49109c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
49209c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
49309c6f1ddSLingrui98  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
49409c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
49509c6f1ddSLingrui98  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
49609c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
49709c6f1ddSLingrui98  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
49809c6f1ddSLingrui98  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
49909c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
50009c6f1ddSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
50109c6f1ddSLingrui98
50209c6f1ddSLingrui98
50309c6f1ddSLingrui98  // multi-write
504b37e4b45SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough
50509c6f1ddSLingrui98  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
50609c6f1ddSLingrui98  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
50709c6f1ddSLingrui98  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
50809c6f1ddSLingrui98
50909c6f1ddSLingrui98  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
51009c6f1ddSLingrui98  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
51109c6f1ddSLingrui98    VecInit(Seq.fill(PredictWidth)(c_invalid))
51209c6f1ddSLingrui98  }))
51309c6f1ddSLingrui98
51409c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
51509c6f1ddSLingrui98  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
51609c6f1ddSLingrui98
51709c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
51809c6f1ddSLingrui98  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
51909c6f1ddSLingrui98
52009c6f1ddSLingrui98
52109c6f1ddSLingrui98  when (bpu_in_fire) {
52209c6f1ddSLingrui98    entry_fetch_status(bpu_in_resp_idx) := f_to_send
52309c6f1ddSLingrui98    commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
524b37e4b45SLingrui98    cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.cfiIndex
52509c6f1ddSLingrui98    mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
526b37e4b45SLingrui98    update_target(bpu_in_resp_idx) := bpu_in_resp.getTarget
52709c6f1ddSLingrui98    pred_stage(bpu_in_resp_idx) := bpu_in_stage
52809c6f1ddSLingrui98  }
52909c6f1ddSLingrui98
53009c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
5317bb9fc10SLingrui98  ifuPtr := ifuPtr + (io.toIfu.req.fire && allowToIfu)
53209c6f1ddSLingrui98
53309c6f1ddSLingrui98  // only use ftb result to assign hit status
53409c6f1ddSLingrui98  when (bpu_s2_resp.valid) {
535b37e4b45SLingrui98    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit)
53609c6f1ddSLingrui98  }
53709c6f1ddSLingrui98
53809c6f1ddSLingrui98
5392f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
54009c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
54109c6f1ddSLingrui98  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
54209c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
54309c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
54409c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
54509c6f1ddSLingrui98      ifuPtr := bpu_s2_resp.ftq_idx
54609c6f1ddSLingrui98    }
54709c6f1ddSLingrui98  }
54809c6f1ddSLingrui98
549cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
550cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
551cb4f77ceSLingrui98  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
552cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
553cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
554cb4f77ceSLingrui98    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
555cb4f77ceSLingrui98      ifuPtr := bpu_s3_resp.ftq_idx
556cb4f77ceSLingrui98    }
557cb4f77ceSLingrui98  }
558cb4f77ceSLingrui98
55909c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
56009c6f1ddSLingrui98
56109c6f1ddSLingrui98  // ****************************************************************
56209c6f1ddSLingrui98  // **************************** to ifu ****************************
56309c6f1ddSLingrui98  // ****************************************************************
56409c6f1ddSLingrui98  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire)
56509c6f1ddSLingrui98  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
56609c6f1ddSLingrui98  val last_cycle_bpu_in = RegNext(bpu_in_fire)
56709c6f1ddSLingrui98  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
56809c6f1ddSLingrui98
56909c6f1ddSLingrui98  // read pc and target
57009c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
57109c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value
57209c6f1ddSLingrui98
5737bb9fc10SLingrui98  io.toIfu.req.valid := entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr
5745ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
575b37e4b45SLingrui98  io.toIfu.req.bits.nextStartAddr := update_target(ifuPtr.value)
5765ff19bd8SLingrui98  io.toIfu.req.bits.ftqOffset := cfiIndex_vec(ifuPtr.value)
57709c6f1ddSLingrui98
578b37e4b45SLingrui98  val toIfuPcBundle = Wire(new Ftq_RF_Components)
5797052722fSJay
58009c6f1ddSLingrui98  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
581b37e4b45SLingrui98    toIfuPcBundle := bpu_in_bypass_buf
58209c6f1ddSLingrui98  }.elsewhen (last_cycle_to_ifu_fire) {
583b37e4b45SLingrui98    toIfuPcBundle := ftq_pc_mem.io.rdata.init.last
58409c6f1ddSLingrui98  }.otherwise {
585b37e4b45SLingrui98    toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last
58609c6f1ddSLingrui98  }
58709c6f1ddSLingrui98
588b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
589b37e4b45SLingrui98
59009c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
591b37e4b45SLingrui98  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
59209c6f1ddSLingrui98    when (io.toIfu.req.fire &&
593cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
594cb4f77ceSLingrui98      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
59509c6f1ddSLingrui98    ) {
59609c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
597352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
59809c6f1ddSLingrui98    }
599b37e4b45SLingrui98    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
60009c6f1ddSLingrui98  }
60109c6f1ddSLingrui98
602*a60a2901SLingrui98  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
603*a60a2901SLingrui98    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
604*a60a2901SLingrui98
60509c6f1ddSLingrui98  val ifu_req_should_be_flushed =
606cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
607cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
60809c6f1ddSLingrui98
60909c6f1ddSLingrui98    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
61009c6f1ddSLingrui98      entry_fetch_status(ifuPtr.value) := f_sent
61109c6f1ddSLingrui98    }
61209c6f1ddSLingrui98
61309c6f1ddSLingrui98  // *********************************************************************
61409c6f1ddSLingrui98  // **************************** wb from ifu ****************************
61509c6f1ddSLingrui98  // *********************************************************************
61609c6f1ddSLingrui98  val pdWb = io.fromIfu.pdWb
61709c6f1ddSLingrui98  val pds = pdWb.bits.pd
61809c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
61909c6f1ddSLingrui98  val ifu_wb_idx = pdWb.bits.ftqIdx.value
62009c6f1ddSLingrui98  // read ports:                                                         commit update
62109c6f1ddSLingrui98  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
62209c6f1ddSLingrui98  ftq_pd_mem.io.wen(0) := ifu_wb_valid
62309c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
62409c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
62509c6f1ddSLingrui98
62609c6f1ddSLingrui98  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
62709c6f1ddSLingrui98  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
62809c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
62909c6f1ddSLingrui98  val pd_reg       = RegEnable(pds,             enable = pdWb.valid)
63009c6f1ddSLingrui98  val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid)
63109c6f1ddSLingrui98  val wb_idx_reg   = RegEnable(ifu_wb_idx,      enable = pdWb.valid)
63209c6f1ddSLingrui98
63309c6f1ddSLingrui98  when (ifu_wb_valid) {
63409c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
63509c6f1ddSLingrui98      case (v, inRange) => v && inRange
63609c6f1ddSLingrui98    })
63709c6f1ddSLingrui98    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
63809c6f1ddSLingrui98      case (qe, v) => when (v) { qe := c_valid }
63909c6f1ddSLingrui98    }
64009c6f1ddSLingrui98  }
64109c6f1ddSLingrui98
64209c6f1ddSLingrui98  ifuWbPtr := ifuWbPtr + ifu_wb_valid
64309c6f1ddSLingrui98
64409c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := ifu_wb_idx
64509c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
64609c6f1ddSLingrui98  when (RegNext(hit_pd_valid)) {
64709c6f1ddSLingrui98    // check for false hit
64809c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
649eeb5ff92SLingrui98    val brSlots = pred_ftb_entry.brSlots
650eeb5ff92SLingrui98    val tailSlot = pred_ftb_entry.tailSlot
65109c6f1ddSLingrui98    // we check cfis that bpu predicted
65209c6f1ddSLingrui98
653eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
654eeb5ff92SLingrui98    val br_false_hit =
655eeb5ff92SLingrui98      brSlots.map{
656eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
657eeb5ff92SLingrui98      }.reduce(_||_) ||
658b37e4b45SLingrui98      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
659eeb5ff92SLingrui98        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
660eeb5ff92SLingrui98
661eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
66209c6f1ddSLingrui98    val jmp_pd = pd_reg(jmpOffset)
66309c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
66409c6f1ddSLingrui98      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
66509c6f1ddSLingrui98       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
66609c6f1ddSLingrui98       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
66709c6f1ddSLingrui98       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
66809c6f1ddSLingrui98      )
66909c6f1ddSLingrui98
67009c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
67165fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
67265fddcf0Szoujr
673352db50aSLingrui98    // assert(!has_false_hit)
67409c6f1ddSLingrui98  }
67509c6f1ddSLingrui98
67609c6f1ddSLingrui98  when (has_false_hit) {
67709c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
67809c6f1ddSLingrui98  }
67909c6f1ddSLingrui98
68009c6f1ddSLingrui98
68109c6f1ddSLingrui98  // **********************************************************************
68209c6f1ddSLingrui98  // **************************** backend read ****************************
68309c6f1ddSLingrui98  // **********************************************************************
68409c6f1ddSLingrui98
68509c6f1ddSLingrui98  // pc reads
68609c6f1ddSLingrui98  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
68709c6f1ddSLingrui98    ftq_pc_mem.io.raddr(i) := req.ptr.value
68809c6f1ddSLingrui98    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
68909c6f1ddSLingrui98  }
69009c6f1ddSLingrui98  // target read
69109c6f1ddSLingrui98  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
69209c6f1ddSLingrui98
69309c6f1ddSLingrui98  // *******************************************************************************
69409c6f1ddSLingrui98  // **************************** redirect from backend ****************************
69509c6f1ddSLingrui98  // *******************************************************************************
69609c6f1ddSLingrui98
69709c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
698df5b4b8eSYinan Xu  ftq_redirect_sram.io.ren.init.last := io.fromBackend.redirect.valid
699df5b4b8eSYinan Xu  ftq_redirect_sram.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value
70009c6f1ddSLingrui98
701df5b4b8eSYinan Xu  ftb_entry_mem.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value
70209c6f1ddSLingrui98
70309c6f1ddSLingrui98  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
704df5b4b8eSYinan Xu  val fromBackendRedirect = WireInit(backendRedirectReg)
70509c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
70609c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
70709c6f1ddSLingrui98
70809c6f1ddSLingrui98  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
70909c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
71009c6f1ddSLingrui98
71109c6f1ddSLingrui98  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
71209c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
71309c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
714eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
71509c6f1ddSLingrui98
71609c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
717eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
71809c6f1ddSLingrui98  }.otherwise {
71909c6f1ddSLingrui98    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
72009c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
72109c6f1ddSLingrui98  }
72209c6f1ddSLingrui98
72309c6f1ddSLingrui98
72409c6f1ddSLingrui98  // ***************************************************************************
72509c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
72609c6f1ddSLingrui98  // ***************************************************************************
72709c6f1ddSLingrui98  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
72809c6f1ddSLingrui98  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
72909c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
73009c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
73109c6f1ddSLingrui98  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
73209c6f1ddSLingrui98
73309c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
73409c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
73509c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
73609c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
73709c6f1ddSLingrui98  ifuRedirectCfiUpdate.target := pdWb.bits.target
73809c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
73909c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
74009c6f1ddSLingrui98
74109c6f1ddSLingrui98  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
74209c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
74309c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
74409c6f1ddSLingrui98
74509c6f1ddSLingrui98  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
74609c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
74709c6f1ddSLingrui98
74809c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
74909c6f1ddSLingrui98
75009c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
75109c6f1ddSLingrui98  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
75209c6f1ddSLingrui98  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
75309c6f1ddSLingrui98    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
75409c6f1ddSLingrui98  }
75509c6f1ddSLingrui98
75609c6f1ddSLingrui98  // *********************************************************************
75709c6f1ddSLingrui98  // **************************** wb from exu ****************************
75809c6f1ddSLingrui98  // *********************************************************************
75909c6f1ddSLingrui98
76009c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
76109c6f1ddSLingrui98    val ftqIdx = wb.bits.ftqIdx.value
76209c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
76309c6f1ddSLingrui98    val taken = wb.bits.cfiUpdate.taken
76409c6f1ddSLingrui98    val mispred = wb.bits.cfiUpdate.isMisPred
76509c6f1ddSLingrui98    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
76609c6f1ddSLingrui98  }
76709c6f1ddSLingrui98
76809c6f1ddSLingrui98  // fix mispredict entry
76909c6f1ddSLingrui98  val lastIsMispredict = RegNext(
770df5b4b8eSYinan Xu    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
77109c6f1ddSLingrui98  )
77209c6f1ddSLingrui98
77309c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
77409c6f1ddSLingrui98    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
77509c6f1ddSLingrui98    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
77609c6f1ddSLingrui98    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
77709c6f1ddSLingrui98    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
77809c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
77909c6f1ddSLingrui98    }
78009c6f1ddSLingrui98    when (cfiIndex_bits_wen) {
78109c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
78209c6f1ddSLingrui98    }
78309c6f1ddSLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target
78409c6f1ddSLingrui98    if (isBackend) {
78509c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
78609c6f1ddSLingrui98    }
78709c6f1ddSLingrui98  }
78809c6f1ddSLingrui98
789df5b4b8eSYinan Xu  when(backendRedirectReg.valid && lastIsMispredict) {
790df5b4b8eSYinan Xu    updateCfiInfo(backendRedirectReg)
79109c6f1ddSLingrui98  }.elsewhen (ifuRedirectToBpu.valid) {
79209c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
79309c6f1ddSLingrui98  }
79409c6f1ddSLingrui98
79509c6f1ddSLingrui98  // ***********************************************************************************
79609c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
79709c6f1ddSLingrui98  // ***********************************************************************************
79809c6f1ddSLingrui98
799df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
80009c6f1ddSLingrui98
80109c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
80209c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_||_)){
8032f4a3aa4SLingrui98    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
80409c6f1ddSLingrui98    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
8052f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
80609c6f1ddSLingrui98    val next = idx + 1.U
80709c6f1ddSLingrui98    bpuPtr := next
80809c6f1ddSLingrui98    ifuPtr := next
80909c6f1ddSLingrui98    ifuWbPtr := next
81009c6f1ddSLingrui98    when (notIfu) {
81109c6f1ddSLingrui98      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
81209c6f1ddSLingrui98        when(i.U > offset || i.U === offset && flushItSelf){
81309c6f1ddSLingrui98          s := c_invalid
81409c6f1ddSLingrui98        }
81509c6f1ddSLingrui98      })
81609c6f1ddSLingrui98    }
81709c6f1ddSLingrui98  }
81809c6f1ddSLingrui98
81909c6f1ddSLingrui98  // only the valid bit is actually needed
820df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
82109c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
82209c6f1ddSLingrui98
82309c6f1ddSLingrui98  // commit
8249aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
82509c6f1ddSLingrui98    when(c.valid) {
82609c6f1ddSLingrui98      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
82788825c5cSYinan Xu      // TODO: remove this
82888825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
829c3abb8b6SYinan Xu      when (c.bits.commitType === 4.U) {
83088825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
831c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
83288825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
833c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
83488825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
83588825c5cSYinan Xu        commitStateQueue(index)(0) := c_commited
836c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
83788825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
83888825c5cSYinan Xu        commitStateQueue(index)(1) := c_commited
83988825c5cSYinan Xu      }
84009c6f1ddSLingrui98    }
84109c6f1ddSLingrui98  }
84209c6f1ddSLingrui98
84309c6f1ddSLingrui98  // ****************************************************************
84409c6f1ddSLingrui98  // **************************** to bpu ****************************
84509c6f1ddSLingrui98  // ****************************************************************
84609c6f1ddSLingrui98
84709c6f1ddSLingrui98  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
84809c6f1ddSLingrui98
8495371700eSzoujr  val may_have_stall_from_bpu = RegInit(false.B)
8505371700eSzoujr  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
85109c6f1ddSLingrui98    Cat(commitStateQueue(commPtr.value).map(s => {
85209c6f1ddSLingrui98      s === c_invalid || s === c_commited
85309c6f1ddSLingrui98    })).andR()
85409c6f1ddSLingrui98
85509c6f1ddSLingrui98  // commit reads
85609c6f1ddSLingrui98  ftq_pc_mem.io.raddr.last := commPtr.value
85709c6f1ddSLingrui98  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
85809c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last := commPtr.value
85909c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
86009c6f1ddSLingrui98  ftq_redirect_sram.io.ren.last := canCommit
86109c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.last := commPtr.value
86209c6f1ddSLingrui98  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
86309c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0) := canCommit
86409c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
86509c6f1ddSLingrui98  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
86609c6f1ddSLingrui98  ftb_entry_mem.io.raddr.last := commPtr.value
86709c6f1ddSLingrui98  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
86809c6f1ddSLingrui98
86909c6f1ddSLingrui98  // need one cycle to read mem and srams
87009c6f1ddSLingrui98  val do_commit_ptr = RegNext(commPtr)
8715371700eSzoujr  val do_commit = RegNext(canCommit, init=false.B)
87209c6f1ddSLingrui98  when (canCommit) { commPtr := commPtr + 1.U }
87309c6f1ddSLingrui98  val commit_state = RegNext(commitStateQueue(commPtr.value))
8745371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
8755371700eSzoujr  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
8765371700eSzoujr    can_commit_cfi.valid := false.B
87709c6f1ddSLingrui98  }
8785371700eSzoujr  val commit_cfi = RegNext(can_commit_cfi)
87909c6f1ddSLingrui98
88009c6f1ddSLingrui98  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
88109c6f1ddSLingrui98    case (mis, state) => mis && state === c_commited
88209c6f1ddSLingrui98  })
8835371700eSzoujr  val can_commit_hit = entry_hit_status(commPtr.value)
8845371700eSzoujr  val commit_hit = RegNext(can_commit_hit)
88509c6f1ddSLingrui98  val commit_target = RegNext(update_target(commPtr.value))
886edc18578SLingrui98  val commit_stage = RegNext(pred_stage(commPtr.value))
88709c6f1ddSLingrui98  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
88809c6f1ddSLingrui98
8895371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
8901c8d9e26Szoujr  may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu
89109c6f1ddSLingrui98
89209c6f1ddSLingrui98  io.toBpu.update := DontCare
89309c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
89409c6f1ddSLingrui98  val update = io.toBpu.update.bits
89509c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
89609c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
89709c6f1ddSLingrui98  update.meta        := commit_meta.meta
8988ffcd86aSLingrui98  update.full_target := commit_target
899edc18578SLingrui98  update.from_stage  := commit_stage
90009c6f1ddSLingrui98  update.fromFtqRedirectSram(commit_spec_meta)
90109c6f1ddSLingrui98
90209c6f1ddSLingrui98  val commit_real_hit = commit_hit === h_hit
90309c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
90409c6f1ddSLingrui98
90509c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
90609c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
90709c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
90809c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
90909c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
91009c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
91109c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
91209c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
91309c6f1ddSLingrui98
91409c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
91509c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
91609c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
91709c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
918edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
919b37e4b45SLingrui98
920b37e4b45SLingrui98  update.is_minimal := false.B
921b37e4b45SLingrui98  update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
922b37e4b45SLingrui98  update.full_pred.br_taken_mask  := ftbEntryGen.taken_mask
923b37e4b45SLingrui98  update.full_pred.jalr_target := commit_target
924b37e4b45SLingrui98  update.full_pred.hit := true.B
925b37e4b45SLingrui98  when (update.full_pred.is_jalr) {
926b37e4b45SLingrui98    update.full_pred.targets.last := commit_target
927b37e4b45SLingrui98  }
92809c6f1ddSLingrui98
929e30430c2SJay  // ****************************************************************
930e30430c2SJay  // *********************** to prefetch ****************************
931e30430c2SJay  // ****************************************************************
932e30430c2SJay
933e30430c2SJay  if(cacheParams.hasPrefetch){
934e30430c2SJay    val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
935e30430c2SJay    prefetchPtr := prefetchPtr + io.toPrefetch.req.fire()
936e30430c2SJay
937e30430c2SJay    when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) {
938e30430c2SJay      prefetchPtr := bpu_s2_resp.ftq_idx
939e30430c2SJay    }
940e30430c2SJay
941cb4f77ceSLingrui98    when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) {
942cb4f77ceSLingrui98      prefetchPtr := bpu_s3_resp.ftq_idx
943a3c55791SJinYue      // XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
944cb4f77ceSLingrui98    }
945de7689fcSJay
946259b970fSJinYue    io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send
947de7689fcSJay    io.toPrefetch.req.bits.target := update_target(prefetchPtr.value)
948de7689fcSJay
949de7689fcSJay    when(redirectVec.map(r => r.valid).reduce(_||_)){
950de7689fcSJay      val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
951de7689fcSJay      val next = r.ftqIdx + 1.U
952de7689fcSJay      prefetchPtr := next
953de7689fcSJay    }
954de7689fcSJay
955de7689fcSJay    XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n")
956de7689fcSJay  }
957de7689fcSJay  else {
958de7689fcSJay    io.toPrefetch.req <> DontCare
959de7689fcSJay  }
960de7689fcSJay
96109c6f1ddSLingrui98  // ******************************************************************************
96209c6f1ddSLingrui98  // **************************** commit perf counters ****************************
96309c6f1ddSLingrui98  // ******************************************************************************
96409c6f1ddSLingrui98
96509c6f1ddSLingrui98  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
96609c6f1ddSLingrui98  val commit_mispred_mask = commit_mispredict.asUInt
96709c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
96809c6f1ddSLingrui98
96909c6f1ddSLingrui98  val commit_br_mask = commit_pd.brMask.asUInt
97009c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
97109c6f1ddSLingrui98  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
97209c6f1ddSLingrui98
97309c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
97409c6f1ddSLingrui98
97509c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
97609c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
97709c6f1ddSLingrui98
97809c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
97909c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
98009c6f1ddSLingrui98
98109c6f1ddSLingrui98  // Cfi Info
98209c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
98309c6f1ddSLingrui98    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
98409c6f1ddSLingrui98    val v = commit_state(i) === c_commited
98509c6f1ddSLingrui98    val isBr = commit_pd.brMask(i)
98609c6f1ddSLingrui98    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
98709c6f1ddSLingrui98    val isCfi = isBr || isJmp
98809c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
98909c6f1ddSLingrui98    val misPred = commit_mispredict(i)
990c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
991c2ad24ebSLingrui98    val histPtr = commit_spec_meta.histPtr
99209c6f1ddSLingrui98    val predCycle = commit_meta.meta(63, 0)
99309c6f1ddSLingrui98    val target = commit_target
99409c6f1ddSLingrui98
99509c6f1ddSLingrui98    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
99609c6f1ddSLingrui98    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
99709c6f1ddSLingrui98    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
99809c6f1ddSLingrui98    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
999c2ad24ebSLingrui98    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
100009c6f1ddSLingrui98    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
100109c6f1ddSLingrui98    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
100209c6f1ddSLingrui98  }
100309c6f1ddSLingrui98
100409c6f1ddSLingrui98  val enq = io.fromBpu.resp
1005df5b4b8eSYinan Xu  val perf_redirect = io.fromBackend.redirect
100609c6f1ddSLingrui98
100709c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
100809c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
100909c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
101009c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
101109c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
101209c6f1ddSLingrui98
101309c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
101409c6f1ddSLingrui98
101509c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
101609c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
101712cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
101809c6f1ddSLingrui98
101909c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
102009c6f1ddSLingrui98  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
1021b37e4b45SLingrui98    assert(!resp.is_minimal)
102209c6f1ddSLingrui98    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
102309c6f1ddSLingrui98    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
102409c6f1ddSLingrui98    val entry_len_map = (1 to PredictWidth+1).map(i =>
102509c6f1ddSLingrui98      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
102609c6f1ddSLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
102709c6f1ddSLingrui98    entry_len_map
102809c6f1ddSLingrui98  }
102909c6f1ddSLingrui98  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
1030cb4f77ceSLingrui98  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
103109c6f1ddSLingrui98
103209c6f1ddSLingrui98  val to_ifu = io.toIfu.req.bits
103309c6f1ddSLingrui98
103409c6f1ddSLingrui98
103509c6f1ddSLingrui98
103609c6f1ddSLingrui98  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
103709c6f1ddSLingrui98  val commit_num_inst_map = (1 to PredictWidth).map(i =>
103809c6f1ddSLingrui98    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
103909c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
104009c6f1ddSLingrui98
104109c6f1ddSLingrui98
104209c6f1ddSLingrui98
104309c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
104409c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
104509c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
104609c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
104709c6f1ddSLingrui98
104809c6f1ddSLingrui98
104909c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
105009c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
105109c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
105209c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
105309c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
105409c6f1ddSLingrui98
105509c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
105609c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
105709c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
105809c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
105909c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
106009c6f1ddSLingrui98
10611d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
10621d7e5011SLingrui98
10631d7e5011SLingrui98  def pred_stage_map(src: UInt, name: String) = {
10641d7e5011SLingrui98    (0 until numBpStages).map(i =>
10651d7e5011SLingrui98      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
10661d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
10671d7e5011SLingrui98  }
10681d7e5011SLingrui98
10691d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
10701d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
10711d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
10721d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
10731d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
10741d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
10751d7e5011SLingrui98
107609c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
107709c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
107809c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
107965fddcf0Szoujr  // assert(!ftb_false_hit)
108009c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
108109c6f1ddSLingrui98
108209c6f1ddSLingrui98  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1083b37e4b45SLingrui98  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1084b37e4b45SLingrui98  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1085b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
108609c6f1ddSLingrui98
108709c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
108809c6f1ddSLingrui98
108909c6f1ddSLingrui98  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
109009c6f1ddSLingrui98  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
109109c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
109209c6f1ddSLingrui98  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
109309c6f1ddSLingrui98  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
109409c6f1ddSLingrui98
109509c6f1ddSLingrui98  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
109609c6f1ddSLingrui98  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
109709c6f1ddSLingrui98  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
109809c6f1ddSLingrui98    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
109909c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
110009c6f1ddSLingrui98  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
110109c6f1ddSLingrui98    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
110209c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
110309c6f1ddSLingrui98
110409c6f1ddSLingrui98  val ftq_occupancy_map = (0 to FtqSize).map(i =>
110509c6f1ddSLingrui98    f"ftq_has_entry_$i" ->( validEntries === i.U)
110609c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
110709c6f1ddSLingrui98
110809c6f1ddSLingrui98  val perfCountsMap = Map(
110909c6f1ddSLingrui98    "BpInstr" -> PopCount(mbpInstrs),
111009c6f1ddSLingrui98    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
111109c6f1ddSLingrui98    "BpRight"  -> PopCount(mbpRights),
111209c6f1ddSLingrui98    "BpWrong"  -> PopCount(mbpWrongs),
111309c6f1ddSLingrui98    "BpBRight" -> PopCount(mbpBRights),
111409c6f1ddSLingrui98    "BpBWrong" -> PopCount(mbpBWrongs),
111509c6f1ddSLingrui98    "BpJRight" -> PopCount(mbpJRights),
111609c6f1ddSLingrui98    "BpJWrong" -> PopCount(mbpJWrongs),
111709c6f1ddSLingrui98    "BpIRight" -> PopCount(mbpIRights),
111809c6f1ddSLingrui98    "BpIWrong" -> PopCount(mbpIWrongs),
111909c6f1ddSLingrui98    "BpCRight" -> PopCount(mbpCRights),
112009c6f1ddSLingrui98    "BpCWrong" -> PopCount(mbpCWrongs),
112109c6f1ddSLingrui98    "BpRRight" -> PopCount(mbpRRights),
112209c6f1ddSLingrui98    "BpRWrong" -> PopCount(mbpRWrongs),
112309c6f1ddSLingrui98
112409c6f1ddSLingrui98    "ftb_false_hit"                -> PopCount(ftb_false_hit),
112509c6f1ddSLingrui98    "ftb_hit"                      -> PopCount(ftb_hit),
112609c6f1ddSLingrui98    "ftb_new_entry"                -> PopCount(ftb_new_entry),
112709c6f1ddSLingrui98    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
112809c6f1ddSLingrui98    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
112909c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
113009c6f1ddSLingrui98    "ftb_old_entry"                -> PopCount(ftb_old_entry),
113109c6f1ddSLingrui98    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
113209c6f1ddSLingrui98    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
113309c6f1ddSLingrui98    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
113409c6f1ddSLingrui98    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
113509c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
11366d0e92edSLingrui98  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++
1137cb4f77ceSLingrui98  s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++
11381d7e5011SLingrui98  mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
11391d7e5011SLingrui98  correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
114009c6f1ddSLingrui98
114109c6f1ddSLingrui98  for((key, value) <- perfCountsMap) {
114209c6f1ddSLingrui98    XSPerfAccumulate(key, value)
114309c6f1ddSLingrui98  }
114409c6f1ddSLingrui98
114509c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
114609c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
114709c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
114809c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
114909c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
115009c6f1ddSLingrui98  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
115109c6f1ddSLingrui98    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
115209c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
115309c6f1ddSLingrui98
115409c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
115509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
115609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
115709c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
115809c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
115909c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
116009c6f1ddSLingrui98  //           !taken),
116109c6f1ddSLingrui98  //         !taken),
116209c6f1ddSLingrui98  //       false.B)
116309c6f1ddSLingrui98  //     }
116409c6f1ddSLingrui98  //   }
116509c6f1ddSLingrui98
116609c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
116709c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
116809c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
116909c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
117009c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
117109c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
117209c6f1ddSLingrui98  //           !taken),
117309c6f1ddSLingrui98  //         !taken),
117409c6f1ddSLingrui98  //       false.B)
117509c6f1ddSLingrui98  //     }
117609c6f1ddSLingrui98  //   }
117709c6f1ddSLingrui98
117809c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
117909c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
118009c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
118109c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
118209c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
118309c6f1ddSLingrui98  //       false.B)
118409c6f1ddSLingrui98  //     }
118509c6f1ddSLingrui98  //   }
118609c6f1ddSLingrui98
118709c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
118809c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
118909c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
119009c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
119109c6f1ddSLingrui98  //         isWrong ^ (!taken),
119209c6f1ddSLingrui98  //           false.B)
119309c6f1ddSLingrui98  //     }
119409c6f1ddSLingrui98  //   }
119509c6f1ddSLingrui98
119609c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
119709c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
119809c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
119909c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
120009c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
120109c6f1ddSLingrui98  //           false.B)
120209c6f1ddSLingrui98  //     }
120309c6f1ddSLingrui98  //   }
120409c6f1ddSLingrui98
120509c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
120609c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
120709c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
120809c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
120909c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
121009c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
121109c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
121209c6f1ddSLingrui98
121309c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
121409c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
121509c6f1ddSLingrui98
121609c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
121709c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
12181ca0e4f3SYinan Xu
1219cd365d4cSrvcoresjw  val perfEvents = Seq(
1220cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1221cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1222cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1223cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1224cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1225cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1226cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1227cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1228cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1229cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1230cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)                                                         ),
1231cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1232cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1233cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1234cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1235cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1236cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1237cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1238cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1239cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1240cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1241cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1242cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1243cd365d4cSrvcoresjw    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1244cd365d4cSrvcoresjw  )
12451ca0e4f3SYinan Xu  generatePerfEvent()
124609c6f1ddSLingrui98}
1247