xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision 9aca92b99bc760501680614d3be4f34b46d9ed2e)
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
241*9aca92b9SYinan Xu  def getRobFlushPcRead = 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
29309c6f1ddSLingrui98  init_entry.brValids(0) := cfi_is_br
29409c6f1ddSLingrui98  init_entry.brOffset(0) := io.cfiIndex.bits
29509c6f1ddSLingrui98  init_entry.setByBrTarget(0, io.start_addr, io.target)
29609c6f1ddSLingrui98  init_entry.always_taken(0) := cfi_is_br // set to always taken on init
29709c6f1ddSLingrui98  init_entry.always_taken(1) := false.B
29809c6f1ddSLingrui98  init_entry.jmpOffset := pd.jmpOffset
29909c6f1ddSLingrui98  init_entry.jmpValid := new_jmp_is_jal || new_jmp_is_jalr
30009c6f1ddSLingrui98  init_entry.setByJmpTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget))
30109c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
30209c6f1ddSLingrui98  init_entry.pftAddr := Mux(entry_has_jmp, jmpPft, getLower(io.start_addr) + ((FetchWidth*4)>>instOffsetBits).U + Mux(last_br_rvi, 1.U, 0.U))
30365fddcf0Szoujr  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))
30409c6f1ddSLingrui98  init_entry.isJalr := new_jmp_is_jalr
30509c6f1ddSLingrui98  init_entry.isCall := new_jmp_is_call
30609c6f1ddSLingrui98  init_entry.isRet  := new_jmp_is_ret
30709c6f1ddSLingrui98  init_entry.last_is_rvc := Mux(entry_has_jmp, pd.rvcMask(pd.jmpOffset), pd.rvcMask.last)
30809c6f1ddSLingrui98
30909c6f1ddSLingrui98  init_entry.oversize := last_br_rvi || last_jmp_rvi
31009c6f1ddSLingrui98
31109c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
31209c6f1ddSLingrui98  val oe = io.old_entry
31309c6f1ddSLingrui98  val br_recorded_vec = VecInit((oe.brValids zip oe.brOffset).map {
31409c6f1ddSLingrui98    case (v, off) => v && (off === io.cfiIndex.bits)
31509c6f1ddSLingrui98  })
31609c6f1ddSLingrui98  val br_recorded = br_recorded_vec.asUInt.orR
31709c6f1ddSLingrui98  val is_new_br = cfi_is_br && !br_recorded
31809c6f1ddSLingrui98  val br_full = oe.brValids.asUInt.andR // all slots have brs
31909c6f1ddSLingrui98  val new_br_offset = io.cfiIndex.bits
32009c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
32109c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map{
32209c6f1ddSLingrui98    i => i match {
32309c6f1ddSLingrui98      case 0 => !oe.brValids(0) || new_br_offset < oe.brOffset(0)
32409c6f1ddSLingrui98      case idx => oe.brValids(idx-1) && new_br_offset > oe.brOffset(idx-1) &&
32509c6f1ddSLingrui98        (!oe.brValids(idx) || new_br_offset < oe.brOffset(idx))
32609c6f1ddSLingrui98    }
32709c6f1ddSLingrui98  })
32809c6f1ddSLingrui98
32909c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
33009c6f1ddSLingrui98  val (new_br_lower, new_br_tar_stat) = old_entry_modified.getBrLowerStatByTarget(io.start_addr, io.target)
33109c6f1ddSLingrui98  for (i <- 0 until numBr) {
33209c6f1ddSLingrui98    old_entry_modified.brOffset(i)  :=  Mux(new_br_insert_onehot(i), new_br_offset,
33309c6f1ddSLingrui98                                          Mux(oe.brOffset(i) < new_br_offset, oe.brOffset(i),
33409c6f1ddSLingrui98                                            (if (i != 0) oe.brOffset(i-1) else oe.brOffset(i))))
33509c6f1ddSLingrui98    old_entry_modified.brLowers(i) :=  Mux(new_br_insert_onehot(i), new_br_lower,
33609c6f1ddSLingrui98                                          Mux(oe.brOffset(i) < new_br_offset, oe.brLowers(i),
33709c6f1ddSLingrui98                                            (if (i != 0) oe.brLowers(i-1) else oe.brLowers(i))))
33809c6f1ddSLingrui98    old_entry_modified.brTarStats(i) := Mux(new_br_insert_onehot(i), new_br_tar_stat,
33909c6f1ddSLingrui98                                          Mux(oe.brOffset(i) < new_br_offset, oe.brTarStats(i),
34009c6f1ddSLingrui98                                            (if (i != 0) oe.brTarStats(i-1) else oe.brTarStats(i))))
34109c6f1ddSLingrui98    old_entry_modified.always_taken(i) := Mux(new_br_insert_onehot(i), true.B,
34209c6f1ddSLingrui98                                            Mux(oe.brOffset(i) < new_br_offset, false.B,
34309c6f1ddSLingrui98                                              (if (i != 0) oe.always_taken(i-1) else oe.always_taken(i))))
34409c6f1ddSLingrui98  }
34509c6f1ddSLingrui98  old_entry_modified.brValids := VecInit((oe.brValids zip new_br_insert_onehot).map{case (v1, v2) => v1 || v2})
34609c6f1ddSLingrui98
34709c6f1ddSLingrui98  // in this case, pft_addr should be the addrs of the last br in packet
34809c6f1ddSLingrui98  val pft_need_to_change = is_new_br && br_full
34909c6f1ddSLingrui98  // it should either be the given last br or the new br
35009c6f1ddSLingrui98  when (pft_need_to_change) {
35109c6f1ddSLingrui98    val new_pft_offset = Mux(new_br_insert_onehot.asUInt.orR, oe.brOffset.last, new_br_offset)
35209c6f1ddSLingrui98    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
35309c6f1ddSLingrui98    old_entry_modified.last_is_rvc := pd.rvcMask(new_pft_offset - 1.U) // TODO: fix this
35409c6f1ddSLingrui98    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
35509c6f1ddSLingrui98    old_entry_modified.oversize := false.B
35609c6f1ddSLingrui98    old_entry_modified.jmpValid := false.B
35709c6f1ddSLingrui98    old_entry_modified.isCall := false.B
35809c6f1ddSLingrui98    old_entry_modified.isRet := false.B
35909c6f1ddSLingrui98  }
36009c6f1ddSLingrui98
36109c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
3623bcae573SLingrui98  val old_target = oe.getJmpTarget(io.start_addr)
3633bcae573SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) // TODO: pass full jalr target
3643bcae573SLingrui98  when (jalr_target_modified) {
36509c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
36609c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
36709c6f1ddSLingrui98  }
36809c6f1ddSLingrui98
36909c6f1ddSLingrui98  val old_entry_always_taken = WireInit(oe)
37009c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
37109c6f1ddSLingrui98  for (i <- 0 until numBr) {
37209c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
37309c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
37409c6f1ddSLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !(io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i))
37509c6f1ddSLingrui98  }
37609c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
37709c6f1ddSLingrui98
37809c6f1ddSLingrui98
37909c6f1ddSLingrui98
38009c6f1ddSLingrui98  val derived_from_old_entry =
38109c6f1ddSLingrui98    Mux(is_new_br, old_entry_modified,
3823bcae573SLingrui98      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
38309c6f1ddSLingrui98
38409c6f1ddSLingrui98
38509c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
38609c6f1ddSLingrui98
38709c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
38809c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
38909c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
39009c6f1ddSLingrui98  })
39109c6f1ddSLingrui98  for (i <- 0 until numBr) {
39209c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
39309c6f1ddSLingrui98  }
39409c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
39509c6f1ddSLingrui98
39609c6f1ddSLingrui98  // for perf counters
39709c6f1ddSLingrui98  io.is_init_entry := !hit
3983bcae573SLingrui98  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
39909c6f1ddSLingrui98  io.is_new_br := hit && is_new_br
4003bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
40109c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
40209c6f1ddSLingrui98  io.is_br_full := hit && is_new_br && br_full
40309c6f1ddSLingrui98}
40409c6f1ddSLingrui98
40509c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
40609c6f1ddSLingrui98  with HasBackendRedirectInfo with BPUUtils with HasBPUConst {
40709c6f1ddSLingrui98  val io = IO(new Bundle {
40809c6f1ddSLingrui98    val fromBpu = Flipped(new BpuToFtqIO)
40909c6f1ddSLingrui98    val fromIfu = Flipped(new IfuToFtqIO)
41009c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
41109c6f1ddSLingrui98
41209c6f1ddSLingrui98    val toBpu = new FtqToBpuIO
41309c6f1ddSLingrui98    val toIfu = new FtqToIfuIO
41409c6f1ddSLingrui98    val toBackend = new FtqToCtrlIO
41509c6f1ddSLingrui98
41609c6f1ddSLingrui98    val bpuInfo = new Bundle {
41709c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
41809c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
41909c6f1ddSLingrui98    }
42009c6f1ddSLingrui98  })
42109c6f1ddSLingrui98  io.bpuInfo := DontCare
42209c6f1ddSLingrui98
423*9aca92b9SYinan Xu  val robFlush = io.fromBackend.robFlush
42409c6f1ddSLingrui98  val stage2Redirect = io.fromBackend.stage2Redirect
42509c6f1ddSLingrui98  val stage3Redirect = io.fromBackend.stage3Redirect
42609c6f1ddSLingrui98
427*9aca92b9SYinan Xu  val stage2Flush = stage2Redirect.valid || robFlush.valid
42809c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
42909c6f1ddSLingrui98  val ifuFlush = Wire(Bool())
43009c6f1ddSLingrui98
43109c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
43209c6f1ddSLingrui98
43309c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
43409c6f1ddSLingrui98  val flushToIfu = !allowToIfu
435*9aca92b9SYinan Xu  allowBpuIn := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
436*9aca92b9SYinan Xu  allowToIfu := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
43709c6f1ddSLingrui98
43809c6f1ddSLingrui98  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
43909c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
44009c6f1ddSLingrui98
44109c6f1ddSLingrui98  // **********************************************************************
44209c6f1ddSLingrui98  // **************************** enq from bpu ****************************
44309c6f1ddSLingrui98  // **********************************************************************
44409c6f1ddSLingrui98  val new_entry_ready = validEntries < FtqSize.U
44509c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
44609c6f1ddSLingrui98
44709c6f1ddSLingrui98  val bpu_s2_resp = io.fromBpu.resp.bits.s2
44809c6f1ddSLingrui98  val bpu_s3_resp = io.fromBpu.resp.bits.s3
44909c6f1ddSLingrui98  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
45009c6f1ddSLingrui98  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
45109c6f1ddSLingrui98
45209c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
45309c6f1ddSLingrui98  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
45409c6f1ddSLingrui98  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
45509c6f1ddSLingrui98
45609c6f1ddSLingrui98  val bpu_in_resp = WireInit(io.fromBpu.resp.bits.selectedResp)
45709c6f1ddSLingrui98  val bpu_in_stage = WireInit(io.fromBpu.resp.bits.selectedRespIdx)
45809c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
45909c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
46009c6f1ddSLingrui98
461*9aca92b9SYinan Xu  // read ports:                            jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate
46209c6f1ddSLingrui98  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1))
46309c6f1ddSLingrui98  // resp from uBTB
46409c6f1ddSLingrui98  ftq_pc_mem.io.wen(0) := bpu_in_fire
46509c6f1ddSLingrui98  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
46609c6f1ddSLingrui98  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
46709c6f1ddSLingrui98
46809c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
46909c6f1ddSLingrui98  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
47009c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
47109c6f1ddSLingrui98  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
47209c6f1ddSLingrui98  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
47309c6f1ddSLingrui98  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
47409c6f1ddSLingrui98
47509c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
47609c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
47709c6f1ddSLingrui98  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
47809c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
47909c6f1ddSLingrui98  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
48009c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
48109c6f1ddSLingrui98  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
48209c6f1ddSLingrui98  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
48309c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
48409c6f1ddSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
48509c6f1ddSLingrui98
48609c6f1ddSLingrui98
48709c6f1ddSLingrui98  // multi-write
48809c6f1ddSLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W)))
48909c6f1ddSLingrui98  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
49009c6f1ddSLingrui98  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
49109c6f1ddSLingrui98  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
49209c6f1ddSLingrui98
49309c6f1ddSLingrui98  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
49409c6f1ddSLingrui98  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
49509c6f1ddSLingrui98    VecInit(Seq.fill(PredictWidth)(c_invalid))
49609c6f1ddSLingrui98  }))
49709c6f1ddSLingrui98
49809c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
49909c6f1ddSLingrui98  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
50009c6f1ddSLingrui98
50109c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
50209c6f1ddSLingrui98  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
50309c6f1ddSLingrui98
50409c6f1ddSLingrui98
50509c6f1ddSLingrui98  when (bpu_in_fire) {
50609c6f1ddSLingrui98    entry_fetch_status(bpu_in_resp_idx) := f_to_send
50709c6f1ddSLingrui98    commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
50809c6f1ddSLingrui98    cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.genCfiIndex
50909c6f1ddSLingrui98    mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
51009c6f1ddSLingrui98    update_target(bpu_in_resp_idx) := bpu_in_resp.target
51109c6f1ddSLingrui98    pred_stage(bpu_in_resp_idx) := bpu_in_stage
51209c6f1ddSLingrui98  }
51309c6f1ddSLingrui98
51409c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
51509c6f1ddSLingrui98  ifuPtr := ifuPtr + io.toIfu.req.fire
51609c6f1ddSLingrui98
51709c6f1ddSLingrui98  // only use ftb result to assign hit status
51809c6f1ddSLingrui98  when (bpu_s2_resp.valid) {
51909c6f1ddSLingrui98    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.preds.hit, h_hit, h_not_hit)
52009c6f1ddSLingrui98  }
52109c6f1ddSLingrui98
52209c6f1ddSLingrui98
52309c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.valid := bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
52409c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
52509c6f1ddSLingrui98  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
52609c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
52709c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
52809c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
52909c6f1ddSLingrui98      ifuPtr := bpu_s2_resp.ftq_idx
53009c6f1ddSLingrui98    }
53109c6f1ddSLingrui98  }
53209c6f1ddSLingrui98
53309c6f1ddSLingrui98  io.toIfu.flushFromBpu.s3.valid := bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
53409c6f1ddSLingrui98  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
53509c6f1ddSLingrui98  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
53609c6f1ddSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
53709c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
53809c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
53909c6f1ddSLingrui98      ifuPtr := bpu_s3_resp.ftq_idx
54009c6f1ddSLingrui98    }
54109c6f1ddSLingrui98    XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
54209c6f1ddSLingrui98  }
54309c6f1ddSLingrui98
54409c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
54509c6f1ddSLingrui98
54609c6f1ddSLingrui98  // ****************************************************************
54709c6f1ddSLingrui98  // **************************** to ifu ****************************
54809c6f1ddSLingrui98  // ****************************************************************
54909c6f1ddSLingrui98  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire)
55009c6f1ddSLingrui98  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
55109c6f1ddSLingrui98  val last_cycle_bpu_in = RegNext(bpu_in_fire)
55209c6f1ddSLingrui98  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
55309c6f1ddSLingrui98
55409c6f1ddSLingrui98  // read pc and target
55509c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
55609c6f1ddSLingrui98  ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value
55709c6f1ddSLingrui98
55809c6f1ddSLingrui98  val toIfuReq = Wire(chiselTypeOf(io.toIfu.req))
55909c6f1ddSLingrui98
56009c6f1ddSLingrui98  toIfuReq.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr
56109c6f1ddSLingrui98  toIfuReq.bits.ftqIdx := ifuPtr
56209c6f1ddSLingrui98  toIfuReq.bits.target := update_target(ifuPtr.value)
56309c6f1ddSLingrui98  toIfuReq.bits.ftqOffset := cfiIndex_vec(ifuPtr.value)
56409c6f1ddSLingrui98  toIfuReq.bits.fallThruError  := false.B
56509c6f1ddSLingrui98
56609c6f1ddSLingrui98  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
56709c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(bpu_in_bypass_buf)
56809c6f1ddSLingrui98  }.elsewhen (last_cycle_to_ifu_fire) {
56909c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.last)
57009c6f1ddSLingrui98  }.otherwise {
57109c6f1ddSLingrui98    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.init.last)
57209c6f1ddSLingrui98  }
57309c6f1ddSLingrui98
57409c6f1ddSLingrui98  io.toIfu.req <> toIfuReq
57509c6f1ddSLingrui98
57609c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
57709c6f1ddSLingrui98  when (toIfuReq.bits.fallThroughError() && entry_hit_status(ifuPtr.value) === h_hit) {
57809c6f1ddSLingrui98    when (io.toIfu.req.fire &&
57909c6f1ddSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
58009c6f1ddSLingrui98      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
58109c6f1ddSLingrui98    ) {
58209c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
58365fddcf0Szoujr      XSDebug(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
58409c6f1ddSLingrui98    }
58509c6f1ddSLingrui98    io.toIfu.req.bits.fallThruAddr   := toIfuReq.bits.startAddr + (FetchWidth*4).U
58609c6f1ddSLingrui98    io.toIfu.req.bits.fallThruError  := true.B
58709c6f1ddSLingrui98    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
58809c6f1ddSLingrui98  }
58909c6f1ddSLingrui98
59009c6f1ddSLingrui98  val ifu_req_should_be_flushed =
59109c6f1ddSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(toIfuReq.bits.ftqIdx) ||
59209c6f1ddSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage3(toIfuReq.bits.ftqIdx)
59309c6f1ddSLingrui98
59409c6f1ddSLingrui98  when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
59509c6f1ddSLingrui98    entry_fetch_status(ifuPtr.value) := f_sent
59609c6f1ddSLingrui98  }
59709c6f1ddSLingrui98
59809c6f1ddSLingrui98
59909c6f1ddSLingrui98  // *********************************************************************
60009c6f1ddSLingrui98  // **************************** wb from ifu ****************************
60109c6f1ddSLingrui98  // *********************************************************************
60209c6f1ddSLingrui98  val pdWb = io.fromIfu.pdWb
60309c6f1ddSLingrui98  val pds = pdWb.bits.pd
60409c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
60509c6f1ddSLingrui98  val ifu_wb_idx = pdWb.bits.ftqIdx.value
60609c6f1ddSLingrui98  // read ports:                                                         commit update
60709c6f1ddSLingrui98  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
60809c6f1ddSLingrui98  ftq_pd_mem.io.wen(0) := ifu_wb_valid
60909c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
61009c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
61109c6f1ddSLingrui98
61209c6f1ddSLingrui98  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
61309c6f1ddSLingrui98  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
61409c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
61509c6f1ddSLingrui98  val pd_reg       = RegEnable(pds,             enable = pdWb.valid)
61609c6f1ddSLingrui98  val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid)
61709c6f1ddSLingrui98  val wb_idx_reg   = RegEnable(ifu_wb_idx,      enable = pdWb.valid)
61809c6f1ddSLingrui98
61909c6f1ddSLingrui98  when (ifu_wb_valid) {
62009c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
62109c6f1ddSLingrui98      case (v, inRange) => v && inRange
62209c6f1ddSLingrui98    })
62309c6f1ddSLingrui98    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
62409c6f1ddSLingrui98      case (qe, v) => when (v) { qe := c_valid }
62509c6f1ddSLingrui98    }
62609c6f1ddSLingrui98  }
62709c6f1ddSLingrui98
62809c6f1ddSLingrui98  ifuWbPtr := ifuWbPtr + ifu_wb_valid
62909c6f1ddSLingrui98
63009c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := ifu_wb_idx
63109c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
63209c6f1ddSLingrui98  when (RegNext(hit_pd_valid)) {
63309c6f1ddSLingrui98    // check for false hit
63409c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
63509c6f1ddSLingrui98    // we check cfis that bpu predicted
63609c6f1ddSLingrui98    val br_false_hit = (pred_ftb_entry.brValids zip pred_ftb_entry.brOffset).map{
63709c6f1ddSLingrui98      case (v, offset) => v && !(pd_reg(offset).valid && pd_reg(offset).isBr)
63809c6f1ddSLingrui98    }.reduce(_||_)
63909c6f1ddSLingrui98
64009c6f1ddSLingrui98    val jmpOffset = pred_ftb_entry.jmpOffset
64109c6f1ddSLingrui98    val jmp_pd = pd_reg(jmpOffset)
64209c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
64309c6f1ddSLingrui98      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
64409c6f1ddSLingrui98       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
64509c6f1ddSLingrui98       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
64609c6f1ddSLingrui98       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
64709c6f1ddSLingrui98      )
64809c6f1ddSLingrui98
64909c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
65065fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
65165fddcf0Szoujr
65265fddcf0Szoujr    // assert(!has_false_hit)
65309c6f1ddSLingrui98  }
65409c6f1ddSLingrui98
65509c6f1ddSLingrui98  when (has_false_hit) {
65609c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
65709c6f1ddSLingrui98  }
65809c6f1ddSLingrui98
65909c6f1ddSLingrui98
66009c6f1ddSLingrui98  // **********************************************************************
66109c6f1ddSLingrui98  // **************************** backend read ****************************
66209c6f1ddSLingrui98  // **********************************************************************
66309c6f1ddSLingrui98
66409c6f1ddSLingrui98  // pc reads
66509c6f1ddSLingrui98  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
66609c6f1ddSLingrui98    ftq_pc_mem.io.raddr(i) := req.ptr.value
66709c6f1ddSLingrui98    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
66809c6f1ddSLingrui98  }
66909c6f1ddSLingrui98  // target read
67009c6f1ddSLingrui98  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
67109c6f1ddSLingrui98
67209c6f1ddSLingrui98  // *******************************************************************************
67309c6f1ddSLingrui98  // **************************** redirect from backend ****************************
67409c6f1ddSLingrui98  // *******************************************************************************
67509c6f1ddSLingrui98
67609c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
67709c6f1ddSLingrui98  ftq_redirect_sram.io.ren.init.last := io.fromBackend.stage2Redirect.valid
67809c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
67909c6f1ddSLingrui98
68009c6f1ddSLingrui98  ftb_entry_mem.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
68109c6f1ddSLingrui98
68209c6f1ddSLingrui98  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
68309c6f1ddSLingrui98  val fromBackendRedirect = WireInit(io.fromBackend.stage3Redirect)
68409c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
68509c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
68609c6f1ddSLingrui98
68709c6f1ddSLingrui98  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
68809c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
68909c6f1ddSLingrui98
69009c6f1ddSLingrui98  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
69109c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
69209c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
69309c6f1ddSLingrui98      !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1)))
69409c6f1ddSLingrui98
69509c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
69609c6f1ddSLingrui98        !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1)))
69709c6f1ddSLingrui98  }.otherwise {
69809c6f1ddSLingrui98    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
69909c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
70009c6f1ddSLingrui98  }
70109c6f1ddSLingrui98
70209c6f1ddSLingrui98
70309c6f1ddSLingrui98  // ***************************************************************************
70409c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
70509c6f1ddSLingrui98  // ***************************************************************************
70609c6f1ddSLingrui98  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
70709c6f1ddSLingrui98  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
70809c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
70909c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
71009c6f1ddSLingrui98  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
71109c6f1ddSLingrui98
71209c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
71309c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
71409c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
71509c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
71609c6f1ddSLingrui98  ifuRedirectCfiUpdate.target := pdWb.bits.target
71709c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
71809c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
71909c6f1ddSLingrui98
72009c6f1ddSLingrui98  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
72109c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
72209c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
72309c6f1ddSLingrui98
72409c6f1ddSLingrui98  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
72509c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
72609c6f1ddSLingrui98
72709c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
72809c6f1ddSLingrui98
72909c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
73009c6f1ddSLingrui98  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
73109c6f1ddSLingrui98  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
73209c6f1ddSLingrui98    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
73309c6f1ddSLingrui98  }
73409c6f1ddSLingrui98
73509c6f1ddSLingrui98  // *********************************************************************
73609c6f1ddSLingrui98  // **************************** wb from exu ****************************
73709c6f1ddSLingrui98  // *********************************************************************
73809c6f1ddSLingrui98
73909c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
74009c6f1ddSLingrui98    val ftqIdx = wb.bits.ftqIdx.value
74109c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
74209c6f1ddSLingrui98    val taken = wb.bits.cfiUpdate.taken
74309c6f1ddSLingrui98    val mispred = wb.bits.cfiUpdate.isMisPred
74409c6f1ddSLingrui98    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
74509c6f1ddSLingrui98  }
74609c6f1ddSLingrui98
74709c6f1ddSLingrui98  // fix mispredict entry
74809c6f1ddSLingrui98  val lastIsMispredict = RegNext(
74909c6f1ddSLingrui98    stage2Redirect.valid && stage2Redirect.bits.level === RedirectLevel.flushAfter, init = false.B
75009c6f1ddSLingrui98  )
75109c6f1ddSLingrui98
75209c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
75309c6f1ddSLingrui98    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
75409c6f1ddSLingrui98    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
75509c6f1ddSLingrui98    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
75609c6f1ddSLingrui98    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
75709c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
75809c6f1ddSLingrui98    }
75909c6f1ddSLingrui98    when (cfiIndex_bits_wen) {
76009c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
76109c6f1ddSLingrui98    }
76209c6f1ddSLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target
76309c6f1ddSLingrui98    if (isBackend) {
76409c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
76509c6f1ddSLingrui98    }
76609c6f1ddSLingrui98  }
76709c6f1ddSLingrui98
76809c6f1ddSLingrui98  when(stage3Redirect.valid && lastIsMispredict) {
76909c6f1ddSLingrui98    updateCfiInfo(stage3Redirect)
77009c6f1ddSLingrui98  }.elsewhen (ifuRedirectToBpu.valid) {
77109c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
77209c6f1ddSLingrui98  }
77309c6f1ddSLingrui98
77409c6f1ddSLingrui98  // ***********************************************************************************
77509c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
77609c6f1ddSLingrui98  // ***********************************************************************************
77709c6f1ddSLingrui98
77809c6f1ddSLingrui98  class RedirectInfo extends Bundle {
77909c6f1ddSLingrui98    val valid = Bool()
78009c6f1ddSLingrui98    val ftqIdx = new FtqPtr
78109c6f1ddSLingrui98    val ftqOffset = UInt(4.W)
78209c6f1ddSLingrui98    val flushItSelf = Bool()
78309c6f1ddSLingrui98    def apply(redirect: Valid[Redirect]) = {
78409c6f1ddSLingrui98      this.valid := redirect.valid
78509c6f1ddSLingrui98      this.ftqIdx := redirect.bits.ftqIdx
78609c6f1ddSLingrui98      this.ftqOffset := redirect.bits.ftqOffset
78709c6f1ddSLingrui98      this.flushItSelf := RedirectLevel.flushItself(redirect.bits.level)
78809c6f1ddSLingrui98      this
78909c6f1ddSLingrui98    }
79009c6f1ddSLingrui98  }
79109c6f1ddSLingrui98  val redirectVec = Wire(Vec(3, new RedirectInfo))
792*9aca92b9SYinan Xu  val robRedirect = Wire(Valid(new Redirect))
793*9aca92b9SYinan Xu  robRedirect := DontCare
794*9aca92b9SYinan Xu  robRedirect.valid := robFlush.valid
795*9aca92b9SYinan Xu  robRedirect.bits.ftqIdx := robFlush.bits.ftqIdx
796*9aca92b9SYinan Xu  robRedirect.bits.ftqOffset := robFlush.bits.ftqOffset
797*9aca92b9SYinan Xu  robRedirect.bits.level := RedirectLevel.flush
79809c6f1ddSLingrui98
799*9aca92b9SYinan Xu  redirectVec.zip(Seq(robRedirect, stage2Redirect, fromIfuRedirect)).map {
80009c6f1ddSLingrui98    case (ve, r) => ve(r)
80109c6f1ddSLingrui98  }
80209c6f1ddSLingrui98
80309c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
80409c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_||_)){
80509c6f1ddSLingrui98    val r = PriorityMux(redirectVec.map(r => (r.valid -> r)))
80609c6f1ddSLingrui98    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
80709c6f1ddSLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, r.flushItSelf)
80809c6f1ddSLingrui98    val next = idx + 1.U
80909c6f1ddSLingrui98    bpuPtr := next
81009c6f1ddSLingrui98    ifuPtr := next
81109c6f1ddSLingrui98    ifuWbPtr := next
81209c6f1ddSLingrui98    when (notIfu) {
81309c6f1ddSLingrui98      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
81409c6f1ddSLingrui98        when(i.U > offset || i.U === offset && flushItSelf){
81509c6f1ddSLingrui98          s := c_invalid
81609c6f1ddSLingrui98        }
81709c6f1ddSLingrui98      })
81809c6f1ddSLingrui98    }
81909c6f1ddSLingrui98  }
82009c6f1ddSLingrui98
82109c6f1ddSLingrui98  // only the valid bit is actually needed
82209c6f1ddSLingrui98  io.toIfu.redirect := DontCare
82309c6f1ddSLingrui98  io.toIfu.redirect.valid := stage2Flush
82409c6f1ddSLingrui98
82509c6f1ddSLingrui98  // commit
826*9aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
82709c6f1ddSLingrui98    when(c.valid) {
82809c6f1ddSLingrui98      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
82988825c5cSYinan Xu      // TODO: remove this
83088825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
83188825c5cSYinan Xu      when (c.bits.isFused === 1.U) {
83288825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
83388825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 2.U) {
83488825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
83588825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 3.U) {
83688825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
83788825c5cSYinan Xu        commitStateQueue(index)(0) := c_commited
83888825c5cSYinan Xu      }.elsewhen(c.bits.isFused === 4.U) {
83988825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
84088825c5cSYinan Xu        commitStateQueue(index)(1) := c_commited
84188825c5cSYinan Xu      }
84209c6f1ddSLingrui98    }
84309c6f1ddSLingrui98  }
84409c6f1ddSLingrui98
84509c6f1ddSLingrui98  // ****************************************************************
84609c6f1ddSLingrui98  // **************************** to bpu ****************************
84709c6f1ddSLingrui98  // ****************************************************************
84809c6f1ddSLingrui98
84909c6f1ddSLingrui98  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
85009c6f1ddSLingrui98
85109c6f1ddSLingrui98  val canCommit = commPtr =/= ifuWbPtr &&
85209c6f1ddSLingrui98    Cat(commitStateQueue(commPtr.value).map(s => {
85309c6f1ddSLingrui98      s === c_invalid || s === c_commited
85409c6f1ddSLingrui98    })).andR()
85509c6f1ddSLingrui98
85609c6f1ddSLingrui98  // commit reads
85709c6f1ddSLingrui98  ftq_pc_mem.io.raddr.last := commPtr.value
85809c6f1ddSLingrui98  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
85909c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last := commPtr.value
86009c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
86109c6f1ddSLingrui98  ftq_redirect_sram.io.ren.last := canCommit
86209c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.last := commPtr.value
86309c6f1ddSLingrui98  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
86409c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0) := canCommit
86509c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
86609c6f1ddSLingrui98  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
86709c6f1ddSLingrui98  ftb_entry_mem.io.raddr.last := commPtr.value
86809c6f1ddSLingrui98  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
86909c6f1ddSLingrui98
87009c6f1ddSLingrui98  // need one cycle to read mem and srams
87109c6f1ddSLingrui98  val do_commit = RegNext(canCommit, init=false.B)
87209c6f1ddSLingrui98  val do_commit_ptr = RegNext(commPtr)
87309c6f1ddSLingrui98  when (canCommit) { commPtr := commPtr + 1.U }
87409c6f1ddSLingrui98  val commit_state = RegNext(commitStateQueue(commPtr.value))
87509c6f1ddSLingrui98  val commit_cfi = WireInit(RegNext(cfiIndex_vec(commPtr.value)))
87609c6f1ddSLingrui98  when (commit_state(commit_cfi.bits) =/= c_commited) {
87709c6f1ddSLingrui98    commit_cfi.valid := false.B
87809c6f1ddSLingrui98  }
87909c6f1ddSLingrui98
88009c6f1ddSLingrui98  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
88109c6f1ddSLingrui98    case (mis, state) => mis && state === c_commited
88209c6f1ddSLingrui98  })
88309c6f1ddSLingrui98  val commit_hit = RegNext(entry_hit_status(commPtr.value))
88409c6f1ddSLingrui98  val commit_target = RegNext(update_target(commPtr.value))
88509c6f1ddSLingrui98  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
88609c6f1ddSLingrui98
88709c6f1ddSLingrui98
88809c6f1ddSLingrui98  io.toBpu.update := DontCare
88909c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
89009c6f1ddSLingrui98  val update = io.toBpu.update.bits
89109c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
89209c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
89309c6f1ddSLingrui98  update.preds.hit   := commit_hit === h_hit || commit_hit === h_false_hit
89409c6f1ddSLingrui98  update.meta        := commit_meta.meta
8958ffcd86aSLingrui98  update.full_target := commit_target
89609c6f1ddSLingrui98  update.fromFtqRedirectSram(commit_spec_meta)
89709c6f1ddSLingrui98
89809c6f1ddSLingrui98  val commit_real_hit = commit_hit === h_hit
89909c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
90009c6f1ddSLingrui98
90109c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
90209c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
90309c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
90409c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
90509c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
90609c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
90709c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
90809c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
90909c6f1ddSLingrui98
91009c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
91109c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
91209c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
91309c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
91409c6f1ddSLingrui98  update.preds.taken_mask  := ftbEntryGen.taken_mask
91509c6f1ddSLingrui98
91609c6f1ddSLingrui98  // ******************************************************************************
91709c6f1ddSLingrui98  // **************************** commit perf counters ****************************
91809c6f1ddSLingrui98  // ******************************************************************************
91909c6f1ddSLingrui98
92009c6f1ddSLingrui98  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
92109c6f1ddSLingrui98  val commit_mispred_mask = commit_mispredict.asUInt
92209c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
92309c6f1ddSLingrui98
92409c6f1ddSLingrui98  val commit_br_mask = commit_pd.brMask.asUInt
92509c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
92609c6f1ddSLingrui98  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
92709c6f1ddSLingrui98
92809c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
92909c6f1ddSLingrui98
93009c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
93109c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
93209c6f1ddSLingrui98
93309c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
93409c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
93509c6f1ddSLingrui98
93609c6f1ddSLingrui98  // Cfi Info
93709c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
93809c6f1ddSLingrui98    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
93909c6f1ddSLingrui98    val v = commit_state(i) === c_commited
94009c6f1ddSLingrui98    val isBr = commit_pd.brMask(i)
94109c6f1ddSLingrui98    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
94209c6f1ddSLingrui98    val isCfi = isBr || isJmp
94309c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
94409c6f1ddSLingrui98    val misPred = commit_mispredict(i)
94509c6f1ddSLingrui98    val ghist = commit_spec_meta.ghist.predHist
94609c6f1ddSLingrui98    val predCycle = commit_meta.meta(63, 0)
94709c6f1ddSLingrui98    val target = commit_target
94809c6f1ddSLingrui98
94909c6f1ddSLingrui98    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
95009c6f1ddSLingrui98    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
95109c6f1ddSLingrui98    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
95209c6f1ddSLingrui98    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
95309c6f1ddSLingrui98    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${Hexadecimal(ghist)}) " +
95409c6f1ddSLingrui98    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
95509c6f1ddSLingrui98    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
95609c6f1ddSLingrui98  }
95709c6f1ddSLingrui98
95809c6f1ddSLingrui98  val enq = io.fromBpu.resp
95909c6f1ddSLingrui98  val perf_redirect = io.fromBackend.stage2Redirect
96009c6f1ddSLingrui98
96109c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
96209c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
96309c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
96409c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
96509c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
96609c6f1ddSLingrui98
96709c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
96809c6f1ddSLingrui98
96909c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
97009c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
97109c6f1ddSLingrui98
97209c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
97309c6f1ddSLingrui98  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
97409c6f1ddSLingrui98    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
97509c6f1ddSLingrui98    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
97609c6f1ddSLingrui98    val entry_len_map = (1 to PredictWidth+1).map(i =>
97709c6f1ddSLingrui98      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
97809c6f1ddSLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
97909c6f1ddSLingrui98    entry_len_map
98009c6f1ddSLingrui98  }
98109c6f1ddSLingrui98  val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1")
98209c6f1ddSLingrui98  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
98309c6f1ddSLingrui98  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
98409c6f1ddSLingrui98
98509c6f1ddSLingrui98  val to_ifu = io.toIfu.req.bits
98609c6f1ddSLingrui98  val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits
98709c6f1ddSLingrui98  val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U)
98809c6f1ddSLingrui98  val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i =>
98909c6f1ddSLingrui98    f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire)
99009c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
99109c6f1ddSLingrui98
99209c6f1ddSLingrui98
99309c6f1ddSLingrui98
99409c6f1ddSLingrui98  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
99509c6f1ddSLingrui98  val commit_num_inst_map = (1 to PredictWidth).map(i =>
99609c6f1ddSLingrui98    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
99709c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
99809c6f1ddSLingrui98
99909c6f1ddSLingrui98
100009c6f1ddSLingrui98
100109c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
100209c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
100309c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
100409c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
100509c6f1ddSLingrui98
100609c6f1ddSLingrui98
100709c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
100809c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
100909c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
101009c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
101109c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
101209c6f1ddSLingrui98
101309c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
101409c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
101509c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
101609c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
101709c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
101809c6f1ddSLingrui98
101909c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
102009c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
102109c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
102265fddcf0Szoujr  // assert(!ftb_false_hit)
102309c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
102409c6f1ddSLingrui98
102509c6f1ddSLingrui98  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
102609c6f1ddSLingrui98  val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid
102709c6f1ddSLingrui98  val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0)
102809c6f1ddSLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid
102909c6f1ddSLingrui98
103009c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
103109c6f1ddSLingrui98
103209c6f1ddSLingrui98  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
103309c6f1ddSLingrui98  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
103409c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
103509c6f1ddSLingrui98  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
103609c6f1ddSLingrui98  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
103709c6f1ddSLingrui98
103809c6f1ddSLingrui98  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
103909c6f1ddSLingrui98  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
104009c6f1ddSLingrui98  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
104109c6f1ddSLingrui98    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
104209c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
104309c6f1ddSLingrui98  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
104409c6f1ddSLingrui98    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
104509c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
104609c6f1ddSLingrui98
104709c6f1ddSLingrui98  val ftq_occupancy_map = (0 to FtqSize).map(i =>
104809c6f1ddSLingrui98    f"ftq_has_entry_$i" ->( validEntries === i.U)
104909c6f1ddSLingrui98  ).foldLeft(Map[String, UInt]())(_+_)
105009c6f1ddSLingrui98
105109c6f1ddSLingrui98  val perfCountsMap = Map(
105209c6f1ddSLingrui98    "BpInstr" -> PopCount(mbpInstrs),
105309c6f1ddSLingrui98    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
105409c6f1ddSLingrui98    "BpRight"  -> PopCount(mbpRights),
105509c6f1ddSLingrui98    "BpWrong"  -> PopCount(mbpWrongs),
105609c6f1ddSLingrui98    "BpBRight" -> PopCount(mbpBRights),
105709c6f1ddSLingrui98    "BpBWrong" -> PopCount(mbpBWrongs),
105809c6f1ddSLingrui98    "BpJRight" -> PopCount(mbpJRights),
105909c6f1ddSLingrui98    "BpJWrong" -> PopCount(mbpJWrongs),
106009c6f1ddSLingrui98    "BpIRight" -> PopCount(mbpIRights),
106109c6f1ddSLingrui98    "BpIWrong" -> PopCount(mbpIWrongs),
106209c6f1ddSLingrui98    "BpCRight" -> PopCount(mbpCRights),
106309c6f1ddSLingrui98    "BpCWrong" -> PopCount(mbpCWrongs),
106409c6f1ddSLingrui98    "BpRRight" -> PopCount(mbpRRights),
106509c6f1ddSLingrui98    "BpRWrong" -> PopCount(mbpRWrongs),
106609c6f1ddSLingrui98
106709c6f1ddSLingrui98    "ftb_false_hit"                -> PopCount(ftb_false_hit),
106809c6f1ddSLingrui98    "ftb_hit"                      -> PopCount(ftb_hit),
106909c6f1ddSLingrui98    "ftb_new_entry"                -> PopCount(ftb_new_entry),
107009c6f1ddSLingrui98    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
107109c6f1ddSLingrui98    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
107209c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
107309c6f1ddSLingrui98    "ftb_old_entry"                -> PopCount(ftb_old_entry),
107409c6f1ddSLingrui98    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
107509c6f1ddSLingrui98    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
107609c6f1ddSLingrui98    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
107709c6f1ddSLingrui98    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
107809c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
107909c6f1ddSLingrui98  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++
108009c6f1ddSLingrui98  s2_entry_len_map ++ s3_entry_len_map ++
108109c6f1ddSLingrui98  to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map
108209c6f1ddSLingrui98
108309c6f1ddSLingrui98  for((key, value) <- perfCountsMap) {
108409c6f1ddSLingrui98    XSPerfAccumulate(key, value)
108509c6f1ddSLingrui98  }
108609c6f1ddSLingrui98
108709c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
108809c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
108909c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
109009c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
109109c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
109209c6f1ddSLingrui98  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
109309c6f1ddSLingrui98    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
109409c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
109509c6f1ddSLingrui98
109609c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
109709c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
109809c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
109909c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
110009c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
110109c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
110209c6f1ddSLingrui98  //           !taken),
110309c6f1ddSLingrui98  //         !taken),
110409c6f1ddSLingrui98  //       false.B)
110509c6f1ddSLingrui98  //     }
110609c6f1ddSLingrui98  //   }
110709c6f1ddSLingrui98
110809c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
110909c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
111009c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
111109c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
111209c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
111309c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
111409c6f1ddSLingrui98  //           !taken),
111509c6f1ddSLingrui98  //         !taken),
111609c6f1ddSLingrui98  //       false.B)
111709c6f1ddSLingrui98  //     }
111809c6f1ddSLingrui98  //   }
111909c6f1ddSLingrui98
112009c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
112109c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
112209c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
112309c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
112409c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
112509c6f1ddSLingrui98  //       false.B)
112609c6f1ddSLingrui98  //     }
112709c6f1ddSLingrui98  //   }
112809c6f1ddSLingrui98
112909c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
113009c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
113109c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
113209c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
113309c6f1ddSLingrui98  //         isWrong ^ (!taken),
113409c6f1ddSLingrui98  //           false.B)
113509c6f1ddSLingrui98  //     }
113609c6f1ddSLingrui98  //   }
113709c6f1ddSLingrui98
113809c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
113909c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
114009c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
114109c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
114209c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
114309c6f1ddSLingrui98  //           false.B)
114409c6f1ddSLingrui98  //     }
114509c6f1ddSLingrui98  //   }
114609c6f1ddSLingrui98
114709c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
114809c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
114909c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
115009c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
115109c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
115209c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
115309c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
115409c6f1ddSLingrui98
115509c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
115609c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
115709c6f1ddSLingrui98
115809c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
115909c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
116009c6f1ddSLingrui98
116109c6f1ddSLingrui98}