xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision c9bc5480d2fe5724d6f2ddb95645d7b99bb64fb8)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.frontend
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import xiangshan._
24import xiangshan.frontend.icache._
25import xiangshan.backend.CtrlToFtqIO
26import xiangshan.backend.decode.ImmUnion
27
28class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr](
29  p => p(XSCoreParamsKey).FtqSize
30){
31}
32
33object FtqPtr {
34  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
35    val ptr = Wire(new FtqPtr)
36    ptr.flag := f
37    ptr.value := v
38    ptr
39  }
40  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
41    apply(!ptr.flag, ptr.value)
42  }
43}
44
45class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
46
47  val io = IO(new Bundle() {
48    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
49    val ren = Input(Vec(numRead, Bool()))
50    val rdata = Output(Vec(numRead, gen))
51    val waddr = Input(UInt(log2Up(FtqSize).W))
52    val wen = Input(Bool())
53    val wdata = Input(gen)
54  })
55
56  for(i <- 0 until numRead){
57    val sram = Module(new SRAMTemplate(gen, FtqSize))
58    sram.io.r.req.valid := io.ren(i)
59    sram.io.r.req.bits.setIdx := io.raddr(i)
60    io.rdata(i) := sram.io.r.resp.data(0)
61    sram.io.w.req.valid := io.wen
62    sram.io.w.req.bits.setIdx := io.waddr
63    sram.io.w.req.bits.data := VecInit(io.wdata)
64  }
65
66}
67
68class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
69  val startAddr = UInt(VAddrBits.W)
70  val nextLineAddr = UInt(VAddrBits.W)
71  val isNextMask = Vec(PredictWidth, Bool())
72  val fallThruError = Bool()
73  // val carry = Bool()
74  def getPc(offset: UInt) = {
75    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
76    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits)
77    Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)),
78        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
79  }
80  def fromBranchPrediction(resp: BranchPredictionBundle) = {
81    def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1)
82    this.startAddr := resp.pc
83    this.nextLineAddr := resp.pc + (FetchWidth * 4 * 2).U // may be broken on other configs
84    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
85      (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool()
86    ))
87    this.fallThruError := resp.fallThruError
88    this
89  }
90  override def toPrintable: Printable = {
91    p"startAddr:${Hexadecimal(startAddr)}"
92  }
93}
94
95class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
96  val brMask = Vec(PredictWidth, Bool())
97  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
99  val jalTarget = UInt(VAddrBits.W)
100  val rvcMask = Vec(PredictWidth, Bool())
101  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
102  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
103  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
104  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
105
106  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
107    val pds = pdWb.pd
108    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
109    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
110    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
111                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
112    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
113    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
114    this.jalTarget := pdWb.jalTarget
115  }
116
117  def toPd(offset: UInt) = {
118    require(offset.getWidth == log2Ceil(PredictWidth))
119    val pd = Wire(new PreDecodeInfo)
120    pd.valid := true.B
121    pd.isRVC := rvcMask(offset)
122    val isBr = brMask(offset)
123    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
124    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
125    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
126    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
127    pd
128  }
129}
130
131
132
133class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
134  val rasSp = UInt(log2Ceil(RasSize).W)
135  val rasEntry = new RASEntry
136  // val specCnt = Vec(numBr, UInt(10.W))
137  // val ghist = new ShiftingGlobalHistory
138  val folded_hist = new AllFoldedHistories(foldedGHistInfos)
139  val afhob = new AllAheadFoldedHistoryOldestBits(foldedGHistInfos)
140  val lastBrNumOH = UInt((numBr+1).W)
141
142  val histPtr = new CGHPtr
143
144  def fromBranchPrediction(resp: BranchPredictionBundle) = {
145    assert(!resp.is_minimal)
146    this.rasSp := resp.rasSp
147    this.rasEntry := resp.rasTop
148    this.folded_hist := resp.folded_hist
149    this.afhob := resp.afhob
150    this.lastBrNumOH := resp.lastBrNumOH
151    this.histPtr := resp.histPtr
152    this
153  }
154}
155
156class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
157  val meta = UInt(MaxMetaLength.W)
158}
159
160class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
161  val target = UInt(VAddrBits.W)
162  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
163}
164
165// class FtqEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
166//   val startAddr = UInt(VAddrBits.W)
167//   val fallThruAddr = UInt(VAddrBits.W)
168//   val isNextMask = Vec(PredictWidth, Bool())
169
170//   val meta = UInt(MaxMetaLength.W)
171
172//   val rasSp = UInt(log2Ceil(RasSize).W)
173//   val rasEntry = new RASEntry
174//   val hist = new ShiftingGlobalHistory
175//   val specCnt = Vec(numBr, UInt(10.W))
176
177//   val valids = Vec(PredictWidth, Bool())
178//   val brMask = Vec(PredictWidth, Bool())
179//   // isJalr, isCall, isRet
180//   val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
181//   val jmpOffset = UInt(log2Ceil(PredictWidth).W)
182
183//   val mispredVec = Vec(PredictWidth, Bool())
184//   val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
185//   val target = UInt(VAddrBits.W)
186// }
187
188class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
189  val ptr = Output(new FtqPtr)
190  val offset = Output(UInt(log2Ceil(PredictWidth).W))
191  val data = Input(gen)
192  def apply(ptr: FtqPtr, offset: UInt) = {
193    this.ptr := ptr
194    this.offset := offset
195    this.data
196  }
197}
198
199
200class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
201  val redirect = Valid(new BranchPredictionRedirect)
202  val update = Valid(new BranchPredictionUpdate)
203  val enq_ptr = Output(new FtqPtr)
204}
205
206class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
207  val req = Decoupled(new FetchRequestBundle)
208  val redirect = Valid(new Redirect)
209  val flushFromBpu = new Bundle {
210    // when ifu pipeline is not stalled,
211    // a packet from bpu s3 can reach f1 at most
212    val s2 = Valid(new FtqPtr)
213    val s3 = Valid(new FtqPtr)
214    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
215      src.valid && !isAfter(src.bits, idx_to_flush)
216    }
217    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
218    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
219  }
220}
221
222trait HasBackendRedirectInfo extends HasXSParameter {
223  def numRedirectPcRead = exuParameters.JmpCnt + exuParameters.AluCnt + 1
224  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
225}
226
227class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
228  val pc_reads = Vec(1 + numRedirectPcRead + 1 + 1, Flipped(new FtqRead(UInt(VAddrBits.W))))
229  val target_read = Flipped(new FtqRead(UInt(VAddrBits.W)))
230  val redirect_s1_real_pc = Output(UInt(VAddrBits.W))
231  def getJumpPcRead = pc_reads.head
232  def getRedirectPcRead = VecInit(pc_reads.tail.dropRight(2))
233  def getRedirectPcReadData = pc_reads.tail.dropRight(2).map(_.data)
234  def getMemPredPcRead = pc_reads.init.last
235  def getRobFlushPcRead = pc_reads.last
236}
237
238
239class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
240  val io = IO(new Bundle {
241    val start_addr = Input(UInt(VAddrBits.W))
242    val old_entry = Input(new FTBEntry)
243    val pd = Input(new Ftq_pd_Entry)
244    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
245    val target = Input(UInt(VAddrBits.W))
246    val hit = Input(Bool())
247    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
248
249    val new_entry = Output(new FTBEntry)
250    val new_br_insert_pos = Output(Vec(numBr, Bool()))
251    val taken_mask = Output(Vec(numBr, Bool()))
252    val mispred_mask = Output(Vec(numBr+1, Bool()))
253
254    // for perf counters
255    val is_init_entry = Output(Bool())
256    val is_old_entry = Output(Bool())
257    val is_new_br = Output(Bool())
258    val is_jalr_target_modified = Output(Bool())
259    val is_always_taken_modified = Output(Bool())
260    val is_br_full = Output(Bool())
261  })
262
263  // no mispredictions detected at predecode
264  val hit = io.hit
265  val pd = io.pd
266
267  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
268
269
270  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
271  val entry_has_jmp = pd.jmpInfo.valid
272  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
273  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
274  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
275  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
276  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
277  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
278
279  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
280  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
281
282  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
283  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
284  // if not hit, establish a new entry
285  init_entry.valid := true.B
286  // tag is left for ftb to assign
287
288  // case br
289  val init_br_slot = init_entry.getSlotForBr(0)
290  when (cfi_is_br) {
291    init_br_slot.valid := true.B
292    init_br_slot.offset := io.cfiIndex.bits
293    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
294    init_entry.always_taken(0) := true.B // set to always taken on init
295  }
296
297  // case jmp
298  when (entry_has_jmp) {
299    init_entry.tailSlot.offset := pd.jmpOffset
300    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
301    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
302  }
303
304  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
305  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
306  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
307  init_entry.isJalr := new_jmp_is_jalr
308  init_entry.isCall := new_jmp_is_call
309  init_entry.isRet  := new_jmp_is_ret
310  // that means fall thru points to the middle of an inst
311  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
312
313  // if hit, check whether a new cfi(only br is possible) is detected
314  val oe = io.old_entry
315  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
316  val br_recorded = br_recorded_vec.asUInt.orR
317  val is_new_br = cfi_is_br && !br_recorded
318  val new_br_offset = io.cfiIndex.bits
319  // vec(i) means new br will be inserted BEFORE old br(i)
320  val allBrSlotsVec = oe.allSlotsForBr
321  val new_br_insert_onehot = VecInit((0 until numBr).map{
322    i => i match {
323      case 0 =>
324        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
325      case idx =>
326        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
327        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
328    }
329  })
330
331  val old_entry_modified = WireInit(io.old_entry)
332  for (i <- 0 until numBr) {
333    val slot = old_entry_modified.allSlotsForBr(i)
334    when (new_br_insert_onehot(i)) {
335      slot.valid := true.B
336      slot.offset := new_br_offset
337      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
338      old_entry_modified.always_taken(i) := true.B
339    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
340      old_entry_modified.always_taken(i) := false.B
341      // all other fields remain unchanged
342    }.otherwise {
343      // case i == 0, remain unchanged
344      if (i != 0) {
345        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
346        when (!noNeedToMoveFromFormerSlot) {
347          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
348          old_entry_modified.always_taken(i) := oe.always_taken(i)
349        }
350      }
351    }
352  }
353
354  // two circumstances:
355  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
356  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
357  //        the previous last br or the new br
358  val may_have_to_replace = oe.noEmptySlotForNewBr
359  val pft_need_to_change = is_new_br && may_have_to_replace
360  // it should either be the given last br or the new br
361  when (pft_need_to_change) {
362    val new_pft_offset =
363      Mux(!new_br_insert_onehot.asUInt.orR,
364        new_br_offset, oe.allSlotsForBr.last.offset)
365
366    // set jmp to invalid
367    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
368    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
369    old_entry_modified.last_may_be_rvi_call := false.B
370    old_entry_modified.isCall := false.B
371    old_entry_modified.isRet := false.B
372    old_entry_modified.isJalr := false.B
373  }
374
375  val old_entry_jmp_target_modified = WireInit(oe)
376  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
377  val old_tail_is_jmp = !oe.tailSlot.sharing
378  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
379  when (jalr_target_modified) {
380    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
381    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
382  }
383
384  val old_entry_always_taken = WireInit(oe)
385  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
386  for (i <- 0 until numBr) {
387    old_entry_always_taken.always_taken(i) :=
388      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
389    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
390  }
391  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
392
393
394
395  val derived_from_old_entry =
396    Mux(is_new_br, old_entry_modified,
397      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
398
399
400  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
401
402  io.new_br_insert_pos := new_br_insert_onehot
403  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
404    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
405  })
406  for (i <- 0 until numBr) {
407    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
408  }
409  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
410
411  // for perf counters
412  io.is_init_entry := !hit
413  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
414  io.is_new_br := hit && is_new_br
415  io.is_jalr_target_modified := hit && jalr_target_modified
416  io.is_always_taken_modified := hit && always_taken_modified
417  io.is_br_full := hit && is_new_br && may_have_to_replace
418}
419
420class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
421  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
422  with HasICacheParameters{
423  val io = IO(new Bundle {
424    val fromBpu = Flipped(new BpuToFtqIO)
425    val fromIfu = Flipped(new IfuToFtqIO)
426    val fromBackend = Flipped(new CtrlToFtqIO)
427
428    val toBpu = new FtqToBpuIO
429    val toIfu = new FtqToIfuIO
430    val toBackend = new FtqToCtrlIO
431
432    val toPrefetch = new FtqPrefechBundle
433
434    val bpuInfo = new Bundle {
435      val bpRight = Output(UInt(XLEN.W))
436      val bpWrong = Output(UInt(XLEN.W))
437    }
438  })
439  io.bpuInfo := DontCare
440
441  val backendRedirect = Wire(Valid(new Redirect))
442  val backendRedirectReg = RegNext(backendRedirect)
443
444  val stage2Flush = backendRedirect.valid
445  val backendFlush = stage2Flush || RegNext(stage2Flush)
446  val ifuFlush = Wire(Bool())
447
448  val flush = stage2Flush || RegNext(stage2Flush)
449
450  val allowBpuIn, allowToIfu = WireInit(false.B)
451  val flushToIfu = !allowToIfu
452  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
453  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
454
455  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
456  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
457  val validEntries = distanceBetween(bpuPtr, commPtr)
458
459  // **********************************************************************
460  // **************************** enq from bpu ****************************
461  // **********************************************************************
462  val new_entry_ready = validEntries < FtqSize.U
463  io.fromBpu.resp.ready := new_entry_ready
464
465  val bpu_s2_resp = io.fromBpu.resp.bits.s2
466  val bpu_s3_resp = io.fromBpu.resp.bits.s3
467  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
468  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
469
470  io.toBpu.enq_ptr := bpuPtr
471  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
472  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
473
474  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
475  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx
476  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
477  val bpu_in_resp_idx = bpu_in_resp_ptr.value
478
479  // read ports:                            jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate
480  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirectPcRead+2+1+1+1, 1))
481  // resp from uBTB
482  ftq_pc_mem.io.wen(0) := bpu_in_fire
483  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
484  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
485
486  //                                                            ifuRedirect + backendRedirect + commit
487  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
488  // these info is intended to enq at the last stage of bpu
489  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
490  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
491  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
492  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
493  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
494
495  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
496  // these info is intended to enq at the last stage of bpu
497  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
498  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
499  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
500  //                                                            ifuRedirect + backendRedirect + commit
501  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
502  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
503  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
504  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
505
506
507  // multi-write
508  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough
509  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
510  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
511  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
512
513  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
514  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
515    VecInit(Seq.fill(PredictWidth)(c_invalid))
516  }))
517
518  val f_to_send :: f_sent :: Nil = Enum(2)
519  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
520
521  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
522  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
523
524  // modify registers one cycle later to cut critical path
525  val last_cycle_bpu_in = RegNext(bpu_in_fire)
526  val last_cycle_bpu_in_idx = RegNext(bpu_in_resp_idx)
527  val last_cycle_update_target = RegNext(bpu_in_resp.getTarget)
528  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex)
529  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
530  when (last_cycle_bpu_in) {
531    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
532    commitStateQueue(last_cycle_bpu_in_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
533    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
534    mispredict_vec(last_cycle_bpu_in_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
535    update_target(last_cycle_bpu_in_idx) := last_cycle_update_target
536    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
537  }
538
539
540  bpuPtr := bpuPtr + enq_fire
541  when (io.toIfu.req.fire && allowToIfu) {
542    ifuPtr := ifuPtrPlus1
543    ifuPtrPlus1 := ifuPtrPlus1 + 1.U
544  }
545
546  // only use ftb result to assign hit status
547  when (bpu_s2_resp.valid) {
548    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit)
549  }
550
551
552  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
553  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
554  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
555    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
556    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
557    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
558      ifuPtr := bpu_s2_resp.ftq_idx
559      ifuPtrPlus1 := bpu_s2_resp.ftq_idx + 1.U
560    }
561  }
562
563  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
564  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
565  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
566    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
567    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
568    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
569      ifuPtr := bpu_s3_resp.ftq_idx
570      ifuPtrPlus1 := bpu_s3_resp.ftq_idx + 1.U
571    }
572  }
573
574  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
575
576  // ****************************************************************
577  // **************************** to ifu ****************************
578  // ****************************************************************
579  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), bpu_in_fire)
580  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
581  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
582
583  // read pc and target
584  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
585  ftq_pc_mem.io.raddr.init.last := ifuPtrPlus1.value
586
587  io.toIfu.req.bits.ftqIdx := ifuPtr
588
589
590  val toIfuPcBundle = Wire(new Ftq_RF_Components)
591  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
592  val entry_next_addr = WireInit(update_target(ifuPtr.value))
593  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
594
595
596  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
597    toIfuPcBundle := bpu_in_bypass_buf
598    entry_is_to_send := true.B
599    entry_next_addr := last_cycle_update_target
600    entry_ftq_offset := last_cycle_cfiIndex
601  }.elsewhen (last_cycle_to_ifu_fire) {
602    toIfuPcBundle := ftq_pc_mem.io.rdata.init.last
603    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
604                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
605  }.otherwise {
606    toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last
607    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send)
608  }
609
610  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
611  io.toIfu.req.bits.nextStartAddr := entry_next_addr
612  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
613  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
614
615  // when fall through is smaller in value than start address, there must be a false hit
616  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
617    when (io.toIfu.req.fire &&
618      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
619      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
620    ) {
621      entry_hit_status(ifuPtr.value) := h_false_hit
622      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
623    }
624    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
625  }
626
627  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
628    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
629
630  val ifu_req_should_be_flushed =
631    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
632    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
633
634    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
635      entry_fetch_status(ifuPtr.value) := f_sent
636    }
637
638  // *********************************************************************
639  // **************************** wb from ifu ****************************
640  // *********************************************************************
641  val pdWb = io.fromIfu.pdWb
642  val pds = pdWb.bits.pd
643  val ifu_wb_valid = pdWb.valid
644  val ifu_wb_idx = pdWb.bits.ftqIdx.value
645  // read ports:                                                         commit update
646  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
647  ftq_pd_mem.io.wen(0) := ifu_wb_valid
648  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
649  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
650
651  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
652  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
653  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
654  val pd_reg       = RegEnable(pds,             pdWb.valid)
655  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
656  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
657
658  when (ifu_wb_valid) {
659    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
660      case (v, inRange) => v && inRange
661    })
662    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
663      case (qe, v) => when (v) { qe := c_valid }
664    }
665  }
666
667  ifuWbPtr := ifuWbPtr + ifu_wb_valid
668
669  ftb_entry_mem.io.raddr.head := ifu_wb_idx
670  val has_false_hit = WireInit(false.B)
671  when (RegNext(hit_pd_valid)) {
672    // check for false hit
673    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
674    val brSlots = pred_ftb_entry.brSlots
675    val tailSlot = pred_ftb_entry.tailSlot
676    // we check cfis that bpu predicted
677
678    // bpu predicted branches but denied by predecode
679    val br_false_hit =
680      brSlots.map{
681        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
682      }.reduce(_||_) ||
683      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
684        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
685
686    val jmpOffset = tailSlot.offset
687    val jmp_pd = pd_reg(jmpOffset)
688    val jal_false_hit = pred_ftb_entry.jmpValid &&
689      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
690       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
691       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
692       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
693      )
694
695    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
696    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
697
698    // assert(!has_false_hit)
699  }
700
701  when (has_false_hit) {
702    entry_hit_status(wb_idx_reg) := h_false_hit
703  }
704
705
706  // **********************************************************************
707  // **************************** backend read ****************************
708  // **********************************************************************
709
710  // pc reads
711  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
712    ftq_pc_mem.io.raddr(i) := req.ptr.value
713    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
714  }
715  // target read
716  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
717
718  // *******************************************************************************
719  // **************************** redirect from backend ****************************
720  // *******************************************************************************
721
722  // redirect read cfiInfo, couples to redirectGen s2
723  ftq_redirect_sram.io.ren.init.last := backendRedirect.valid
724  ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
725
726  ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
727
728  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
729  val fromBackendRedirect = WireInit(backendRedirectReg)
730  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
731  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
732
733  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
734  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
735
736  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
737    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
738      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
739      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
740
741    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
742        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
743  }.otherwise {
744    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
745    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
746  }
747
748
749  // ***************************************************************************
750  // **************************** redirect from ifu ****************************
751  // ***************************************************************************
752  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
753  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
754  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
755  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
756  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
757
758  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
759  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
760  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
761  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
762  ifuRedirectCfiUpdate.target := pdWb.bits.target
763  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
764  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
765
766  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
767  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
768  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
769
770  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
771  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
772
773  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
774
775  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
776  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
777  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
778    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
779  }
780
781  // *********************************************************************
782  // **************************** wb from exu ****************************
783  // *********************************************************************
784
785  class RedirectGen(implicit p: Parameters) extends XSModule
786    with HasCircularQueuePtrHelper {
787    val io = IO(new Bundle {
788      val in = Flipped((new CtrlToFtqIO).for_redirect_gen)
789      val stage1Pc = Input(Vec(numRedirectPcRead, UInt(VAddrBits.W)))
790      val out = Valid(new Redirect)
791      val s1_real_pc = Output(UInt(VAddrBits.W))
792      val debug_diff = Flipped(Valid(new Redirect))
793    })
794    val s1_jumpTarget = io.in.s1_jumpTarget
795    val s1_uop = io.in.s1_oldest_exu_output.bits.uop
796    val s1_imm12_reg = s1_uop.ctrl.imm(11,0)
797    val s1_pd = s1_uop.cf.pd
798    val s1_isReplay = io.in.s1_redirect_onehot.last
799    val s1_isJump = io.in.s1_redirect_onehot.head
800    val real_pc = Mux1H(io.in.s1_redirect_onehot, io.stage1Pc)
801    val brTarget = real_pc + SignExt(ImmUnion.B.toImm32(s1_imm12_reg), XLEN)
802    val snpc = real_pc + Mux(s1_pd.isRVC, 2.U, 4.U)
803    val target = Mux(s1_isReplay,
804      real_pc,
805      Mux(io.in.s1_oldest_redirect.bits.cfiUpdate.taken,
806        Mux(s1_isJump, io.in.s1_jumpTarget, brTarget),
807        snpc
808      )
809    )
810
811    val redirectGenRes = WireInit(io.in.rawRedirect)
812    redirectGenRes.bits.cfiUpdate.pc := real_pc
813    redirectGenRes.bits.cfiUpdate.pd := s1_pd
814    redirectGenRes.bits.cfiUpdate.target := target
815
816    val realRedirect = Wire(Valid(new Redirect))
817    realRedirect.valid := redirectGenRes.valid || io.in.flushRedirect.valid
818    realRedirect.bits := Mux(io.in.flushRedirect.valid, io.in.flushRedirect.bits, redirectGenRes.bits)
819
820    when (io.in.flushRedirect.valid) {
821      realRedirect.bits.level := RedirectLevel.flush
822      realRedirect.bits.cfiUpdate.target := io.in.frontendFlushTarget
823    }
824
825    io.out := realRedirect
826    io.s1_real_pc := real_pc
827    XSError((io.debug_diff.valid || realRedirect.valid) && io.debug_diff.asUInt =/= io.out.asUInt, "redirect wrong")
828
829  }
830
831  val redirectGen = Module(new RedirectGen)
832  redirectGen.io.in <> io.fromBackend.for_redirect_gen
833  redirectGen.io.stage1Pc := io.toBackend.getRedirectPcReadData
834  redirectGen.io.debug_diff := io.fromBackend.redirect
835  backendRedirect := redirectGen.io.out
836
837  io.toBackend.redirect_s1_real_pc := redirectGen.io.s1_real_pc
838
839  def extractRedirectInfo(wb: Valid[Redirect]) = {
840    val ftqIdx = wb.bits.ftqIdx.value
841    val ftqOffset = wb.bits.ftqOffset
842    val taken = wb.bits.cfiUpdate.taken
843    val mispred = wb.bits.cfiUpdate.isMisPred
844    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
845  }
846
847  // fix mispredict entry
848  val lastIsMispredict = RegNext(
849    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
850  )
851
852  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
853    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
854    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
855    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
856    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
857      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
858    }
859    when (cfiIndex_bits_wen) {
860      cfiIndex_vec(r_idx).bits := r_offset
861    }
862    update_target(r_idx) := redirect.bits.cfiUpdate.target
863    if (isBackend) {
864      mispredict_vec(r_idx)(r_offset) := r_mispred
865    }
866  }
867
868  when(backendRedirectReg.valid && lastIsMispredict) {
869    updateCfiInfo(backendRedirectReg)
870  }.elsewhen (ifuRedirectToBpu.valid) {
871    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
872  }
873
874  // ***********************************************************************************
875  // **************************** flush ptr and state queue ****************************
876  // ***********************************************************************************
877
878  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
879
880  // when redirect, we should reset ptrs and status queues
881  when(redirectVec.map(r => r.valid).reduce(_||_)){
882    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
883    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
884    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
885    val next = idx + 1.U
886    bpuPtr := next
887    ifuPtr := next
888    ifuWbPtr := next
889    ifuPtrPlus1 := idx + 2.U
890    when (notIfu) {
891      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
892        when(i.U > offset || i.U === offset && flushItSelf){
893          s := c_invalid
894        }
895      })
896    }
897  }
898
899  // only the valid bit is actually needed
900  io.toIfu.redirect.bits    := backendRedirect.bits
901  io.toIfu.redirect.valid   := stage2Flush
902
903  // commit
904  for (c <- io.fromBackend.rob_commits) {
905    when(c.valid) {
906      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
907      // TODO: remove this
908      // For instruction fusions, we also update the next instruction
909      when (c.bits.commitType === 4.U) {
910        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
911      }.elsewhen(c.bits.commitType === 5.U) {
912        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
913      }.elsewhen(c.bits.commitType === 6.U) {
914        val index = (c.bits.ftqIdx + 1.U).value
915        commitStateQueue(index)(0) := c_commited
916      }.elsewhen(c.bits.commitType === 7.U) {
917        val index = (c.bits.ftqIdx + 1.U).value
918        commitStateQueue(index)(1) := c_commited
919      }
920    }
921  }
922
923  // ****************************************************************
924  // **************************** to bpu ****************************
925  // ****************************************************************
926
927  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
928
929  val may_have_stall_from_bpu = RegInit(false.B)
930  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
931    Cat(commitStateQueue(commPtr.value).map(s => {
932      s === c_invalid || s === c_commited
933    })).andR()
934
935  // commit reads
936  ftq_pc_mem.io.raddr.last := commPtr.value
937  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
938  ftq_pd_mem.io.raddr.last := commPtr.value
939  val commit_pd = ftq_pd_mem.io.rdata.last
940  ftq_redirect_sram.io.ren.last := canCommit
941  ftq_redirect_sram.io.raddr.last := commPtr.value
942  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
943  ftq_meta_1r_sram.io.ren(0) := canCommit
944  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
945  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
946  ftb_entry_mem.io.raddr.last := commPtr.value
947  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
948
949  // need one cycle to read mem and srams
950  val do_commit_ptr = RegNext(commPtr)
951  val do_commit = RegNext(canCommit, init=false.B)
952  when (canCommit) { commPtr := commPtr + 1.U }
953  val commit_state = RegNext(commitStateQueue(commPtr.value))
954  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
955  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
956    can_commit_cfi.valid := false.B
957  }
958  val commit_cfi = RegNext(can_commit_cfi)
959
960  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
961    case (mis, state) => mis && state === c_commited
962  })
963  val can_commit_hit = entry_hit_status(commPtr.value)
964  val commit_hit = RegNext(can_commit_hit)
965  val commit_target = RegNext(update_target(commPtr.value))
966  val commit_stage = RegNext(pred_stage(commPtr.value))
967  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
968
969  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
970  may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu
971
972  io.toBpu.update := DontCare
973  io.toBpu.update.valid := commit_valid && do_commit
974  val update = io.toBpu.update.bits
975  update.false_hit   := commit_hit === h_false_hit
976  update.pc          := commit_pc_bundle.startAddr
977  update.meta        := commit_meta.meta
978  update.full_target := commit_target
979  update.from_stage  := commit_stage
980  update.fromFtqRedirectSram(commit_spec_meta)
981
982  val commit_real_hit = commit_hit === h_hit
983  val update_ftb_entry = update.ftb_entry
984
985  val ftbEntryGen = Module(new FTBEntryGen).io
986  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
987  ftbEntryGen.old_entry      := commit_ftb_entry
988  ftbEntryGen.pd             := commit_pd
989  ftbEntryGen.cfiIndex       := commit_cfi
990  ftbEntryGen.target         := commit_target
991  ftbEntryGen.hit            := commit_real_hit
992  ftbEntryGen.mispredict_vec := commit_mispredict
993
994  update_ftb_entry         := ftbEntryGen.new_entry
995  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
996  update.mispred_mask      := ftbEntryGen.mispred_mask
997  update.old_entry         := ftbEntryGen.is_old_entry
998  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
999
1000  update.is_minimal := false.B
1001  update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1002  update.full_pred.br_taken_mask  := ftbEntryGen.taken_mask
1003  update.full_pred.jalr_target := commit_target
1004  update.full_pred.hit := true.B
1005  when (update.full_pred.is_jalr) {
1006    update.full_pred.targets.last := commit_target
1007  }
1008
1009  // ****************************************************************
1010  // *********************** to prefetch ****************************
1011  // ****************************************************************
1012
1013  if(cacheParams.hasPrefetch){
1014    val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1015    prefetchPtr := prefetchPtr + io.toPrefetch.req.fire()
1016
1017    when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) {
1018      prefetchPtr := bpu_s2_resp.ftq_idx
1019    }
1020
1021    when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) {
1022      prefetchPtr := bpu_s3_resp.ftq_idx
1023      // XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
1024    }
1025
1026
1027    val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send)
1028    val prefetch_addr = WireInit(update_target(prefetchPtr.value))
1029
1030    when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) {
1031      prefetch_is_to_send := true.B
1032      prefetch_addr := last_cycle_update_target
1033    }
1034    io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send
1035    io.toPrefetch.req.bits.target := prefetch_addr
1036
1037    when(redirectVec.map(r => r.valid).reduce(_||_)){
1038      val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1039      val next = r.ftqIdx + 1.U
1040      prefetchPtr := next
1041    }
1042
1043    XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n")
1044    XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n")
1045  }
1046  else {
1047    io.toPrefetch.req <> DontCare
1048  }
1049
1050  // ******************************************************************************
1051  // **************************** commit perf counters ****************************
1052  // ******************************************************************************
1053
1054  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1055  val commit_mispred_mask = commit_mispredict.asUInt
1056  val commit_not_mispred_mask = ~commit_mispred_mask
1057
1058  val commit_br_mask = commit_pd.brMask.asUInt
1059  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1060  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1061
1062  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1063
1064  val mbpRights = mbpInstrs & commit_not_mispred_mask
1065  val mbpWrongs = mbpInstrs & commit_mispred_mask
1066
1067  io.bpuInfo.bpRight := PopCount(mbpRights)
1068  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1069
1070  // Cfi Info
1071  for (i <- 0 until PredictWidth) {
1072    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1073    val v = commit_state(i) === c_commited
1074    val isBr = commit_pd.brMask(i)
1075    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1076    val isCfi = isBr || isJmp
1077    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1078    val misPred = commit_mispredict(i)
1079    // val ghist = commit_spec_meta.ghist.predHist
1080    val histPtr = commit_spec_meta.histPtr
1081    val predCycle = commit_meta.meta(63, 0)
1082    val target = commit_target
1083
1084    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1085    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1086    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1087    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1088    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1089    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1090    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1091  }
1092
1093  val enq = io.fromBpu.resp
1094  val perf_redirect = backendRedirect
1095
1096  XSPerfAccumulate("entry", validEntries)
1097  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1098  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1099  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1100  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1101
1102  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1103
1104  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1105  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1106  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1107
1108  val from_bpu = io.fromBpu.resp.bits
1109  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
1110    assert(!resp.is_minimal)
1111    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
1112    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
1113    val entry_len_map = (1 to PredictWidth+1).map(i =>
1114      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
1115    ).foldLeft(Map[String, UInt]())(_+_)
1116    entry_len_map
1117  }
1118  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
1119  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
1120
1121  val to_ifu = io.toIfu.req.bits
1122
1123
1124
1125  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
1126  val commit_num_inst_map = (1 to PredictWidth).map(i =>
1127    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
1128  ).foldLeft(Map[String, UInt]())(_+_)
1129
1130
1131
1132  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1133  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1134  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1135  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1136
1137
1138  val mbpBRights = mbpRights & commit_br_mask
1139  val mbpJRights = mbpRights & commit_jal_mask
1140  val mbpIRights = mbpRights & commit_jalr_mask
1141  val mbpCRights = mbpRights & commit_call_mask
1142  val mbpRRights = mbpRights & commit_ret_mask
1143
1144  val mbpBWrongs = mbpWrongs & commit_br_mask
1145  val mbpJWrongs = mbpWrongs & commit_jal_mask
1146  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1147  val mbpCWrongs = mbpWrongs & commit_call_mask
1148  val mbpRWrongs = mbpWrongs & commit_ret_mask
1149
1150  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1151
1152  def pred_stage_map(src: UInt, name: String) = {
1153    (0 until numBpStages).map(i =>
1154      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1155    ).foldLeft(Map[String, UInt]())(_+_)
1156  }
1157
1158  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1159  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1160  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1161  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1162  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1163  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1164
1165  val update_valid = io.toBpu.update.valid
1166  def u(cond: Bool) = update_valid && cond
1167  val ftb_false_hit = u(update.false_hit)
1168  // assert(!ftb_false_hit)
1169  val ftb_hit = u(commit_hit === h_hit)
1170
1171  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1172  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1173  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1174  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1175
1176  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1177
1178  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1179  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1180  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1181  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1182  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1183
1184  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
1185  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
1186  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
1187    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
1188  ).foldLeft(Map[String, UInt]())(_+_)
1189  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
1190    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
1191  ).foldLeft(Map[String, UInt]())(_+_)
1192
1193  val ftq_occupancy_map = (0 to FtqSize).map(i =>
1194    f"ftq_has_entry_$i" ->( validEntries === i.U)
1195  ).foldLeft(Map[String, UInt]())(_+_)
1196
1197  val perfCountsMap = Map(
1198    "BpInstr" -> PopCount(mbpInstrs),
1199    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1200    "BpRight"  -> PopCount(mbpRights),
1201    "BpWrong"  -> PopCount(mbpWrongs),
1202    "BpBRight" -> PopCount(mbpBRights),
1203    "BpBWrong" -> PopCount(mbpBWrongs),
1204    "BpJRight" -> PopCount(mbpJRights),
1205    "BpJWrong" -> PopCount(mbpJWrongs),
1206    "BpIRight" -> PopCount(mbpIRights),
1207    "BpIWrong" -> PopCount(mbpIWrongs),
1208    "BpCRight" -> PopCount(mbpCRights),
1209    "BpCWrong" -> PopCount(mbpCWrongs),
1210    "BpRRight" -> PopCount(mbpRRights),
1211    "BpRWrong" -> PopCount(mbpRWrongs),
1212
1213    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1214    "ftb_hit"                      -> PopCount(ftb_hit),
1215    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1216    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1217    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1218    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1219    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1220    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1221    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1222    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1223    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1224    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1225  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++
1226  s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++
1227  mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1228  correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1229
1230  for((key, value) <- perfCountsMap) {
1231    XSPerfAccumulate(key, value)
1232  }
1233
1234  // --------------------------- Debug --------------------------------
1235  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1236  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1237  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1238  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1239  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1240    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1241  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1242
1243  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1244  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1245  //       case (((valid, pd), ans), taken) =>
1246  //       Mux(valid && pd.isBr,
1247  //         isWrong ^ Mux(ans.hit.asBool,
1248  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1249  //           !taken),
1250  //         !taken),
1251  //       false.B)
1252  //     }
1253  //   }
1254
1255  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1256  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1257  //       case (((valid, pd), ans), taken) =>
1258  //       Mux(valid && pd.isBr,
1259  //         isWrong ^ Mux(ans.hit.asBool,
1260  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1261  //           !taken),
1262  //         !taken),
1263  //       false.B)
1264  //     }
1265  //   }
1266
1267  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1268  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1269  //       case (((valid, pd), ans), taken) =>
1270  //       Mux(valid && pd.isBr,
1271  //         isWrong ^ (ans.taken.asBool === taken),
1272  //       false.B)
1273  //     }
1274  //   }
1275
1276  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1277  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1278  //       case (((valid, pd), ans), taken) =>
1279  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1280  //         isWrong ^ (!taken),
1281  //           false.B)
1282  //     }
1283  //   }
1284
1285  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1286  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1287  //       case (((valid, pd), ans), taken) =>
1288  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1289  //         isWrong ^ (ans.target === commitEntry.target),
1290  //           false.B)
1291  //     }
1292  //   }
1293
1294  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1295  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1296  //   // btb and ubtb pred jal and jalr as well
1297  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1298  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1299  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1300  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1301
1302  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1303  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1304
1305  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1306  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1307
1308  val perfEvents = Seq(
1309    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1310    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1311    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1312    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1313    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1314    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1315    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1316    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1317    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1318    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1319    ("BpRight                ", PopCount(mbpRights)                                                         ),
1320    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1321    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1322    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1323    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1324    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1325    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1326    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1327    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1328    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1329    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1330    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1331    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1332    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1333  )
1334  generatePerfEvent()
1335}
1336