xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision eeb5ff92e228cc529156e0533d0f8c330c1d7bcb)
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._
2209c6f1ddSLingrui98import utils.{AsyncDataModuleTemplate, CircularQueuePtr, DataModuleTemplate, HasCircularQueuePtrHelper, SRAMTemplate, SyncDataModuleTemplate, XSDebug, XSPerfAccumulate, XSError}
2309c6f1ddSLingrui98import xiangshan._
2409c6f1ddSLingrui98import scala.tools.nsc.doc.model.Val
2509c6f1ddSLingrui98import utils.{ParallelPriorityMux, ParallelPriorityEncoder}
2609c6f1ddSLingrui98import xiangshan.backend.{CtrlToFtqIO}
2709c6f1ddSLingrui98import firrtl.annotations.MemoryLoadFileType
2809c6f1ddSLingrui98
2909c6f1ddSLingrui98class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr](
3009c6f1ddSLingrui98  p => p(XSCoreParamsKey).FtqSize
3109c6f1ddSLingrui98){
3209c6f1ddSLingrui98  override def cloneType = (new FtqPtr).asInstanceOf[this.type]
3309c6f1ddSLingrui98}
3409c6f1ddSLingrui98
3509c6f1ddSLingrui98object FtqPtr {
3609c6f1ddSLingrui98  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
3709c6f1ddSLingrui98    val ptr = Wire(new FtqPtr)
3809c6f1ddSLingrui98    ptr.flag := f
3909c6f1ddSLingrui98    ptr.value := v
4009c6f1ddSLingrui98    ptr
4109c6f1ddSLingrui98  }
4209c6f1ddSLingrui98  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
4309c6f1ddSLingrui98    apply(!ptr.flag, ptr.value)
4409c6f1ddSLingrui98  }
4509c6f1ddSLingrui98}
4609c6f1ddSLingrui98
4709c6f1ddSLingrui98class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
4809c6f1ddSLingrui98
4909c6f1ddSLingrui98  val io = IO(new Bundle() {
5009c6f1ddSLingrui98    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
5109c6f1ddSLingrui98    val ren = Input(Vec(numRead, Bool()))
5209c6f1ddSLingrui98    val rdata = Output(Vec(numRead, gen))
5309c6f1ddSLingrui98    val waddr = Input(UInt(log2Up(FtqSize).W))
5409c6f1ddSLingrui98    val wen = Input(Bool())
5509c6f1ddSLingrui98    val wdata = Input(gen)
5609c6f1ddSLingrui98  })
5709c6f1ddSLingrui98
5809c6f1ddSLingrui98  for(i <- 0 until numRead){
5909c6f1ddSLingrui98    val sram = Module(new SRAMTemplate(gen, FtqSize))
6009c6f1ddSLingrui98    sram.io.r.req.valid := io.ren(i)
6109c6f1ddSLingrui98    sram.io.r.req.bits.setIdx := io.raddr(i)
6209c6f1ddSLingrui98    io.rdata(i) := sram.io.r.resp.data(0)
6309c6f1ddSLingrui98    sram.io.w.req.valid := io.wen
6409c6f1ddSLingrui98    sram.io.w.req.bits.setIdx := io.waddr
6509c6f1ddSLingrui98    sram.io.w.req.bits.data := VecInit(io.wdata)
6609c6f1ddSLingrui98  }
6709c6f1ddSLingrui98
6809c6f1ddSLingrui98}
6909c6f1ddSLingrui98
7009c6f1ddSLingrui98class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
7109c6f1ddSLingrui98  // TODO: move pftAddr, oversize, carry to another mem
7209c6f1ddSLingrui98  val startAddr = UInt(VAddrBits.W)
7309c6f1ddSLingrui98  val nextRangeAddr = UInt(VAddrBits.W)
7409c6f1ddSLingrui98  val pftAddr = UInt((log2Ceil(PredictWidth)+1).W)
7509c6f1ddSLingrui98  val isNextMask = Vec(PredictWidth, Bool())
7609c6f1ddSLingrui98  val oversize = Bool()
7709c6f1ddSLingrui98  val carry = Bool()
7809c6f1ddSLingrui98  def getPc(offset: UInt) = {
7909c6f1ddSLingrui98    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits)
8009c6f1ddSLingrui98    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits-1, instOffsetBits)
8109c6f1ddSLingrui98    Cat(getHigher(Mux(isNextMask(offset), nextRangeAddr, startAddr)),
8209c6f1ddSLingrui98        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
8309c6f1ddSLingrui98  }
8409c6f1ddSLingrui98  def getFallThrough() = {
8509c6f1ddSLingrui98    getFallThroughAddr(this.startAddr, this.carry, this.pftAddr)
8609c6f1ddSLingrui98  }
8709c6f1ddSLingrui98  def fallThroughError() = {
8809c6f1ddSLingrui98    !carry && startAddr(instOffsetBits+log2Ceil(PredictWidth), instOffsetBits) > pftAddr
8909c6f1ddSLingrui98  }
9009c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
9109c6f1ddSLingrui98    this.startAddr := resp.pc
9209c6f1ddSLingrui98    this.nextRangeAddr := resp.pc + (FetchWidth * 4).U
9309c6f1ddSLingrui98    this.pftAddr := resp.ftb_entry.pftAddr
9409c6f1ddSLingrui98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
9509c6f1ddSLingrui98      (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool()
9609c6f1ddSLingrui98    ))
9709c6f1ddSLingrui98    this.oversize := resp.ftb_entry.oversize
9809c6f1ddSLingrui98    this.carry := resp.ftb_entry.carry
9909c6f1ddSLingrui98    this
10009c6f1ddSLingrui98  }
10109c6f1ddSLingrui98  override def toPrintable: Printable = {
10209c6f1ddSLingrui98    p"startAddr:${Hexadecimal(startAddr)}, fallThru:${Hexadecimal(getFallThrough())}"
10309c6f1ddSLingrui98  }
10409c6f1ddSLingrui98}
10509c6f1ddSLingrui98
10609c6f1ddSLingrui98class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
10709c6f1ddSLingrui98  val brMask = Vec(PredictWidth, Bool())
10809c6f1ddSLingrui98  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
10909c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
11009c6f1ddSLingrui98  val jalTarget = UInt(VAddrBits.W)
11109c6f1ddSLingrui98  val rvcMask = Vec(PredictWidth, Bool())
11209c6f1ddSLingrui98  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
11309c6f1ddSLingrui98  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
11409c6f1ddSLingrui98  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
11509c6f1ddSLingrui98  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
11609c6f1ddSLingrui98
11709c6f1ddSLingrui98  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
11809c6f1ddSLingrui98    val pds = pdWb.pd
11909c6f1ddSLingrui98    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
12009c6f1ddSLingrui98    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
12109c6f1ddSLingrui98    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
12209c6f1ddSLingrui98                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
12309c6f1ddSLingrui98    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
12409c6f1ddSLingrui98    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
12509c6f1ddSLingrui98    this.jalTarget := pdWb.jalTarget
12609c6f1ddSLingrui98  }
12709c6f1ddSLingrui98
12809c6f1ddSLingrui98  def toPd(offset: UInt) = {
12909c6f1ddSLingrui98    require(offset.getWidth == log2Ceil(PredictWidth))
13009c6f1ddSLingrui98    val pd = Wire(new PreDecodeInfo)
13109c6f1ddSLingrui98    pd.valid := true.B
13209c6f1ddSLingrui98    pd.isRVC := rvcMask(offset)
13309c6f1ddSLingrui98    val isBr = brMask(offset)
13409c6f1ddSLingrui98    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
13509c6f1ddSLingrui98    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
13609c6f1ddSLingrui98    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
13709c6f1ddSLingrui98    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
13809c6f1ddSLingrui98    pd
13909c6f1ddSLingrui98  }
14009c6f1ddSLingrui98}
14109c6f1ddSLingrui98
14209c6f1ddSLingrui98
14309c6f1ddSLingrui98
14409c6f1ddSLingrui98class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
14509c6f1ddSLingrui98  val rasSp = UInt(log2Ceil(RasSize).W)
14609c6f1ddSLingrui98  val rasEntry = new RASEntry
14709c6f1ddSLingrui98  val specCnt = Vec(numBr, UInt(10.W))
14809c6f1ddSLingrui98  val ghist = new GlobalHistory
14909c6f1ddSLingrui98  val phist = UInt(PathHistoryLength.W)
15009c6f1ddSLingrui98  val phNewBit = UInt(1.W)
15109c6f1ddSLingrui98
15209c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
15309c6f1ddSLingrui98    this.rasSp := resp.rasSp
15409c6f1ddSLingrui98    this.rasEntry := resp.rasTop
15509c6f1ddSLingrui98    this.specCnt := resp.specCnt
15609c6f1ddSLingrui98    this.ghist := resp.ghist
15709c6f1ddSLingrui98    this.phist := resp.phist
15809c6f1ddSLingrui98    this.phNewBit := resp.pc(instOffsetBits)
15909c6f1ddSLingrui98    this
16009c6f1ddSLingrui98  }
16109c6f1ddSLingrui98}
16209c6f1ddSLingrui98
16309c6f1ddSLingrui98class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
16409c6f1ddSLingrui98  val meta = UInt(MaxMetaLength.W)
16509c6f1ddSLingrui98}
16609c6f1ddSLingrui98
16709c6f1ddSLingrui98class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
16809c6f1ddSLingrui98  val target = UInt(VAddrBits.W)
16909c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
17009c6f1ddSLingrui98}
17109c6f1ddSLingrui98
17209c6f1ddSLingrui98class FtqEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
17309c6f1ddSLingrui98  val startAddr = UInt(VAddrBits.W)
17409c6f1ddSLingrui98  val fallThruAddr = UInt(VAddrBits.W)
17509c6f1ddSLingrui98  val isNextMask = Vec(PredictWidth, Bool())
17609c6f1ddSLingrui98
17709c6f1ddSLingrui98  val meta = UInt(MaxMetaLength.W)
17809c6f1ddSLingrui98
17909c6f1ddSLingrui98  val rasSp = UInt(log2Ceil(RasSize).W)
18009c6f1ddSLingrui98  val rasEntry = new RASEntry
18109c6f1ddSLingrui98  val hist = new GlobalHistory
18209c6f1ddSLingrui98  val specCnt = Vec(numBr, UInt(10.W))
18309c6f1ddSLingrui98
18409c6f1ddSLingrui98  val valids = Vec(PredictWidth, Bool())
18509c6f1ddSLingrui98  val brMask = Vec(PredictWidth, Bool())
18609c6f1ddSLingrui98  // isJalr, isCall, isRet
18709c6f1ddSLingrui98  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
18809c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
18909c6f1ddSLingrui98
19009c6f1ddSLingrui98  val mispredVec = Vec(PredictWidth, Bool())
19109c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
19209c6f1ddSLingrui98  val target = UInt(VAddrBits.W)
19309c6f1ddSLingrui98}
19409c6f1ddSLingrui98
19509c6f1ddSLingrui98class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
19609c6f1ddSLingrui98  val ptr = Output(new FtqPtr)
19709c6f1ddSLingrui98  val offset = Output(UInt(log2Ceil(PredictWidth).W))
19809c6f1ddSLingrui98  val data = Input(gen)
19909c6f1ddSLingrui98  def apply(ptr: FtqPtr, offset: UInt) = {
20009c6f1ddSLingrui98    this.ptr := ptr
20109c6f1ddSLingrui98    this.offset := offset
20209c6f1ddSLingrui98    this.data
20309c6f1ddSLingrui98  }
20409c6f1ddSLingrui98  override def cloneType = (new FtqRead(gen)).asInstanceOf[this.type]
20509c6f1ddSLingrui98}
20609c6f1ddSLingrui98
20709c6f1ddSLingrui98
20809c6f1ddSLingrui98class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
20909c6f1ddSLingrui98  val redirect = Valid(new BranchPredictionRedirect)
21009c6f1ddSLingrui98  val update = Valid(new BranchPredictionUpdate)
21109c6f1ddSLingrui98  val enq_ptr = Output(new FtqPtr)
21209c6f1ddSLingrui98}
21309c6f1ddSLingrui98
21409c6f1ddSLingrui98class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
21509c6f1ddSLingrui98  val req = Decoupled(new FetchRequestBundle)
21609c6f1ddSLingrui98  val redirect = Valid(new Redirect)
21709c6f1ddSLingrui98  val flushFromBpu = new Bundle {
21809c6f1ddSLingrui98    // when ifu pipeline is not stalled,
21909c6f1ddSLingrui98    // a packet from bpu s3 can reach f1 at most
22009c6f1ddSLingrui98    val s2 = Valid(new FtqPtr)
22109c6f1ddSLingrui98    val s3 = Valid(new FtqPtr)
22209c6f1ddSLingrui98    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
22309c6f1ddSLingrui98      src.valid && !isAfter(src.bits, idx_to_flush)
22409c6f1ddSLingrui98    }
22509c6f1ddSLingrui98    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
22609c6f1ddSLingrui98    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
22709c6f1ddSLingrui98  }
22809c6f1ddSLingrui98}
22909c6f1ddSLingrui98
23009c6f1ddSLingrui98trait HasBackendRedirectInfo extends HasXSParameter {
23109c6f1ddSLingrui98  def numRedirect = exuParameters.JmpCnt + exuParameters.AluCnt + 1
23209c6f1ddSLingrui98  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
23309c6f1ddSLingrui98}
23409c6f1ddSLingrui98
23509c6f1ddSLingrui98class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
23609c6f1ddSLingrui98  val pc_reads = Vec(1 + numRedirect + 1 + 1, Flipped(new FtqRead(UInt(VAddrBits.W))))
23709c6f1ddSLingrui98  val target_read = Flipped(new FtqRead(UInt(VAddrBits.W)))
23809c6f1ddSLingrui98  def getJumpPcRead = pc_reads.head
23909c6f1ddSLingrui98  def getRedirectPcRead = VecInit(pc_reads.tail.dropRight(2))
24009c6f1ddSLingrui98  def getMemPredPcRead = pc_reads.init.last
24109c6f1ddSLingrui98  def getRoqFlushPcRead = pc_reads.last
24209c6f1ddSLingrui98}
24309c6f1ddSLingrui98
24409c6f1ddSLingrui98
24509c6f1ddSLingrui98class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
24609c6f1ddSLingrui98  val io = IO(new Bundle {
24709c6f1ddSLingrui98    val start_addr = Input(UInt(VAddrBits.W))
24809c6f1ddSLingrui98    val old_entry = Input(new FTBEntry)
24909c6f1ddSLingrui98    val pd = Input(new Ftq_pd_Entry)
25009c6f1ddSLingrui98    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
25109c6f1ddSLingrui98    val target = Input(UInt(VAddrBits.W))
25209c6f1ddSLingrui98    val hit = Input(Bool())
25309c6f1ddSLingrui98    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
25409c6f1ddSLingrui98
25509c6f1ddSLingrui98    val new_entry = Output(new FTBEntry)
25609c6f1ddSLingrui98    val new_br_insert_pos = Output(Vec(numBr, Bool()))
25709c6f1ddSLingrui98    val taken_mask = Output(Vec(numBr, Bool()))
25809c6f1ddSLingrui98    val mispred_mask = Output(Vec(numBr+1, Bool()))
25909c6f1ddSLingrui98
26009c6f1ddSLingrui98    // for perf counters
26109c6f1ddSLingrui98    val is_init_entry = Output(Bool())
26209c6f1ddSLingrui98    val is_old_entry = Output(Bool())
26309c6f1ddSLingrui98    val is_new_br = Output(Bool())
26409c6f1ddSLingrui98    val is_jalr_target_modified = Output(Bool())
26509c6f1ddSLingrui98    val is_always_taken_modified = Output(Bool())
26609c6f1ddSLingrui98    val is_br_full = Output(Bool())
26709c6f1ddSLingrui98  })
26809c6f1ddSLingrui98
26909c6f1ddSLingrui98  // no mispredictions detected at predecode
27009c6f1ddSLingrui98  val hit = io.hit
27109c6f1ddSLingrui98  val pd = io.pd
27209c6f1ddSLingrui98
27309c6f1ddSLingrui98  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
27409c6f1ddSLingrui98
27509c6f1ddSLingrui98
27609c6f1ddSLingrui98  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
27709c6f1ddSLingrui98  val entry_has_jmp = pd.jmpInfo.valid
27809c6f1ddSLingrui98  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
27909c6f1ddSLingrui98  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
28009c6f1ddSLingrui98  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
28109c6f1ddSLingrui98  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
28209c6f1ddSLingrui98  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
28309c6f1ddSLingrui98  val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
28409c6f1ddSLingrui98
28509c6f1ddSLingrui98  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
28609c6f1ddSLingrui98  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
28709c6f1ddSLingrui98
28809c6f1ddSLingrui98  def carryPos = log2Ceil(PredictWidth)+instOffsetBits+1
28909c6f1ddSLingrui98  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
29009c6f1ddSLingrui98  // if not hit, establish a new entry
29109c6f1ddSLingrui98  init_entry.valid := true.B
29209c6f1ddSLingrui98  // tag is left for ftb to assign
293*eeb5ff92SLingrui98
294*eeb5ff92SLingrui98  // case br
295*eeb5ff92SLingrui98  val init_br_slot = init_entry.getSlotForBr(0)
296*eeb5ff92SLingrui98  when (cfi_is_br) {
297*eeb5ff92SLingrui98    init_br_slot.valid := true.B
298*eeb5ff92SLingrui98    init_br_slot.offset := io.cfiIndex.bits
299*eeb5ff92SLingrui98    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, shareTailSlot && numBr == 1)
300*eeb5ff92SLingrui98    init_entry.always_taken(0) := true.B // set to always taken on init
301*eeb5ff92SLingrui98  }
302*eeb5ff92SLingrui98  // init_entry.isBrSharing := shareTailSlot.B && (numBr == 1).B && cfi_is_br
303*eeb5ff92SLingrui98
304*eeb5ff92SLingrui98  // case jmp
305*eeb5ff92SLingrui98  when (entry_has_jmp) {
306*eeb5ff92SLingrui98    init_entry.tailSlot.offset := pd.jmpOffset
307*eeb5ff92SLingrui98    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
308*eeb5ff92SLingrui98    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
309*eeb5ff92SLingrui98  }
310*eeb5ff92SLingrui98
31109c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
31209c6f1ddSLingrui98  init_entry.pftAddr := Mux(entry_has_jmp, jmpPft, getLower(io.start_addr) + ((FetchWidth*4)>>instOffsetBits).U + Mux(last_br_rvi, 1.U, 0.U))
31365fddcf0Szoujr  init_entry.carry   := Mux(entry_has_jmp, jmpPft(carryPos-instOffsetBits), io.start_addr(carryPos-1) || (io.start_addr(carryPos-2, instOffsetBits).andR && last_br_rvi))
31409c6f1ddSLingrui98  init_entry.isJalr := new_jmp_is_jalr
31509c6f1ddSLingrui98  init_entry.isCall := new_jmp_is_call
31609c6f1ddSLingrui98  init_entry.isRet  := new_jmp_is_ret
31709c6f1ddSLingrui98  init_entry.last_is_rvc := Mux(entry_has_jmp, pd.rvcMask(pd.jmpOffset), pd.rvcMask.last)
31809c6f1ddSLingrui98
31909c6f1ddSLingrui98  init_entry.oversize := last_br_rvi || last_jmp_rvi
32009c6f1ddSLingrui98
32109c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
32209c6f1ddSLingrui98  val oe = io.old_entry
323*eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
32409c6f1ddSLingrui98  val br_recorded = br_recorded_vec.asUInt.orR
32509c6f1ddSLingrui98  val is_new_br = cfi_is_br && !br_recorded
32609c6f1ddSLingrui98  val new_br_offset = io.cfiIndex.bits
32709c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
328*eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
32909c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map{
33009c6f1ddSLingrui98    i => i match {
331*eeb5ff92SLingrui98      case 0 =>
332*eeb5ff92SLingrui98        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
333*eeb5ff92SLingrui98      case idx =>
334*eeb5ff92SLingrui98        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
335*eeb5ff92SLingrui98        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
33609c6f1ddSLingrui98    }
33709c6f1ddSLingrui98  })
33809c6f1ddSLingrui98
33909c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
34009c6f1ddSLingrui98  for (i <- 0 until numBr) {
341*eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
342*eeb5ff92SLingrui98    when (new_br_insert_onehot(i)) {
343*eeb5ff92SLingrui98      slot.valid := true.B
344*eeb5ff92SLingrui98      slot.offset := new_br_offset
345*eeb5ff92SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, shareTailSlot && i == numBr-1)
346*eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := true.B
347*eeb5ff92SLingrui98    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
348*eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := false.B
349*eeb5ff92SLingrui98      // all other fields remain unchanged
350*eeb5ff92SLingrui98    }.otherwise {
351*eeb5ff92SLingrui98      // case i == 0, remain unchanged
352*eeb5ff92SLingrui98      if (i != 0) {
353*eeb5ff92SLingrui98        val noNeedToMoveFromFormerSlot = (shareTailSlot && i == numBr-1).B && !oe.brSlots.last.valid
354*eeb5ff92SLingrui98        when (!noNeedToMoveFromFormerSlot) {
355*eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
356*eeb5ff92SLingrui98          old_entry_modified.always_taken(i) := oe.always_taken(i)
35709c6f1ddSLingrui98        }
358*eeb5ff92SLingrui98      }
359*eeb5ff92SLingrui98    }
360*eeb5ff92SLingrui98  }
36109c6f1ddSLingrui98
362*eeb5ff92SLingrui98  // two circumstances:
363*eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
364*eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
365*eeb5ff92SLingrui98  //        the previous last br or the new br
366*eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
367*eeb5ff92SLingrui98  val pft_need_to_change = is_new_br && may_have_to_replace
36809c6f1ddSLingrui98  // it should either be the given last br or the new br
36909c6f1ddSLingrui98  when (pft_need_to_change) {
370*eeb5ff92SLingrui98    val new_pft_offset =
371*eeb5ff92SLingrui98      Mux(!oe.tailSlot.sharing || new_br_insert_onehot.asUInt.orR,
372*eeb5ff92SLingrui98        oe.tailSlot.offset,
373*eeb5ff92SLingrui98        new_br_offset
374*eeb5ff92SLingrui98      )
375*eeb5ff92SLingrui98
37609c6f1ddSLingrui98    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
37709c6f1ddSLingrui98    old_entry_modified.last_is_rvc := pd.rvcMask(new_pft_offset - 1.U) // TODO: fix this
37809c6f1ddSLingrui98    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
37909c6f1ddSLingrui98    old_entry_modified.oversize := false.B
38009c6f1ddSLingrui98    old_entry_modified.isCall := false.B
38109c6f1ddSLingrui98    old_entry_modified.isRet := false.B
382*eeb5ff92SLingrui98    old_entry_modified.isJalr := false.B
38309c6f1ddSLingrui98  }
38409c6f1ddSLingrui98
38509c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
386*eeb5ff92SLingrui98  val old_target = oe.tailSlot.getTarget(io.start_addr)
387*eeb5ff92SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
388*eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3893bcae573SLingrui98  when (jalr_target_modified) {
39009c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
39109c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
39209c6f1ddSLingrui98  }
39309c6f1ddSLingrui98
39409c6f1ddSLingrui98  val old_entry_always_taken = WireInit(oe)
39509c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
39609c6f1ddSLingrui98  for (i <- 0 until numBr) {
39709c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
39809c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
39909c6f1ddSLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !(io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i))
40009c6f1ddSLingrui98  }
40109c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
40209c6f1ddSLingrui98
40309c6f1ddSLingrui98
40409c6f1ddSLingrui98
40509c6f1ddSLingrui98  val derived_from_old_entry =
40609c6f1ddSLingrui98    Mux(is_new_br, old_entry_modified,
4073bcae573SLingrui98      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
40809c6f1ddSLingrui98
40909c6f1ddSLingrui98
41009c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
41109c6f1ddSLingrui98
41209c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
41309c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
41409c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
41509c6f1ddSLingrui98  })
41609c6f1ddSLingrui98  for (i <- 0 until numBr) {
41709c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
41809c6f1ddSLingrui98  }
41909c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
42009c6f1ddSLingrui98
42109c6f1ddSLingrui98  // for perf counters
42209c6f1ddSLingrui98  io.is_init_entry := !hit
4233bcae573SLingrui98  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
42409c6f1ddSLingrui98  io.is_new_br := hit && is_new_br
4253bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
42609c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
427*eeb5ff92SLingrui98  io.is_br_full := hit && is_new_br && may_have_to_replace
42809c6f1ddSLingrui98}
42909c6f1ddSLingrui98
43009c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
43109c6f1ddSLingrui98  with HasBackendRedirectInfo with BPUUtils with HasBPUConst {
43209c6f1ddSLingrui98  val io = IO(new Bundle {
43309c6f1ddSLingrui98    val fromBpu = Flipped(new BpuToFtqIO)
43409c6f1ddSLingrui98    val fromIfu = Flipped(new IfuToFtqIO)
43509c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
43609c6f1ddSLingrui98
43709c6f1ddSLingrui98    val toBpu = new FtqToBpuIO
43809c6f1ddSLingrui98    val toIfu = new FtqToIfuIO
43909c6f1ddSLingrui98    val toBackend = new FtqToCtrlIO
44009c6f1ddSLingrui98
44109c6f1ddSLingrui98    val bpuInfo = new Bundle {
44209c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
44309c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
44409c6f1ddSLingrui98    }
44509c6f1ddSLingrui98  })
44609c6f1ddSLingrui98  io.bpuInfo := DontCare
44709c6f1ddSLingrui98
44809c6f1ddSLingrui98  val roqFlush = io.fromBackend.roqFlush
44909c6f1ddSLingrui98  val stage2Redirect = io.fromBackend.stage2Redirect
45009c6f1ddSLingrui98  val stage3Redirect = io.fromBackend.stage3Redirect
45109c6f1ddSLingrui98
45209c6f1ddSLingrui98  val stage2Flush = stage2Redirect.valid || roqFlush.valid
45309c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
45409c6f1ddSLingrui98  val ifuFlush = Wire(Bool())
45509c6f1ddSLingrui98
45609c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
45709c6f1ddSLingrui98
45809c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
45909c6f1ddSLingrui98  val flushToIfu = !allowToIfu
46009c6f1ddSLingrui98  allowBpuIn := !ifuFlush && !roqFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
46109c6f1ddSLingrui98  allowToIfu := !ifuFlush && !roqFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
46209c6f1ddSLingrui98
46309c6f1ddSLingrui98  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
46409c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
46509c6f1ddSLingrui98
46609c6f1ddSLingrui98  // **********************************************************************
46709c6f1ddSLingrui98  // **************************** enq from bpu ****************************
46809c6f1ddSLingrui98  // **********************************************************************
46909c6f1ddSLingrui98  val new_entry_ready = validEntries < FtqSize.U
47009c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
47109c6f1ddSLingrui98
47209c6f1ddSLingrui98  val bpu_s2_resp = io.fromBpu.resp.bits.s2
47309c6f1ddSLingrui98  val bpu_s3_resp = io.fromBpu.resp.bits.s3
47409c6f1ddSLingrui98  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
47509c6f1ddSLingrui98  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
47609c6f1ddSLingrui98
47709c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
47809c6f1ddSLingrui98  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
47909c6f1ddSLingrui98  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
48009c6f1ddSLingrui98
48109c6f1ddSLingrui98  val bpu_in_resp = WireInit(io.fromBpu.resp.bits.selectedResp)
48209c6f1ddSLingrui98  val bpu_in_stage = WireInit(io.fromBpu.resp.bits.selectedRespIdx)
48309c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
48409c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
48509c6f1ddSLingrui98
48609c6f1ddSLingrui98  // read ports:                            jumpPc + redirects + loadPred + roqFlush + ifuReq1 + ifuReq2 + commitUpdate
48709c6f1ddSLingrui98  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1))
48809c6f1ddSLingrui98  // resp from uBTB
48909c6f1ddSLingrui98  ftq_pc_mem.io.wen(0) := bpu_in_fire
49009c6f1ddSLingrui98  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
49109c6f1ddSLingrui98  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
49209c6f1ddSLingrui98
49309c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
49409c6f1ddSLingrui98  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
49509c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
49609c6f1ddSLingrui98  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
49709c6f1ddSLingrui98  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
49809c6f1ddSLingrui98  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
49909c6f1ddSLingrui98
50009c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
50109c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
50209c6f1ddSLingrui98  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
50309c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
50409c6f1ddSLingrui98  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
50509c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
50609c6f1ddSLingrui98  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
50709c6f1ddSLingrui98  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
50809c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
50909c6f1ddSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
51009c6f1ddSLingrui98
51109c6f1ddSLingrui98
51209c6f1ddSLingrui98  // multi-write
51309c6f1ddSLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W)))
51409c6f1ddSLingrui98  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
51509c6f1ddSLingrui98  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
51609c6f1ddSLingrui98  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
51709c6f1ddSLingrui98
51809c6f1ddSLingrui98  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
51909c6f1ddSLingrui98  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
52009c6f1ddSLingrui98    VecInit(Seq.fill(PredictWidth)(c_invalid))
52109c6f1ddSLingrui98  }))
52209c6f1ddSLingrui98
52309c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
52409c6f1ddSLingrui98  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
52509c6f1ddSLingrui98
52609c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
52709c6f1ddSLingrui98  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
52809c6f1ddSLingrui98
52909c6f1ddSLingrui98
53009c6f1ddSLingrui98  when (bpu_in_fire) {
53109c6f1ddSLingrui98    entry_fetch_status(bpu_in_resp_idx) := f_to_send
53209c6f1ddSLingrui98    commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
53309c6f1ddSLingrui98    cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.genCfiIndex
53409c6f1ddSLingrui98    mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
53509c6f1ddSLingrui98    update_target(bpu_in_resp_idx) := bpu_in_resp.target
53609c6f1ddSLingrui98    pred_stage(bpu_in_resp_idx) := bpu_in_stage
53709c6f1ddSLingrui98  }
53809c6f1ddSLingrui98
53909c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
54009c6f1ddSLingrui98  ifuPtr := ifuPtr + io.toIfu.req.fire
54109c6f1ddSLingrui98
54209c6f1ddSLingrui98  // only use ftb result to assign hit status
54309c6f1ddSLingrui98  when (bpu_s2_resp.valid) {
54409c6f1ddSLingrui98    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.preds.hit, h_hit, h_not_hit)
54509c6f1ddSLingrui98  }
54609c6f1ddSLingrui98
54709c6f1ddSLingrui98
54809c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.valid := bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
54909c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
55009c6f1ddSLingrui98  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
55109c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
55209c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
55309c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
55409c6f1ddSLingrui98      ifuPtr := bpu_s2_resp.ftq_idx
55509c6f1ddSLingrui98    }
55609c6f1ddSLingrui98  }
55709c6f1ddSLingrui98
55809c6f1ddSLingrui98  io.toIfu.flushFromBpu.s3.valid := bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
55909c6f1ddSLingrui98  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
56009c6f1ddSLingrui98  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
56109c6f1ddSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
56209c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
56309c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
56409c6f1ddSLingrui98      ifuPtr := bpu_s3_resp.ftq_idx
56509c6f1ddSLingrui98    }
56609c6f1ddSLingrui98    XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
56709c6f1ddSLingrui98  }
56809c6f1ddSLingrui98
56909c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
57009c6f1ddSLingrui98
57109c6f1ddSLingrui98  // ****************************************************************
57209c6f1ddSLingrui98  // **************************** to ifu ****************************
57309c6f1ddSLingrui98  // ****************************************************************
57409c6f1ddSLingrui98  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire)
57509c6f1ddSLingrui98  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
57609c6f1ddSLingrui98  val last_cycle_bpu_in = RegNext(bpu_in_fire)
57709c6f1ddSLingrui98  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
57809c6f1ddSLingrui98
57909c6f1ddSLingrui98  // read pc and target
58009c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
58109c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value
58209c6f1ddSLingrui98
58309c6f1ddSLingrui98  val toIfuReq = Wire(chiselTypeOf(io.toIfu.req))
58409c6f1ddSLingrui98
58509c6f1ddSLingrui98  toIfuReq.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr
58609c6f1ddSLingrui98  toIfuReq.bits.ftqIdx := ifuPtr
58709c6f1ddSLingrui98  toIfuReq.bits.target := update_target(ifuPtr.value)
58809c6f1ddSLingrui98  toIfuReq.bits.ftqOffset := cfiIndex_vec(ifuPtr.value)
58909c6f1ddSLingrui98  toIfuReq.bits.fallThruError  := false.B
59009c6f1ddSLingrui98
59109c6f1ddSLingrui98  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
59209c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(bpu_in_bypass_buf)
59309c6f1ddSLingrui98  }.elsewhen (last_cycle_to_ifu_fire) {
59409c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.last)
59509c6f1ddSLingrui98  }.otherwise {
59609c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.init.last)
59709c6f1ddSLingrui98  }
59809c6f1ddSLingrui98
59909c6f1ddSLingrui98  io.toIfu.req <> toIfuReq
60009c6f1ddSLingrui98
60109c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
60209c6f1ddSLingrui98  when (toIfuReq.bits.fallThroughError() && entry_hit_status(ifuPtr.value) === h_hit) {
60309c6f1ddSLingrui98    when (io.toIfu.req.fire &&
60409c6f1ddSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
60509c6f1ddSLingrui98      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
60609c6f1ddSLingrui98    ) {
60709c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
60865fddcf0Szoujr      XSDebug(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
60909c6f1ddSLingrui98    }
61009c6f1ddSLingrui98    io.toIfu.req.bits.fallThruAddr   := toIfuReq.bits.startAddr + (FetchWidth*4).U
61109c6f1ddSLingrui98    io.toIfu.req.bits.fallThruError  := true.B
61209c6f1ddSLingrui98    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
61309c6f1ddSLingrui98  }
61409c6f1ddSLingrui98
61509c6f1ddSLingrui98  val ifu_req_should_be_flushed =
61609c6f1ddSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(toIfuReq.bits.ftqIdx) ||
61709c6f1ddSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage3(toIfuReq.bits.ftqIdx)
61809c6f1ddSLingrui98
61909c6f1ddSLingrui98  when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
62009c6f1ddSLingrui98    entry_fetch_status(ifuPtr.value) := f_sent
62109c6f1ddSLingrui98  }
62209c6f1ddSLingrui98
62309c6f1ddSLingrui98
62409c6f1ddSLingrui98  // *********************************************************************
62509c6f1ddSLingrui98  // **************************** wb from ifu ****************************
62609c6f1ddSLingrui98  // *********************************************************************
62709c6f1ddSLingrui98  val pdWb = io.fromIfu.pdWb
62809c6f1ddSLingrui98  val pds = pdWb.bits.pd
62909c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
63009c6f1ddSLingrui98  val ifu_wb_idx = pdWb.bits.ftqIdx.value
63109c6f1ddSLingrui98  // read ports:                                                         commit update
63209c6f1ddSLingrui98  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
63309c6f1ddSLingrui98  ftq_pd_mem.io.wen(0) := ifu_wb_valid
63409c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
63509c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
63609c6f1ddSLingrui98
63709c6f1ddSLingrui98  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
63809c6f1ddSLingrui98  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
63909c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
64009c6f1ddSLingrui98  val pd_reg       = RegEnable(pds,             enable = pdWb.valid)
64109c6f1ddSLingrui98  val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid)
64209c6f1ddSLingrui98  val wb_idx_reg   = RegEnable(ifu_wb_idx,      enable = pdWb.valid)
64309c6f1ddSLingrui98
64409c6f1ddSLingrui98  when (ifu_wb_valid) {
64509c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
64609c6f1ddSLingrui98      case (v, inRange) => v && inRange
64709c6f1ddSLingrui98    })
64809c6f1ddSLingrui98    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
64909c6f1ddSLingrui98      case (qe, v) => when (v) { qe := c_valid }
65009c6f1ddSLingrui98    }
65109c6f1ddSLingrui98  }
65209c6f1ddSLingrui98
65309c6f1ddSLingrui98  ifuWbPtr := ifuWbPtr + ifu_wb_valid
65409c6f1ddSLingrui98
65509c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := ifu_wb_idx
65609c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
65709c6f1ddSLingrui98  when (RegNext(hit_pd_valid)) {
65809c6f1ddSLingrui98    // check for false hit
65909c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
660*eeb5ff92SLingrui98    val brSlots = pred_ftb_entry.brSlots
661*eeb5ff92SLingrui98    val tailSlot = pred_ftb_entry.tailSlot
66209c6f1ddSLingrui98    // we check cfis that bpu predicted
66309c6f1ddSLingrui98
664*eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
665*eeb5ff92SLingrui98    val br_false_hit =
666*eeb5ff92SLingrui98      brSlots.map{
667*eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
668*eeb5ff92SLingrui98      }.reduce(_||_) ||
669*eeb5ff92SLingrui98      (shareTailSlot.B && tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
670*eeb5ff92SLingrui98        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
671*eeb5ff92SLingrui98
672*eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
67309c6f1ddSLingrui98    val jmp_pd = pd_reg(jmpOffset)
67409c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
67509c6f1ddSLingrui98      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
67609c6f1ddSLingrui98       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
67709c6f1ddSLingrui98       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
67809c6f1ddSLingrui98       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
67909c6f1ddSLingrui98      )
68009c6f1ddSLingrui98
68109c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
68265fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
68365fddcf0Szoujr
68465fddcf0Szoujr    // assert(!has_false_hit)
68509c6f1ddSLingrui98  }
68609c6f1ddSLingrui98
68709c6f1ddSLingrui98  when (has_false_hit) {
68809c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
68909c6f1ddSLingrui98  }
69009c6f1ddSLingrui98
69109c6f1ddSLingrui98
69209c6f1ddSLingrui98  // **********************************************************************
69309c6f1ddSLingrui98  // **************************** backend read ****************************
69409c6f1ddSLingrui98  // **********************************************************************
69509c6f1ddSLingrui98
69609c6f1ddSLingrui98  // pc reads
69709c6f1ddSLingrui98  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
69809c6f1ddSLingrui98    ftq_pc_mem.io.raddr(i) := req.ptr.value
69909c6f1ddSLingrui98    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
70009c6f1ddSLingrui98  }
70109c6f1ddSLingrui98  // target read
70209c6f1ddSLingrui98  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
70309c6f1ddSLingrui98
70409c6f1ddSLingrui98  // *******************************************************************************
70509c6f1ddSLingrui98  // **************************** redirect from backend ****************************
70609c6f1ddSLingrui98  // *******************************************************************************
70709c6f1ddSLingrui98
70809c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
70909c6f1ddSLingrui98  ftq_redirect_sram.io.ren.init.last := io.fromBackend.stage2Redirect.valid
71009c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
71109c6f1ddSLingrui98
71209c6f1ddSLingrui98  ftb_entry_mem.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
71309c6f1ddSLingrui98
71409c6f1ddSLingrui98  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
71509c6f1ddSLingrui98  val fromBackendRedirect = WireInit(io.fromBackend.stage3Redirect)
71609c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
71709c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
71809c6f1ddSLingrui98
71909c6f1ddSLingrui98  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
72009c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
72109c6f1ddSLingrui98
72209c6f1ddSLingrui98  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
72309c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
72409c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
725*eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
72609c6f1ddSLingrui98
72709c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
728*eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
72909c6f1ddSLingrui98  }.otherwise {
73009c6f1ddSLingrui98    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
73109c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
73209c6f1ddSLingrui98  }
73309c6f1ddSLingrui98
73409c6f1ddSLingrui98
73509c6f1ddSLingrui98  // ***************************************************************************
73609c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
73709c6f1ddSLingrui98  // ***************************************************************************
73809c6f1ddSLingrui98  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
73909c6f1ddSLingrui98  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
74009c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
74109c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
74209c6f1ddSLingrui98  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
74309c6f1ddSLingrui98
74409c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
74509c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
74609c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
74709c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
74809c6f1ddSLingrui98  ifuRedirectCfiUpdate.target := pdWb.bits.target
74909c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
75009c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
75109c6f1ddSLingrui98
75209c6f1ddSLingrui98  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
75309c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
75409c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
75509c6f1ddSLingrui98
75609c6f1ddSLingrui98  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
75709c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
75809c6f1ddSLingrui98
75909c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
76009c6f1ddSLingrui98
76109c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
76209c6f1ddSLingrui98  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
76309c6f1ddSLingrui98  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
76409c6f1ddSLingrui98    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
76509c6f1ddSLingrui98  }
76609c6f1ddSLingrui98
76709c6f1ddSLingrui98  // *********************************************************************
76809c6f1ddSLingrui98  // **************************** wb from exu ****************************
76909c6f1ddSLingrui98  // *********************************************************************
77009c6f1ddSLingrui98
77109c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
77209c6f1ddSLingrui98    val ftqIdx = wb.bits.ftqIdx.value
77309c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
77409c6f1ddSLingrui98    val taken = wb.bits.cfiUpdate.taken
77509c6f1ddSLingrui98    val mispred = wb.bits.cfiUpdate.isMisPred
77609c6f1ddSLingrui98    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
77709c6f1ddSLingrui98  }
77809c6f1ddSLingrui98
77909c6f1ddSLingrui98  // fix mispredict entry
78009c6f1ddSLingrui98  val lastIsMispredict = RegNext(
78109c6f1ddSLingrui98    stage2Redirect.valid && stage2Redirect.bits.level === RedirectLevel.flushAfter, init = false.B
78209c6f1ddSLingrui98  )
78309c6f1ddSLingrui98
78409c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
78509c6f1ddSLingrui98    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
78609c6f1ddSLingrui98    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
78709c6f1ddSLingrui98    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
78809c6f1ddSLingrui98    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
78909c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
79009c6f1ddSLingrui98    }
79109c6f1ddSLingrui98    when (cfiIndex_bits_wen) {
79209c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
79309c6f1ddSLingrui98    }
79409c6f1ddSLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target
79509c6f1ddSLingrui98    if (isBackend) {
79609c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
79709c6f1ddSLingrui98    }
79809c6f1ddSLingrui98  }
79909c6f1ddSLingrui98
80009c6f1ddSLingrui98  when(stage3Redirect.valid && lastIsMispredict) {
80109c6f1ddSLingrui98    updateCfiInfo(stage3Redirect)
80209c6f1ddSLingrui98  }.elsewhen (ifuRedirectToBpu.valid) {
80309c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
80409c6f1ddSLingrui98  }
80509c6f1ddSLingrui98
80609c6f1ddSLingrui98  // ***********************************************************************************
80709c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
80809c6f1ddSLingrui98  // ***********************************************************************************
80909c6f1ddSLingrui98
81009c6f1ddSLingrui98  class RedirectInfo extends Bundle {
81109c6f1ddSLingrui98    val valid = Bool()
81209c6f1ddSLingrui98    val ftqIdx = new FtqPtr
8132fe8f338SLingrui98    val ftqOffset = UInt(log2Ceil(PredictWidth).W)
81409c6f1ddSLingrui98    val flushItSelf = Bool()
81509c6f1ddSLingrui98    def apply(redirect: Valid[Redirect]) = {
81609c6f1ddSLingrui98      this.valid := redirect.valid
81709c6f1ddSLingrui98      this.ftqIdx := redirect.bits.ftqIdx
81809c6f1ddSLingrui98      this.ftqOffset := redirect.bits.ftqOffset
81909c6f1ddSLingrui98      this.flushItSelf := RedirectLevel.flushItself(redirect.bits.level)
82009c6f1ddSLingrui98      this
82109c6f1ddSLingrui98    }
82209c6f1ddSLingrui98  }
82309c6f1ddSLingrui98  val redirectVec = Wire(Vec(3, new RedirectInfo))
82409c6f1ddSLingrui98  val roqRedirect = Wire(Valid(new Redirect))
82509c6f1ddSLingrui98  roqRedirect := DontCare
82609c6f1ddSLingrui98  roqRedirect.valid := roqFlush.valid
82709c6f1ddSLingrui98  roqRedirect.bits.ftqIdx := roqFlush.bits.ftqIdx
82809c6f1ddSLingrui98  roqRedirect.bits.ftqOffset := roqFlush.bits.ftqOffset
82909c6f1ddSLingrui98  roqRedirect.bits.level := RedirectLevel.flush
83009c6f1ddSLingrui98
83109c6f1ddSLingrui98  redirectVec.zip(Seq(roqRedirect, stage2Redirect, fromIfuRedirect)).map {
83209c6f1ddSLingrui98    case (ve, r) => ve(r)
83309c6f1ddSLingrui98  }
83409c6f1ddSLingrui98
83509c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
83609c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_||_)){
83709c6f1ddSLingrui98    val r = PriorityMux(redirectVec.map(r => (r.valid -> r)))
83809c6f1ddSLingrui98    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
83909c6f1ddSLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, r.flushItSelf)
84009c6f1ddSLingrui98    val next = idx + 1.U
84109c6f1ddSLingrui98    bpuPtr := next
84209c6f1ddSLingrui98    ifuPtr := next
84309c6f1ddSLingrui98    ifuWbPtr := next
84409c6f1ddSLingrui98    when (notIfu) {
84509c6f1ddSLingrui98      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
84609c6f1ddSLingrui98        when(i.U > offset || i.U === offset && flushItSelf){
84709c6f1ddSLingrui98          s := c_invalid
84809c6f1ddSLingrui98        }
84909c6f1ddSLingrui98      })
85009c6f1ddSLingrui98    }
85109c6f1ddSLingrui98  }
85209c6f1ddSLingrui98
85309c6f1ddSLingrui98  // only the valid bit is actually needed
85409c6f1ddSLingrui98  io.toIfu.redirect := DontCare
85509c6f1ddSLingrui98  io.toIfu.redirect.valid := stage2Flush
85609c6f1ddSLingrui98
85709c6f1ddSLingrui98  // commit
85809c6f1ddSLingrui98  for (c <- io.fromBackend.roq_commits) {
85909c6f1ddSLingrui98    when(c.valid) {
86009c6f1ddSLingrui98      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
86188825c5cSYinan Xu      // TODO: remove this
86288825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
86388825c5cSYinan Xu      when (c.bits.isFused === 1.U) {
86488825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
86588825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 2.U) {
86688825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
86788825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 3.U) {
86888825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
86988825c5cSYinan Xu        commitStateQueue(index)(0) := c_commited
87088825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 4.U) {
87188825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
87288825c5cSYinan Xu        commitStateQueue(index)(1) := c_commited
87388825c5cSYinan Xu      }
87409c6f1ddSLingrui98    }
87509c6f1ddSLingrui98  }
87609c6f1ddSLingrui98
87709c6f1ddSLingrui98  // ****************************************************************
87809c6f1ddSLingrui98  // **************************** to bpu ****************************
87909c6f1ddSLingrui98  // ****************************************************************
88009c6f1ddSLingrui98
88109c6f1ddSLingrui98  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
88209c6f1ddSLingrui98
88309c6f1ddSLingrui98  val canCommit = commPtr =/= ifuWbPtr &&
88409c6f1ddSLingrui98    Cat(commitStateQueue(commPtr.value).map(s => {
88509c6f1ddSLingrui98      s === c_invalid || s === c_commited
88609c6f1ddSLingrui98    })).andR()
88709c6f1ddSLingrui98
88809c6f1ddSLingrui98  // commit reads
88909c6f1ddSLingrui98  ftq_pc_mem.io.raddr.last := commPtr.value
89009c6f1ddSLingrui98  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
89109c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last := commPtr.value
89209c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
89309c6f1ddSLingrui98  ftq_redirect_sram.io.ren.last := canCommit
89409c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.last := commPtr.value
89509c6f1ddSLingrui98  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
89609c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0) := canCommit
89709c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
89809c6f1ddSLingrui98  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
89909c6f1ddSLingrui98  ftb_entry_mem.io.raddr.last := commPtr.value
90009c6f1ddSLingrui98  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
90109c6f1ddSLingrui98
90209c6f1ddSLingrui98  // need one cycle to read mem and srams
90309c6f1ddSLingrui98  val do_commit = RegNext(canCommit, init=false.B)
90409c6f1ddSLingrui98  val do_commit_ptr = RegNext(commPtr)
90509c6f1ddSLingrui98  when (canCommit) { commPtr := commPtr + 1.U }
90609c6f1ddSLingrui98  val commit_state = RegNext(commitStateQueue(commPtr.value))
90709c6f1ddSLingrui98  val commit_cfi = WireInit(RegNext(cfiIndex_vec(commPtr.value)))
90809c6f1ddSLingrui98  when (commit_state(commit_cfi.bits) =/= c_commited) {
90909c6f1ddSLingrui98    commit_cfi.valid := false.B
91009c6f1ddSLingrui98  }
91109c6f1ddSLingrui98
91209c6f1ddSLingrui98  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
91309c6f1ddSLingrui98    case (mis, state) => mis && state === c_commited
91409c6f1ddSLingrui98  })
91509c6f1ddSLingrui98  val commit_hit = RegNext(entry_hit_status(commPtr.value))
91609c6f1ddSLingrui98  val commit_target = RegNext(update_target(commPtr.value))
91709c6f1ddSLingrui98  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
91809c6f1ddSLingrui98
91909c6f1ddSLingrui98
92009c6f1ddSLingrui98  io.toBpu.update := DontCare
92109c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
92209c6f1ddSLingrui98  val update = io.toBpu.update.bits
92309c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
92409c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
92509c6f1ddSLingrui98  update.preds.hit   := commit_hit === h_hit || commit_hit === h_false_hit
92609c6f1ddSLingrui98  update.meta        := commit_meta.meta
9278ffcd86aSLingrui98  update.full_target := commit_target
92809c6f1ddSLingrui98  update.fromFtqRedirectSram(commit_spec_meta)
92909c6f1ddSLingrui98
93009c6f1ddSLingrui98  val commit_real_hit = commit_hit === h_hit
93109c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
93209c6f1ddSLingrui98
93309c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
93409c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
93509c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
93609c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
93709c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
93809c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
93909c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
94009c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
94109c6f1ddSLingrui98
94209c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
94309c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
94409c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
94509c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
946*eeb5ff92SLingrui98  update.preds.br_taken_mask  := ftbEntryGen.taken_mask
94709c6f1ddSLingrui98
94809c6f1ddSLingrui98  // ******************************************************************************
94909c6f1ddSLingrui98  // **************************** commit perf counters ****************************
95009c6f1ddSLingrui98  // ******************************************************************************
95109c6f1ddSLingrui98
95209c6f1ddSLingrui98  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
95309c6f1ddSLingrui98  val commit_mispred_mask = commit_mispredict.asUInt
95409c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
95509c6f1ddSLingrui98
95609c6f1ddSLingrui98  val commit_br_mask = commit_pd.brMask.asUInt
95709c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
95809c6f1ddSLingrui98  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
95909c6f1ddSLingrui98
96009c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
96109c6f1ddSLingrui98
96209c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
96309c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
96409c6f1ddSLingrui98
96509c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
96609c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
96709c6f1ddSLingrui98
96809c6f1ddSLingrui98  // Cfi Info
96909c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
97009c6f1ddSLingrui98    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
97109c6f1ddSLingrui98    val v = commit_state(i) === c_commited
97209c6f1ddSLingrui98    val isBr = commit_pd.brMask(i)
97309c6f1ddSLingrui98    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
97409c6f1ddSLingrui98    val isCfi = isBr || isJmp
97509c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
97609c6f1ddSLingrui98    val misPred = commit_mispredict(i)
97709c6f1ddSLingrui98    val ghist = commit_spec_meta.ghist.predHist
97809c6f1ddSLingrui98    val predCycle = commit_meta.meta(63, 0)
97909c6f1ddSLingrui98    val target = commit_target
98009c6f1ddSLingrui98
98109c6f1ddSLingrui98    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
98209c6f1ddSLingrui98    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
98309c6f1ddSLingrui98    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
98409c6f1ddSLingrui98    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
98509c6f1ddSLingrui98    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${Hexadecimal(ghist)}) " +
98609c6f1ddSLingrui98    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
98709c6f1ddSLingrui98    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
98809c6f1ddSLingrui98  }
98909c6f1ddSLingrui98
99009c6f1ddSLingrui98  val enq = io.fromBpu.resp
99109c6f1ddSLingrui98  val perf_redirect = io.fromBackend.stage2Redirect
99209c6f1ddSLingrui98
99309c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
99409c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
99509c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
99609c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
99709c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
99809c6f1ddSLingrui98
99909c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
100009c6f1ddSLingrui98
100109c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
100209c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
100309c6f1ddSLingrui98
100409c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
100509c6f1ddSLingrui98  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
100609c6f1ddSLingrui98    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
100709c6f1ddSLingrui98    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
100809c6f1ddSLingrui98    val entry_len_map = (1 to PredictWidth+1).map(i =>
100909c6f1ddSLingrui98      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
101009c6f1ddSLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
101109c6f1ddSLingrui98    entry_len_map
101209c6f1ddSLingrui98  }
101309c6f1ddSLingrui98  val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1")
101409c6f1ddSLingrui98  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
101509c6f1ddSLingrui98  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
101609c6f1ddSLingrui98
101709c6f1ddSLingrui98  val to_ifu = io.toIfu.req.bits
101809c6f1ddSLingrui98  val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits
101909c6f1ddSLingrui98  val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U)
102009c6f1ddSLingrui98  val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i =>
102109c6f1ddSLingrui98    f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire)
102209c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
102309c6f1ddSLingrui98
102409c6f1ddSLingrui98
102509c6f1ddSLingrui98
102609c6f1ddSLingrui98  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
102709c6f1ddSLingrui98  val commit_num_inst_map = (1 to PredictWidth).map(i =>
102809c6f1ddSLingrui98    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
102909c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
103009c6f1ddSLingrui98
103109c6f1ddSLingrui98
103209c6f1ddSLingrui98
103309c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
103409c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
103509c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
103609c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
103709c6f1ddSLingrui98
103809c6f1ddSLingrui98
103909c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
104009c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
104109c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
104209c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
104309c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
104409c6f1ddSLingrui98
104509c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
104609c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
104709c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
104809c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
104909c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
105009c6f1ddSLingrui98
105109c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
105209c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
105309c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
105465fddcf0Szoujr  // assert(!ftb_false_hit)
105509c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
105609c6f1ddSLingrui98
105709c6f1ddSLingrui98  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
105809c6f1ddSLingrui98  val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid
105909c6f1ddSLingrui98  val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0)
106009c6f1ddSLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid
106109c6f1ddSLingrui98
106209c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
106309c6f1ddSLingrui98
106409c6f1ddSLingrui98  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
106509c6f1ddSLingrui98  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
106609c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
106709c6f1ddSLingrui98  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
106809c6f1ddSLingrui98  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
106909c6f1ddSLingrui98
107009c6f1ddSLingrui98  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
107109c6f1ddSLingrui98  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
107209c6f1ddSLingrui98  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
107309c6f1ddSLingrui98    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
107409c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
107509c6f1ddSLingrui98  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
107609c6f1ddSLingrui98    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
107709c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
107809c6f1ddSLingrui98
107909c6f1ddSLingrui98  val ftq_occupancy_map = (0 to FtqSize).map(i =>
108009c6f1ddSLingrui98    f"ftq_has_entry_$i" ->( validEntries === i.U)
108109c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
108209c6f1ddSLingrui98
108309c6f1ddSLingrui98  val perfCountsMap = Map(
108409c6f1ddSLingrui98    "BpInstr" -> PopCount(mbpInstrs),
108509c6f1ddSLingrui98    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
108609c6f1ddSLingrui98    "BpRight"  -> PopCount(mbpRights),
108709c6f1ddSLingrui98    "BpWrong"  -> PopCount(mbpWrongs),
108809c6f1ddSLingrui98    "BpBRight" -> PopCount(mbpBRights),
108909c6f1ddSLingrui98    "BpBWrong" -> PopCount(mbpBWrongs),
109009c6f1ddSLingrui98    "BpJRight" -> PopCount(mbpJRights),
109109c6f1ddSLingrui98    "BpJWrong" -> PopCount(mbpJWrongs),
109209c6f1ddSLingrui98    "BpIRight" -> PopCount(mbpIRights),
109309c6f1ddSLingrui98    "BpIWrong" -> PopCount(mbpIWrongs),
109409c6f1ddSLingrui98    "BpCRight" -> PopCount(mbpCRights),
109509c6f1ddSLingrui98    "BpCWrong" -> PopCount(mbpCWrongs),
109609c6f1ddSLingrui98    "BpRRight" -> PopCount(mbpRRights),
109709c6f1ddSLingrui98    "BpRWrong" -> PopCount(mbpRWrongs),
109809c6f1ddSLingrui98
109909c6f1ddSLingrui98    "ftb_false_hit"                -> PopCount(ftb_false_hit),
110009c6f1ddSLingrui98    "ftb_hit"                      -> PopCount(ftb_hit),
110109c6f1ddSLingrui98    "ftb_new_entry"                -> PopCount(ftb_new_entry),
110209c6f1ddSLingrui98    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
110309c6f1ddSLingrui98    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
110409c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
110509c6f1ddSLingrui98    "ftb_old_entry"                -> PopCount(ftb_old_entry),
110609c6f1ddSLingrui98    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
110709c6f1ddSLingrui98    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
110809c6f1ddSLingrui98    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
110909c6f1ddSLingrui98    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
111009c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
111109c6f1ddSLingrui98  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++
111209c6f1ddSLingrui98  s2_entry_len_map ++ s3_entry_len_map ++
111309c6f1ddSLingrui98  to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map
111409c6f1ddSLingrui98
111509c6f1ddSLingrui98  for((key, value) <- perfCountsMap) {
111609c6f1ddSLingrui98    XSPerfAccumulate(key, value)
111709c6f1ddSLingrui98  }
111809c6f1ddSLingrui98
111909c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
112009c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
112109c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
112209c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
112309c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
112409c6f1ddSLingrui98  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
112509c6f1ddSLingrui98    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
112609c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
112709c6f1ddSLingrui98
112809c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
112909c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
113009c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
113109c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
113209c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
113309c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
113409c6f1ddSLingrui98  //           !taken),
113509c6f1ddSLingrui98  //         !taken),
113609c6f1ddSLingrui98  //       false.B)
113709c6f1ddSLingrui98  //     }
113809c6f1ddSLingrui98  //   }
113909c6f1ddSLingrui98
114009c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
114109c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
114209c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
114309c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
114409c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
114509c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
114609c6f1ddSLingrui98  //           !taken),
114709c6f1ddSLingrui98  //         !taken),
114809c6f1ddSLingrui98  //       false.B)
114909c6f1ddSLingrui98  //     }
115009c6f1ddSLingrui98  //   }
115109c6f1ddSLingrui98
115209c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
115309c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
115409c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
115509c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
115609c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
115709c6f1ddSLingrui98  //       false.B)
115809c6f1ddSLingrui98  //     }
115909c6f1ddSLingrui98  //   }
116009c6f1ddSLingrui98
116109c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
116209c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
116309c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
116409c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
116509c6f1ddSLingrui98  //         isWrong ^ (!taken),
116609c6f1ddSLingrui98  //           false.B)
116709c6f1ddSLingrui98  //     }
116809c6f1ddSLingrui98  //   }
116909c6f1ddSLingrui98
117009c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
117109c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
117209c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
117309c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
117409c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
117509c6f1ddSLingrui98  //           false.B)
117609c6f1ddSLingrui98  //     }
117709c6f1ddSLingrui98  //   }
117809c6f1ddSLingrui98
117909c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
118009c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
118109c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
118209c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
118309c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
118409c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
118509c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
118609c6f1ddSLingrui98
118709c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
118809c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
118909c6f1ddSLingrui98
119009c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
119109c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
119209c6f1ddSLingrui98
119309c6f1ddSLingrui98}