xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision f678dd917799bbd165ede9d6fb9dc60952afa709)
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
83a60a2901SLingrui98    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
276a60a2901SLingrui98  // 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
281a60a2901SLingrui98  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)
304a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
305a60a2901SLingrui98  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
309f4ebc4b2SLingrui98  // that means fall thru points to the middle of an inst
310f4ebc4b2SLingrui98  init_entry.last_may_be_rvi_call := io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
31109c6f1ddSLingrui98
31209c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
31309c6f1ddSLingrui98  val oe = io.old_entry
314eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
31509c6f1ddSLingrui98  val br_recorded = br_recorded_vec.asUInt.orR
31609c6f1ddSLingrui98  val is_new_br = cfi_is_br && !br_recorded
31709c6f1ddSLingrui98  val new_br_offset = io.cfiIndex.bits
31809c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
319eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
32009c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map{
32109c6f1ddSLingrui98    i => i match {
322eeb5ff92SLingrui98      case 0 =>
323eeb5ff92SLingrui98        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
324eeb5ff92SLingrui98      case idx =>
325eeb5ff92SLingrui98        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
326eeb5ff92SLingrui98        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
32709c6f1ddSLingrui98    }
32809c6f1ddSLingrui98  })
32909c6f1ddSLingrui98
33009c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
33109c6f1ddSLingrui98  for (i <- 0 until numBr) {
332eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
333eeb5ff92SLingrui98    when (new_br_insert_onehot(i)) {
334eeb5ff92SLingrui98      slot.valid := true.B
335eeb5ff92SLingrui98      slot.offset := new_br_offset
336b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
337eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := true.B
338eeb5ff92SLingrui98    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
339eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := false.B
340eeb5ff92SLingrui98      // all other fields remain unchanged
341eeb5ff92SLingrui98    }.otherwise {
342eeb5ff92SLingrui98      // case i == 0, remain unchanged
343eeb5ff92SLingrui98      if (i != 0) {
344b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
345eeb5ff92SLingrui98        when (!noNeedToMoveFromFormerSlot) {
346eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
347eeb5ff92SLingrui98          old_entry_modified.always_taken(i) := oe.always_taken(i)
34809c6f1ddSLingrui98        }
349eeb5ff92SLingrui98      }
350eeb5ff92SLingrui98    }
351eeb5ff92SLingrui98  }
35209c6f1ddSLingrui98
353eeb5ff92SLingrui98  // two circumstances:
354eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
355eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
356eeb5ff92SLingrui98  //        the previous last br or the new br
357eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
358eeb5ff92SLingrui98  val pft_need_to_change = is_new_br && may_have_to_replace
35909c6f1ddSLingrui98  // it should either be the given last br or the new br
36009c6f1ddSLingrui98  when (pft_need_to_change) {
361eeb5ff92SLingrui98    val new_pft_offset =
362710a8720SLingrui98      Mux(!new_br_insert_onehot.asUInt.orR,
363710a8720SLingrui98        new_br_offset, oe.allSlotsForBr.last.offset)
364eeb5ff92SLingrui98
365710a8720SLingrui98    // set jmp to invalid
36609c6f1ddSLingrui98    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
36709c6f1ddSLingrui98    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
368f4ebc4b2SLingrui98    old_entry_modified.last_may_be_rvi_call := false.B
36909c6f1ddSLingrui98    old_entry_modified.isCall := false.B
37009c6f1ddSLingrui98    old_entry_modified.isRet := false.B
371eeb5ff92SLingrui98    old_entry_modified.isJalr := false.B
37209c6f1ddSLingrui98  }
37309c6f1ddSLingrui98
37409c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
375710a8720SLingrui98  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
376b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
377eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3783bcae573SLingrui98  when (jalr_target_modified) {
37909c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
38009c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
38109c6f1ddSLingrui98  }
38209c6f1ddSLingrui98
38309c6f1ddSLingrui98  val old_entry_always_taken = WireInit(oe)
38409c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
38509c6f1ddSLingrui98  for (i <- 0 until numBr) {
38609c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
38709c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
388710a8720SLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
38909c6f1ddSLingrui98  }
39009c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
39109c6f1ddSLingrui98
39209c6f1ddSLingrui98
39309c6f1ddSLingrui98
39409c6f1ddSLingrui98  val derived_from_old_entry =
39509c6f1ddSLingrui98    Mux(is_new_br, old_entry_modified,
3963bcae573SLingrui98      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
39709c6f1ddSLingrui98
39809c6f1ddSLingrui98
39909c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
40009c6f1ddSLingrui98
40109c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
40209c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
40309c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
40409c6f1ddSLingrui98  })
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
4123bcae573SLingrui98  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
41309c6f1ddSLingrui98  io.is_new_br := hit && is_new_br
4143bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
41509c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
416eeb5ff92SLingrui98  io.is_br_full := hit && is_new_br && may_have_to_replace
41709c6f1ddSLingrui98}
41809c6f1ddSLingrui98
41909c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
420e30430c2SJay  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
421e30430c2SJay  with HasICacheParameters{
42209c6f1ddSLingrui98  val io = IO(new Bundle {
42309c6f1ddSLingrui98    val fromBpu = Flipped(new BpuToFtqIO)
42409c6f1ddSLingrui98    val fromIfu = Flipped(new IfuToFtqIO)
42509c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
42609c6f1ddSLingrui98
42709c6f1ddSLingrui98    val toBpu = new FtqToBpuIO
42809c6f1ddSLingrui98    val toIfu = new FtqToIfuIO
42909c6f1ddSLingrui98    val toBackend = new FtqToCtrlIO
43009c6f1ddSLingrui98
4317052722fSJay    val toPrefetch = new FtqPrefechBundle
4327052722fSJay
43309c6f1ddSLingrui98    val bpuInfo = new Bundle {
43409c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
43509c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
43609c6f1ddSLingrui98    }
43709c6f1ddSLingrui98  })
43809c6f1ddSLingrui98  io.bpuInfo := DontCare
43909c6f1ddSLingrui98
440df5b4b8eSYinan Xu  val backendRedirect = io.fromBackend.redirect
441df5b4b8eSYinan Xu  val backendRedirectReg = RegNext(io.fromBackend.redirect)
44209c6f1ddSLingrui98
443df5b4b8eSYinan Xu  val stage2Flush = backendRedirect.valid
44409c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
44509c6f1ddSLingrui98  val ifuFlush = Wire(Bool())
44609c6f1ddSLingrui98
44709c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
44809c6f1ddSLingrui98
44909c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
45009c6f1ddSLingrui98  val flushToIfu = !allowToIfu
451df5b4b8eSYinan Xu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
452df5b4b8eSYinan Xu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
45309c6f1ddSLingrui98
454e30430c2SJay  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
45509c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
45609c6f1ddSLingrui98
45709c6f1ddSLingrui98  // **********************************************************************
45809c6f1ddSLingrui98  // **************************** enq from bpu ****************************
45909c6f1ddSLingrui98  // **********************************************************************
46009c6f1ddSLingrui98  val new_entry_ready = validEntries < FtqSize.U
46109c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
46209c6f1ddSLingrui98
46309c6f1ddSLingrui98  val bpu_s2_resp = io.fromBpu.resp.bits.s2
464cb4f77ceSLingrui98  val bpu_s3_resp = io.fromBpu.resp.bits.s3
46509c6f1ddSLingrui98  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
466cb4f77ceSLingrui98  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
46709c6f1ddSLingrui98
46809c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
46909c6f1ddSLingrui98  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
470cb4f77ceSLingrui98  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
47109c6f1ddSLingrui98
472b37e4b45SLingrui98  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
473b37e4b45SLingrui98  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx
47409c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
47509c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
47609c6f1ddSLingrui98
4779aca92b9SYinan Xu  // read ports:                            jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate
47809c6f1ddSLingrui98  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1))
47909c6f1ddSLingrui98  // resp from uBTB
48009c6f1ddSLingrui98  ftq_pc_mem.io.wen(0) := bpu_in_fire
48109c6f1ddSLingrui98  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
48209c6f1ddSLingrui98  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
48309c6f1ddSLingrui98
48409c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
48509c6f1ddSLingrui98  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
48609c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
48709c6f1ddSLingrui98  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
48809c6f1ddSLingrui98  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
48909c6f1ddSLingrui98  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
49049cbc998SLingrui98  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
49149cbc998SLingrui98  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
49209c6f1ddSLingrui98
49309c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
49409c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
49509c6f1ddSLingrui98  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
49609c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
49709c6f1ddSLingrui98  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
49809c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
49909c6f1ddSLingrui98  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
50009c6f1ddSLingrui98  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
50109c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
50209c6f1ddSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
50309c6f1ddSLingrui98
50409c6f1ddSLingrui98
50509c6f1ddSLingrui98  // multi-write
506b37e4b45SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough
50709c6f1ddSLingrui98  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
50809c6f1ddSLingrui98  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
50909c6f1ddSLingrui98  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
51009c6f1ddSLingrui98
51109c6f1ddSLingrui98  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
51209c6f1ddSLingrui98  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
51309c6f1ddSLingrui98    VecInit(Seq.fill(PredictWidth)(c_invalid))
51409c6f1ddSLingrui98  }))
51509c6f1ddSLingrui98
51609c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
51709c6f1ddSLingrui98  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
51809c6f1ddSLingrui98
51909c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
52009c6f1ddSLingrui98  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
52109c6f1ddSLingrui98
52209c6f1ddSLingrui98
52309c6f1ddSLingrui98  when (bpu_in_fire) {
52409c6f1ddSLingrui98    entry_fetch_status(bpu_in_resp_idx) := f_to_send
52509c6f1ddSLingrui98    commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
526b37e4b45SLingrui98    cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.cfiIndex
52709c6f1ddSLingrui98    mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
528b37e4b45SLingrui98    update_target(bpu_in_resp_idx) := bpu_in_resp.getTarget
52909c6f1ddSLingrui98    pred_stage(bpu_in_resp_idx) := bpu_in_stage
53009c6f1ddSLingrui98  }
53109c6f1ddSLingrui98
53209c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
5337bb9fc10SLingrui98  ifuPtr := ifuPtr + (io.toIfu.req.fire && allowToIfu)
53409c6f1ddSLingrui98
53509c6f1ddSLingrui98  // only use ftb result to assign hit status
53609c6f1ddSLingrui98  when (bpu_s2_resp.valid) {
537b37e4b45SLingrui98    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit)
53809c6f1ddSLingrui98  }
53909c6f1ddSLingrui98
54009c6f1ddSLingrui98
5412f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
54209c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
54309c6f1ddSLingrui98  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
54409c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
54509c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
54609c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
54709c6f1ddSLingrui98      ifuPtr := bpu_s2_resp.ftq_idx
54809c6f1ddSLingrui98    }
54909c6f1ddSLingrui98  }
55009c6f1ddSLingrui98
551cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
552cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
553cb4f77ceSLingrui98  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
554cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
555cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
556cb4f77ceSLingrui98    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
557cb4f77ceSLingrui98      ifuPtr := bpu_s3_resp.ftq_idx
558cb4f77ceSLingrui98    }
559cb4f77ceSLingrui98  }
560cb4f77ceSLingrui98
56109c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
56209c6f1ddSLingrui98
56309c6f1ddSLingrui98  // ****************************************************************
56409c6f1ddSLingrui98  // **************************** to ifu ****************************
56509c6f1ddSLingrui98  // ****************************************************************
56609c6f1ddSLingrui98  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire)
56709c6f1ddSLingrui98  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
56809c6f1ddSLingrui98  val last_cycle_bpu_in = RegNext(bpu_in_fire)
56909c6f1ddSLingrui98  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
57009c6f1ddSLingrui98
57109c6f1ddSLingrui98  // read pc and target
57209c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
57309c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value
57409c6f1ddSLingrui98
5755ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
576b37e4b45SLingrui98  io.toIfu.req.bits.nextStartAddr := update_target(ifuPtr.value)
5775ff19bd8SLingrui98  io.toIfu.req.bits.ftqOffset := cfiIndex_vec(ifuPtr.value)
57809c6f1ddSLingrui98
579b37e4b45SLingrui98  val toIfuPcBundle = Wire(new Ftq_RF_Components)
580*f678dd91SSteve Gou  val entry_is_to_send = WireInit(false.B)
5817052722fSJay
58209c6f1ddSLingrui98  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
583b37e4b45SLingrui98    toIfuPcBundle := bpu_in_bypass_buf
584*f678dd91SSteve Gou    entry_is_to_send := true.B
58509c6f1ddSLingrui98  }.elsewhen (last_cycle_to_ifu_fire) {
586b37e4b45SLingrui98    toIfuPcBundle := ftq_pc_mem.io.rdata.init.last
587*f678dd91SSteve Gou    entry_is_to_send := RegNext(entry_fetch_status((ifuPtr+1.U).value) === f_to_send)
58809c6f1ddSLingrui98  }.otherwise {
589b37e4b45SLingrui98    toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last
590*f678dd91SSteve Gou    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send)
59109c6f1ddSLingrui98  }
59209c6f1ddSLingrui98
593*f678dd91SSteve Gou  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
594b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
595b37e4b45SLingrui98
59609c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
597b37e4b45SLingrui98  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
59809c6f1ddSLingrui98    when (io.toIfu.req.fire &&
599cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
600cb4f77ceSLingrui98      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
60109c6f1ddSLingrui98    ) {
60209c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
603352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
60409c6f1ddSLingrui98    }
605b37e4b45SLingrui98    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
60609c6f1ddSLingrui98  }
60709c6f1ddSLingrui98
608a60a2901SLingrui98  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
609a60a2901SLingrui98    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
610a60a2901SLingrui98
61109c6f1ddSLingrui98  val ifu_req_should_be_flushed =
612cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
613cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
61409c6f1ddSLingrui98
61509c6f1ddSLingrui98    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
61609c6f1ddSLingrui98      entry_fetch_status(ifuPtr.value) := f_sent
61709c6f1ddSLingrui98    }
61809c6f1ddSLingrui98
61909c6f1ddSLingrui98  // *********************************************************************
62009c6f1ddSLingrui98  // **************************** wb from ifu ****************************
62109c6f1ddSLingrui98  // *********************************************************************
62209c6f1ddSLingrui98  val pdWb = io.fromIfu.pdWb
62309c6f1ddSLingrui98  val pds = pdWb.bits.pd
62409c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
62509c6f1ddSLingrui98  val ifu_wb_idx = pdWb.bits.ftqIdx.value
62609c6f1ddSLingrui98  // read ports:                                                         commit update
62709c6f1ddSLingrui98  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
62809c6f1ddSLingrui98  ftq_pd_mem.io.wen(0) := ifu_wb_valid
62909c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
63009c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
63109c6f1ddSLingrui98
63209c6f1ddSLingrui98  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
63309c6f1ddSLingrui98  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
63409c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
63509c6f1ddSLingrui98  val pd_reg       = RegEnable(pds,             enable = pdWb.valid)
63609c6f1ddSLingrui98  val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid)
63709c6f1ddSLingrui98  val wb_idx_reg   = RegEnable(ifu_wb_idx,      enable = pdWb.valid)
63809c6f1ddSLingrui98
63909c6f1ddSLingrui98  when (ifu_wb_valid) {
64009c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
64109c6f1ddSLingrui98      case (v, inRange) => v && inRange
64209c6f1ddSLingrui98    })
64309c6f1ddSLingrui98    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
64409c6f1ddSLingrui98      case (qe, v) => when (v) { qe := c_valid }
64509c6f1ddSLingrui98    }
64609c6f1ddSLingrui98  }
64709c6f1ddSLingrui98
64809c6f1ddSLingrui98  ifuWbPtr := ifuWbPtr + ifu_wb_valid
64909c6f1ddSLingrui98
65009c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := ifu_wb_idx
65109c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
65209c6f1ddSLingrui98  when (RegNext(hit_pd_valid)) {
65309c6f1ddSLingrui98    // check for false hit
65409c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
655eeb5ff92SLingrui98    val brSlots = pred_ftb_entry.brSlots
656eeb5ff92SLingrui98    val tailSlot = pred_ftb_entry.tailSlot
65709c6f1ddSLingrui98    // we check cfis that bpu predicted
65809c6f1ddSLingrui98
659eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
660eeb5ff92SLingrui98    val br_false_hit =
661eeb5ff92SLingrui98      brSlots.map{
662eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
663eeb5ff92SLingrui98      }.reduce(_||_) ||
664b37e4b45SLingrui98      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
665eeb5ff92SLingrui98        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
666eeb5ff92SLingrui98
667eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
66809c6f1ddSLingrui98    val jmp_pd = pd_reg(jmpOffset)
66909c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
67009c6f1ddSLingrui98      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
67109c6f1ddSLingrui98       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
67209c6f1ddSLingrui98       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
67309c6f1ddSLingrui98       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
67409c6f1ddSLingrui98      )
67509c6f1ddSLingrui98
67609c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
67765fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
67865fddcf0Szoujr
679352db50aSLingrui98    // assert(!has_false_hit)
68009c6f1ddSLingrui98  }
68109c6f1ddSLingrui98
68209c6f1ddSLingrui98  when (has_false_hit) {
68309c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
68409c6f1ddSLingrui98  }
68509c6f1ddSLingrui98
68609c6f1ddSLingrui98
68709c6f1ddSLingrui98  // **********************************************************************
68809c6f1ddSLingrui98  // **************************** backend read ****************************
68909c6f1ddSLingrui98  // **********************************************************************
69009c6f1ddSLingrui98
69109c6f1ddSLingrui98  // pc reads
69209c6f1ddSLingrui98  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
69309c6f1ddSLingrui98    ftq_pc_mem.io.raddr(i) := req.ptr.value
69409c6f1ddSLingrui98    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
69509c6f1ddSLingrui98  }
69609c6f1ddSLingrui98  // target read
69709c6f1ddSLingrui98  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
69809c6f1ddSLingrui98
69909c6f1ddSLingrui98  // *******************************************************************************
70009c6f1ddSLingrui98  // **************************** redirect from backend ****************************
70109c6f1ddSLingrui98  // *******************************************************************************
70209c6f1ddSLingrui98
70309c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
704df5b4b8eSYinan Xu  ftq_redirect_sram.io.ren.init.last := io.fromBackend.redirect.valid
705df5b4b8eSYinan Xu  ftq_redirect_sram.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value
70609c6f1ddSLingrui98
707df5b4b8eSYinan Xu  ftb_entry_mem.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value
70809c6f1ddSLingrui98
70909c6f1ddSLingrui98  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
710df5b4b8eSYinan Xu  val fromBackendRedirect = WireInit(backendRedirectReg)
71109c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
71209c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
71309c6f1ddSLingrui98
71409c6f1ddSLingrui98  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
71509c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
71609c6f1ddSLingrui98
71709c6f1ddSLingrui98  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
71809c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
71909c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
720eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
72109c6f1ddSLingrui98
72209c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
723eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
72409c6f1ddSLingrui98  }.otherwise {
72509c6f1ddSLingrui98    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
72609c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
72709c6f1ddSLingrui98  }
72809c6f1ddSLingrui98
72909c6f1ddSLingrui98
73009c6f1ddSLingrui98  // ***************************************************************************
73109c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
73209c6f1ddSLingrui98  // ***************************************************************************
73309c6f1ddSLingrui98  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
73409c6f1ddSLingrui98  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
73509c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
73609c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
73709c6f1ddSLingrui98  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
73809c6f1ddSLingrui98
73909c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
74009c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
74109c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
74209c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
74309c6f1ddSLingrui98  ifuRedirectCfiUpdate.target := pdWb.bits.target
74409c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
74509c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
74609c6f1ddSLingrui98
74709c6f1ddSLingrui98  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
74809c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
74909c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
75009c6f1ddSLingrui98
75109c6f1ddSLingrui98  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
75209c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
75309c6f1ddSLingrui98
75409c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
75509c6f1ddSLingrui98
75609c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
75709c6f1ddSLingrui98  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
75809c6f1ddSLingrui98  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
75909c6f1ddSLingrui98    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
76009c6f1ddSLingrui98  }
76109c6f1ddSLingrui98
76209c6f1ddSLingrui98  // *********************************************************************
76309c6f1ddSLingrui98  // **************************** wb from exu ****************************
76409c6f1ddSLingrui98  // *********************************************************************
76509c6f1ddSLingrui98
76609c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
76709c6f1ddSLingrui98    val ftqIdx = wb.bits.ftqIdx.value
76809c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
76909c6f1ddSLingrui98    val taken = wb.bits.cfiUpdate.taken
77009c6f1ddSLingrui98    val mispred = wb.bits.cfiUpdate.isMisPred
77109c6f1ddSLingrui98    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
77209c6f1ddSLingrui98  }
77309c6f1ddSLingrui98
77409c6f1ddSLingrui98  // fix mispredict entry
77509c6f1ddSLingrui98  val lastIsMispredict = RegNext(
776df5b4b8eSYinan Xu    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
77709c6f1ddSLingrui98  )
77809c6f1ddSLingrui98
77909c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
78009c6f1ddSLingrui98    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
78109c6f1ddSLingrui98    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
78209c6f1ddSLingrui98    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
78309c6f1ddSLingrui98    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
78409c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
78509c6f1ddSLingrui98    }
78609c6f1ddSLingrui98    when (cfiIndex_bits_wen) {
78709c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
78809c6f1ddSLingrui98    }
78909c6f1ddSLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target
79009c6f1ddSLingrui98    if (isBackend) {
79109c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
79209c6f1ddSLingrui98    }
79309c6f1ddSLingrui98  }
79409c6f1ddSLingrui98
795df5b4b8eSYinan Xu  when(backendRedirectReg.valid && lastIsMispredict) {
796df5b4b8eSYinan Xu    updateCfiInfo(backendRedirectReg)
79709c6f1ddSLingrui98  }.elsewhen (ifuRedirectToBpu.valid) {
79809c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
79909c6f1ddSLingrui98  }
80009c6f1ddSLingrui98
80109c6f1ddSLingrui98  // ***********************************************************************************
80209c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
80309c6f1ddSLingrui98  // ***********************************************************************************
80409c6f1ddSLingrui98
805df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
80609c6f1ddSLingrui98
80709c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
80809c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_||_)){
8092f4a3aa4SLingrui98    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
81009c6f1ddSLingrui98    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
8112f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
81209c6f1ddSLingrui98    val next = idx + 1.U
81309c6f1ddSLingrui98    bpuPtr := next
81409c6f1ddSLingrui98    ifuPtr := next
81509c6f1ddSLingrui98    ifuWbPtr := next
81609c6f1ddSLingrui98    when (notIfu) {
81709c6f1ddSLingrui98      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
81809c6f1ddSLingrui98        when(i.U > offset || i.U === offset && flushItSelf){
81909c6f1ddSLingrui98          s := c_invalid
82009c6f1ddSLingrui98        }
82109c6f1ddSLingrui98      })
82209c6f1ddSLingrui98    }
82309c6f1ddSLingrui98  }
82409c6f1ddSLingrui98
82509c6f1ddSLingrui98  // only the valid bit is actually needed
826df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
82709c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
82809c6f1ddSLingrui98
82909c6f1ddSLingrui98  // commit
8309aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
83109c6f1ddSLingrui98    when(c.valid) {
83209c6f1ddSLingrui98      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
83388825c5cSYinan Xu      // TODO: remove this
83488825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
835c3abb8b6SYinan Xu      when (c.bits.commitType === 4.U) {
83688825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
837c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
83888825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
839c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
84088825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
84188825c5cSYinan Xu        commitStateQueue(index)(0) := c_commited
842c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
84388825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
84488825c5cSYinan Xu        commitStateQueue(index)(1) := c_commited
84588825c5cSYinan Xu      }
84609c6f1ddSLingrui98    }
84709c6f1ddSLingrui98  }
84809c6f1ddSLingrui98
84909c6f1ddSLingrui98  // ****************************************************************
85009c6f1ddSLingrui98  // **************************** to bpu ****************************
85109c6f1ddSLingrui98  // ****************************************************************
85209c6f1ddSLingrui98
85309c6f1ddSLingrui98  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
85409c6f1ddSLingrui98
8555371700eSzoujr  val may_have_stall_from_bpu = RegInit(false.B)
8565371700eSzoujr  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
85709c6f1ddSLingrui98    Cat(commitStateQueue(commPtr.value).map(s => {
85809c6f1ddSLingrui98      s === c_invalid || s === c_commited
85909c6f1ddSLingrui98    })).andR()
86009c6f1ddSLingrui98
86109c6f1ddSLingrui98  // commit reads
86209c6f1ddSLingrui98  ftq_pc_mem.io.raddr.last := commPtr.value
86309c6f1ddSLingrui98  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
86409c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last := commPtr.value
86509c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
86609c6f1ddSLingrui98  ftq_redirect_sram.io.ren.last := canCommit
86709c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.last := commPtr.value
86809c6f1ddSLingrui98  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
86909c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0) := canCommit
87009c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
87109c6f1ddSLingrui98  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
87209c6f1ddSLingrui98  ftb_entry_mem.io.raddr.last := commPtr.value
87309c6f1ddSLingrui98  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
87409c6f1ddSLingrui98
87509c6f1ddSLingrui98  // need one cycle to read mem and srams
87609c6f1ddSLingrui98  val do_commit_ptr = RegNext(commPtr)
8775371700eSzoujr  val do_commit = RegNext(canCommit, init=false.B)
87809c6f1ddSLingrui98  when (canCommit) { commPtr := commPtr + 1.U }
87909c6f1ddSLingrui98  val commit_state = RegNext(commitStateQueue(commPtr.value))
8805371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
8815371700eSzoujr  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
8825371700eSzoujr    can_commit_cfi.valid := false.B
88309c6f1ddSLingrui98  }
8845371700eSzoujr  val commit_cfi = RegNext(can_commit_cfi)
88509c6f1ddSLingrui98
88609c6f1ddSLingrui98  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
88709c6f1ddSLingrui98    case (mis, state) => mis && state === c_commited
88809c6f1ddSLingrui98  })
8895371700eSzoujr  val can_commit_hit = entry_hit_status(commPtr.value)
8905371700eSzoujr  val commit_hit = RegNext(can_commit_hit)
89109c6f1ddSLingrui98  val commit_target = RegNext(update_target(commPtr.value))
892edc18578SLingrui98  val commit_stage = RegNext(pred_stage(commPtr.value))
89309c6f1ddSLingrui98  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
89409c6f1ddSLingrui98
8955371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
8961c8d9e26Szoujr  may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu
89709c6f1ddSLingrui98
89809c6f1ddSLingrui98  io.toBpu.update := DontCare
89909c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
90009c6f1ddSLingrui98  val update = io.toBpu.update.bits
90109c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
90209c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
90309c6f1ddSLingrui98  update.meta        := commit_meta.meta
9048ffcd86aSLingrui98  update.full_target := commit_target
905edc18578SLingrui98  update.from_stage  := commit_stage
90609c6f1ddSLingrui98  update.fromFtqRedirectSram(commit_spec_meta)
90709c6f1ddSLingrui98
90809c6f1ddSLingrui98  val commit_real_hit = commit_hit === h_hit
90909c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
91009c6f1ddSLingrui98
91109c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
91209c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
91309c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
91409c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
91509c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
91609c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
91709c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
91809c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
91909c6f1ddSLingrui98
92009c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
92109c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
92209c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
92309c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
924edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
925b37e4b45SLingrui98
926b37e4b45SLingrui98  update.is_minimal := false.B
927b37e4b45SLingrui98  update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
928b37e4b45SLingrui98  update.full_pred.br_taken_mask  := ftbEntryGen.taken_mask
929b37e4b45SLingrui98  update.full_pred.jalr_target := commit_target
930b37e4b45SLingrui98  update.full_pred.hit := true.B
931b37e4b45SLingrui98  when (update.full_pred.is_jalr) {
932b37e4b45SLingrui98    update.full_pred.targets.last := commit_target
933b37e4b45SLingrui98  }
93409c6f1ddSLingrui98
935e30430c2SJay  // ****************************************************************
936e30430c2SJay  // *********************** to prefetch ****************************
937e30430c2SJay  // ****************************************************************
938e30430c2SJay
939e30430c2SJay  if(cacheParams.hasPrefetch){
940e30430c2SJay    val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
941e30430c2SJay    prefetchPtr := prefetchPtr + io.toPrefetch.req.fire()
942e30430c2SJay
943e30430c2SJay    when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) {
944e30430c2SJay      prefetchPtr := bpu_s2_resp.ftq_idx
945e30430c2SJay    }
946e30430c2SJay
947cb4f77ceSLingrui98    when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) {
948cb4f77ceSLingrui98      prefetchPtr := bpu_s3_resp.ftq_idx
949a3c55791SJinYue      // XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
950cb4f77ceSLingrui98    }
951de7689fcSJay
952259b970fSJinYue    io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send
953de7689fcSJay    io.toPrefetch.req.bits.target := update_target(prefetchPtr.value)
954de7689fcSJay
955de7689fcSJay    when(redirectVec.map(r => r.valid).reduce(_||_)){
956de7689fcSJay      val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
957de7689fcSJay      val next = r.ftqIdx + 1.U
958de7689fcSJay      prefetchPtr := next
959de7689fcSJay    }
960de7689fcSJay
961de7689fcSJay    XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n")
962de7689fcSJay  }
963de7689fcSJay  else {
964de7689fcSJay    io.toPrefetch.req <> DontCare
965de7689fcSJay  }
966de7689fcSJay
96709c6f1ddSLingrui98  // ******************************************************************************
96809c6f1ddSLingrui98  // **************************** commit perf counters ****************************
96909c6f1ddSLingrui98  // ******************************************************************************
97009c6f1ddSLingrui98
97109c6f1ddSLingrui98  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
97209c6f1ddSLingrui98  val commit_mispred_mask = commit_mispredict.asUInt
97309c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
97409c6f1ddSLingrui98
97509c6f1ddSLingrui98  val commit_br_mask = commit_pd.brMask.asUInt
97609c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
97709c6f1ddSLingrui98  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
97809c6f1ddSLingrui98
97909c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
98009c6f1ddSLingrui98
98109c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
98209c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
98309c6f1ddSLingrui98
98409c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
98509c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
98609c6f1ddSLingrui98
98709c6f1ddSLingrui98  // Cfi Info
98809c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
98909c6f1ddSLingrui98    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
99009c6f1ddSLingrui98    val v = commit_state(i) === c_commited
99109c6f1ddSLingrui98    val isBr = commit_pd.brMask(i)
99209c6f1ddSLingrui98    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
99309c6f1ddSLingrui98    val isCfi = isBr || isJmp
99409c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
99509c6f1ddSLingrui98    val misPred = commit_mispredict(i)
996c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
997c2ad24ebSLingrui98    val histPtr = commit_spec_meta.histPtr
99809c6f1ddSLingrui98    val predCycle = commit_meta.meta(63, 0)
99909c6f1ddSLingrui98    val target = commit_target
100009c6f1ddSLingrui98
100109c6f1ddSLingrui98    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
100209c6f1ddSLingrui98    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
100309c6f1ddSLingrui98    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
100409c6f1ddSLingrui98    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1005c2ad24ebSLingrui98    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
100609c6f1ddSLingrui98    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
100709c6f1ddSLingrui98    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
100809c6f1ddSLingrui98  }
100909c6f1ddSLingrui98
101009c6f1ddSLingrui98  val enq = io.fromBpu.resp
1011df5b4b8eSYinan Xu  val perf_redirect = io.fromBackend.redirect
101209c6f1ddSLingrui98
101309c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
101409c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
101509c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
101609c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
101709c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
101809c6f1ddSLingrui98
101909c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
102009c6f1ddSLingrui98
102109c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
102209c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
102312cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
102409c6f1ddSLingrui98
102509c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
102609c6f1ddSLingrui98  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
1027b37e4b45SLingrui98    assert(!resp.is_minimal)
102809c6f1ddSLingrui98    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
102909c6f1ddSLingrui98    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
103009c6f1ddSLingrui98    val entry_len_map = (1 to PredictWidth+1).map(i =>
103109c6f1ddSLingrui98      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
103209c6f1ddSLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
103309c6f1ddSLingrui98    entry_len_map
103409c6f1ddSLingrui98  }
103509c6f1ddSLingrui98  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
1036cb4f77ceSLingrui98  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
103709c6f1ddSLingrui98
103809c6f1ddSLingrui98  val to_ifu = io.toIfu.req.bits
103909c6f1ddSLingrui98
104009c6f1ddSLingrui98
104109c6f1ddSLingrui98
104209c6f1ddSLingrui98  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
104309c6f1ddSLingrui98  val commit_num_inst_map = (1 to PredictWidth).map(i =>
104409c6f1ddSLingrui98    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
104509c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
104609c6f1ddSLingrui98
104709c6f1ddSLingrui98
104809c6f1ddSLingrui98
104909c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
105009c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
105109c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
105209c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
105309c6f1ddSLingrui98
105409c6f1ddSLingrui98
105509c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
105609c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
105709c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
105809c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
105909c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
106009c6f1ddSLingrui98
106109c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
106209c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
106309c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
106409c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
106509c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
106609c6f1ddSLingrui98
10671d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
10681d7e5011SLingrui98
10691d7e5011SLingrui98  def pred_stage_map(src: UInt, name: String) = {
10701d7e5011SLingrui98    (0 until numBpStages).map(i =>
10711d7e5011SLingrui98      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
10721d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
10731d7e5011SLingrui98  }
10741d7e5011SLingrui98
10751d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
10761d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
10771d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
10781d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
10791d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
10801d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
10811d7e5011SLingrui98
108209c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
108309c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
108409c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
108565fddcf0Szoujr  // assert(!ftb_false_hit)
108609c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
108709c6f1ddSLingrui98
108809c6f1ddSLingrui98  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1089b37e4b45SLingrui98  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1090b37e4b45SLingrui98  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1091b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
109209c6f1ddSLingrui98
109309c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
109409c6f1ddSLingrui98
109509c6f1ddSLingrui98  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
109609c6f1ddSLingrui98  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
109709c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
109809c6f1ddSLingrui98  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
109909c6f1ddSLingrui98  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
110009c6f1ddSLingrui98
110109c6f1ddSLingrui98  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
110209c6f1ddSLingrui98  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
110309c6f1ddSLingrui98  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
110409c6f1ddSLingrui98    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
110509c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
110609c6f1ddSLingrui98  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
110709c6f1ddSLingrui98    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
110809c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
110909c6f1ddSLingrui98
111009c6f1ddSLingrui98  val ftq_occupancy_map = (0 to FtqSize).map(i =>
111109c6f1ddSLingrui98    f"ftq_has_entry_$i" ->( validEntries === i.U)
111209c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
111309c6f1ddSLingrui98
111409c6f1ddSLingrui98  val perfCountsMap = Map(
111509c6f1ddSLingrui98    "BpInstr" -> PopCount(mbpInstrs),
111609c6f1ddSLingrui98    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
111709c6f1ddSLingrui98    "BpRight"  -> PopCount(mbpRights),
111809c6f1ddSLingrui98    "BpWrong"  -> PopCount(mbpWrongs),
111909c6f1ddSLingrui98    "BpBRight" -> PopCount(mbpBRights),
112009c6f1ddSLingrui98    "BpBWrong" -> PopCount(mbpBWrongs),
112109c6f1ddSLingrui98    "BpJRight" -> PopCount(mbpJRights),
112209c6f1ddSLingrui98    "BpJWrong" -> PopCount(mbpJWrongs),
112309c6f1ddSLingrui98    "BpIRight" -> PopCount(mbpIRights),
112409c6f1ddSLingrui98    "BpIWrong" -> PopCount(mbpIWrongs),
112509c6f1ddSLingrui98    "BpCRight" -> PopCount(mbpCRights),
112609c6f1ddSLingrui98    "BpCWrong" -> PopCount(mbpCWrongs),
112709c6f1ddSLingrui98    "BpRRight" -> PopCount(mbpRRights),
112809c6f1ddSLingrui98    "BpRWrong" -> PopCount(mbpRWrongs),
112909c6f1ddSLingrui98
113009c6f1ddSLingrui98    "ftb_false_hit"                -> PopCount(ftb_false_hit),
113109c6f1ddSLingrui98    "ftb_hit"                      -> PopCount(ftb_hit),
113209c6f1ddSLingrui98    "ftb_new_entry"                -> PopCount(ftb_new_entry),
113309c6f1ddSLingrui98    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
113409c6f1ddSLingrui98    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
113509c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
113609c6f1ddSLingrui98    "ftb_old_entry"                -> PopCount(ftb_old_entry),
113709c6f1ddSLingrui98    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
113809c6f1ddSLingrui98    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
113909c6f1ddSLingrui98    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
114009c6f1ddSLingrui98    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
114109c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
11426d0e92edSLingrui98  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++
1143cb4f77ceSLingrui98  s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++
11441d7e5011SLingrui98  mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
11451d7e5011SLingrui98  correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
114609c6f1ddSLingrui98
114709c6f1ddSLingrui98  for((key, value) <- perfCountsMap) {
114809c6f1ddSLingrui98    XSPerfAccumulate(key, value)
114909c6f1ddSLingrui98  }
115009c6f1ddSLingrui98
115109c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
115209c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
115309c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
115409c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
115509c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
115609c6f1ddSLingrui98  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
115709c6f1ddSLingrui98    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
115809c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
115909c6f1ddSLingrui98
116009c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
116109c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
116209c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
116309c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
116409c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
116509c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
116609c6f1ddSLingrui98  //           !taken),
116709c6f1ddSLingrui98  //         !taken),
116809c6f1ddSLingrui98  //       false.B)
116909c6f1ddSLingrui98  //     }
117009c6f1ddSLingrui98  //   }
117109c6f1ddSLingrui98
117209c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
117309c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
117409c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
117509c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
117609c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
117709c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
117809c6f1ddSLingrui98  //           !taken),
117909c6f1ddSLingrui98  //         !taken),
118009c6f1ddSLingrui98  //       false.B)
118109c6f1ddSLingrui98  //     }
118209c6f1ddSLingrui98  //   }
118309c6f1ddSLingrui98
118409c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
118509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
118609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
118709c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
118809c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
118909c6f1ddSLingrui98  //       false.B)
119009c6f1ddSLingrui98  //     }
119109c6f1ddSLingrui98  //   }
119209c6f1ddSLingrui98
119309c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
119409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
119509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
119609c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
119709c6f1ddSLingrui98  //         isWrong ^ (!taken),
119809c6f1ddSLingrui98  //           false.B)
119909c6f1ddSLingrui98  //     }
120009c6f1ddSLingrui98  //   }
120109c6f1ddSLingrui98
120209c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
120309c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
120409c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
120509c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
120609c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
120709c6f1ddSLingrui98  //           false.B)
120809c6f1ddSLingrui98  //     }
120909c6f1ddSLingrui98  //   }
121009c6f1ddSLingrui98
121109c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
121209c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
121309c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
121409c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
121509c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
121609c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
121709c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
121809c6f1ddSLingrui98
121909c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
122009c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
122109c6f1ddSLingrui98
122209c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
122309c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
12241ca0e4f3SYinan Xu
1225cd365d4cSrvcoresjw  val perfEvents = Seq(
1226cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1227cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1228cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1229cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1230cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1231cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1232cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1233cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1234cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1235cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1236cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)                                                         ),
1237cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1238cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1239cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1240cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1241cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1242cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1243cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1244cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1245cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1246cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1247cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1248cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1249cd365d4cSrvcoresjw    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1250cd365d4cSrvcoresjw  )
12511ca0e4f3SYinan Xu  generatePerfEvent()
125209c6f1ddSLingrui98}
1253