xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision e4d4d30585412eb8ac83b5c75599a348356342a2)
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 org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import utility._
24import xiangshan._
25import xiangshan.frontend.icache._
26import xiangshan.backend.CtrlToFtqIO
27import xiangshan.backend.decode.ImmUnion
28import utility.ChiselDB
29
30class FtqDebugBundle extends Bundle {
31  val pc = UInt(39.W)
32  val target = UInt(39.W)
33  val isBr = Bool()
34  val isJmp = Bool()
35  val isCall = Bool()
36  val isRet = Bool()
37  val misPred = Bool()
38  val isTaken = Bool()
39  val predStage = UInt(2.W)
40}
41
42class FtqPtr(entries: Int) extends CircularQueuePtr[FtqPtr](
43  entries
44){
45  def this()(implicit p: Parameters) = this(p(XSCoreParamsKey).FtqSize)
46}
47
48object FtqPtr {
49  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
50    val ptr = Wire(new FtqPtr)
51    ptr.flag := f
52    ptr.value := v
53    ptr
54  }
55  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
56    apply(!ptr.flag, ptr.value)
57  }
58}
59
60class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
61
62  val io = IO(new Bundle() {
63    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
64    val ren = Input(Vec(numRead, Bool()))
65    val rdata = Output(Vec(numRead, gen))
66    val waddr = Input(UInt(log2Up(FtqSize).W))
67    val wen = Input(Bool())
68    val wdata = Input(gen)
69  })
70
71  for(i <- 0 until numRead){
72    val sram = Module(new SRAMTemplate(gen, FtqSize))
73    sram.io.r.req.valid := io.ren(i)
74    sram.io.r.req.bits.setIdx := io.raddr(i)
75    io.rdata(i) := sram.io.r.resp.data(0)
76    sram.io.w.req.valid := io.wen
77    sram.io.w.req.bits.setIdx := io.waddr
78    sram.io.w.req.bits.data := VecInit(io.wdata)
79  }
80
81}
82
83class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
84  val startAddr = UInt(VAddrBits.W)
85  val nextLineAddr = UInt(VAddrBits.W)
86  val isNextMask = Vec(PredictWidth, Bool())
87  val fallThruError = Bool()
88  // val carry = Bool()
89  def getPc(offset: UInt) = {
90    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
91    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits)
92    Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)),
93        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
94  }
95  def fromBranchPrediction(resp: BranchPredictionBundle) = {
96    def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1)
97    this.startAddr := resp.pc(3)
98    this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs
99    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
100      (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool
101    ))
102    this.fallThruError := resp.fallThruError(3)
103    this
104  }
105  override def toPrintable: Printable = {
106    p"startAddr:${Hexadecimal(startAddr)}"
107  }
108}
109
110class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
111  val brMask = Vec(PredictWidth, Bool())
112  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
113  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
114  val jalTarget = UInt(VAddrBits.W)
115  val rvcMask = Vec(PredictWidth, Bool())
116  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
117  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
118  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
119  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
120
121  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
122    val pds = pdWb.pd
123    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
124    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
125    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
126                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
127    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
128    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
129    this.jalTarget := pdWb.jalTarget
130  }
131
132  def toPd(offset: UInt) = {
133    require(offset.getWidth == log2Ceil(PredictWidth))
134    val pd = Wire(new PreDecodeInfo)
135    pd.valid := true.B
136    pd.isRVC := rvcMask(offset)
137    val isBr = brMask(offset)
138    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
139    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
140    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
141    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
142    pd
143  }
144}
145
146class PrefetchPtrDB(implicit p: Parameters) extends Bundle {
147  val fromFtqPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
148  val fromIfuPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
149}
150
151class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo {
152  val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None
153}
154
155class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
156  val meta = UInt(MaxMetaLength.W)
157}
158
159class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
160  val target = UInt(VAddrBits.W)
161  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
162}
163
164
165class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
166  val ptr = Output(new FtqPtr)
167  val offset = Output(UInt(log2Ceil(PredictWidth).W))
168  val data = Input(gen)
169  def apply(ptr: FtqPtr, offset: UInt) = {
170    this.ptr := ptr
171    this.offset := offset
172    this.data
173  }
174}
175
176
177class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
178  val redirect = Valid(new BranchPredictionRedirect)
179  val update = Valid(new BranchPredictionUpdate)
180  val enq_ptr = Output(new FtqPtr)
181}
182
183class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
184  val req = Decoupled(new FetchRequestBundle)
185  val redirect = Valid(new BranchPredictionRedirect)
186  val topdown_redirect = Valid(new BranchPredictionRedirect)
187  val flushFromBpu = new Bundle {
188    // when ifu pipeline is not stalled,
189    // a packet from bpu s3 can reach f1 at most
190    val s2 = Valid(new FtqPtr)
191    val s3 = Valid(new FtqPtr)
192    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
193      src.valid && !isAfter(src.bits, idx_to_flush)
194    }
195    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
196    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
197  }
198}
199
200class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
201  //NOTE: req.bits must be prepare in T cycle
202  // while req.valid is set true in T + 1 cycle
203  val req = Decoupled(new FtqToICacheRequestBundle)
204}
205
206trait HasBackendRedirectInfo extends HasXSParameter {
207  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
208}
209
210class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
211  // write to backend pc mem
212  val pc_mem_wen = Output(Bool())
213  val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W))
214  val pc_mem_wdata = Output(new Ftq_RF_Components)
215  // newest target
216  val newest_entry_target = Output(UInt(VAddrBits.W))
217  val newest_entry_ptr = Output(new FtqPtr)
218}
219
220
221class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
222  val io = IO(new Bundle {
223    val start_addr = Input(UInt(VAddrBits.W))
224    val old_entry = Input(new FTBEntry)
225    val pd = Input(new Ftq_pd_Entry)
226    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
227    val target = Input(UInt(VAddrBits.W))
228    val hit = Input(Bool())
229    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
230
231    val new_entry = Output(new FTBEntry)
232    val new_br_insert_pos = Output(Vec(numBr, Bool()))
233    val taken_mask = Output(Vec(numBr, Bool()))
234    val jmp_taken = Output(Bool())
235    val mispred_mask = Output(Vec(numBr+1, Bool()))
236
237    // for perf counters
238    val is_init_entry = Output(Bool())
239    val is_old_entry = Output(Bool())
240    val is_new_br = Output(Bool())
241    val is_jalr_target_modified = Output(Bool())
242    val is_always_taken_modified = Output(Bool())
243    val is_br_full = Output(Bool())
244  })
245
246  // no mispredictions detected at predecode
247  val hit = io.hit
248  val pd = io.pd
249
250  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
251
252
253  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
254  val entry_has_jmp = pd.jmpInfo.valid
255  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
256  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
257  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
258  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
259  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
260  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
261
262  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
263  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
264
265  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
266  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
267  // if not hit, establish a new entry
268  init_entry.valid := true.B
269  // tag is left for ftb to assign
270
271  // case br
272  val init_br_slot = init_entry.getSlotForBr(0)
273  when (cfi_is_br) {
274    init_br_slot.valid := true.B
275    init_br_slot.offset := io.cfiIndex.bits
276    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
277    init_entry.always_taken(0) := true.B // set to always taken on init
278  }
279
280  // case jmp
281  when (entry_has_jmp) {
282    init_entry.tailSlot.offset := pd.jmpOffset
283    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
284    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
285  }
286
287  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
288  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
289  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
290  init_entry.isJalr := new_jmp_is_jalr
291  init_entry.isCall := new_jmp_is_call
292  init_entry.isRet  := new_jmp_is_ret
293  // that means fall thru points to the middle of an inst
294  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
295
296  // if hit, check whether a new cfi(only br is possible) is detected
297  val oe = io.old_entry
298  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
299  val br_recorded = br_recorded_vec.asUInt.orR
300  val is_new_br = cfi_is_br && !br_recorded
301  val new_br_offset = io.cfiIndex.bits
302  // vec(i) means new br will be inserted BEFORE old br(i)
303  val allBrSlotsVec = oe.allSlotsForBr
304  val new_br_insert_onehot = VecInit((0 until numBr).map{
305    i => i match {
306      case 0 =>
307        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
308      case idx =>
309        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
310        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
311    }
312  })
313
314  val old_entry_modified = WireInit(io.old_entry)
315  for (i <- 0 until numBr) {
316    val slot = old_entry_modified.allSlotsForBr(i)
317    when (new_br_insert_onehot(i)) {
318      slot.valid := true.B
319      slot.offset := new_br_offset
320      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
321      old_entry_modified.always_taken(i) := true.B
322    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
323      old_entry_modified.always_taken(i) := false.B
324      // all other fields remain unchanged
325    }.otherwise {
326      // case i == 0, remain unchanged
327      if (i != 0) {
328        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
329        when (!noNeedToMoveFromFormerSlot) {
330          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
331          old_entry_modified.always_taken(i) := oe.always_taken(i)
332        }
333      }
334    }
335  }
336
337  // two circumstances:
338  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
339  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
340  //        the previous last br or the new br
341  val may_have_to_replace = oe.noEmptySlotForNewBr
342  val pft_need_to_change = is_new_br && may_have_to_replace
343  // it should either be the given last br or the new br
344  when (pft_need_to_change) {
345    val new_pft_offset =
346      Mux(!new_br_insert_onehot.asUInt.orR,
347        new_br_offset, oe.allSlotsForBr.last.offset)
348
349    // set jmp to invalid
350    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
351    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
352    old_entry_modified.last_may_be_rvi_call := false.B
353    old_entry_modified.isCall := false.B
354    old_entry_modified.isRet := false.B
355    old_entry_modified.isJalr := false.B
356  }
357
358  val old_entry_jmp_target_modified = WireInit(oe)
359  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
360  val old_tail_is_jmp = !oe.tailSlot.sharing
361  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
362  when (jalr_target_modified) {
363    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
364    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
365  }
366
367  val old_entry_always_taken = WireInit(oe)
368  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
369  for (i <- 0 until numBr) {
370    old_entry_always_taken.always_taken(i) :=
371      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
372    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
373  }
374  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
375
376
377
378  val derived_from_old_entry =
379    Mux(is_new_br, old_entry_modified,
380      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
381
382
383  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
384
385  io.new_br_insert_pos := new_br_insert_onehot
386  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
387    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
388  })
389  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
390  for (i <- 0 until numBr) {
391    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
392  }
393  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
394
395  // for perf counters
396  io.is_init_entry := !hit
397  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
398  io.is_new_br := hit && is_new_br
399  io.is_jalr_target_modified := hit && jalr_target_modified
400  io.is_always_taken_modified := hit && always_taken_modified
401  io.is_br_full := hit && is_new_br && may_have_to_replace
402}
403
404class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
405  val io = IO(new Bundle {
406    val ifuPtr_w       = Input(new FtqPtr)
407    val ifuPtrPlus1_w  = Input(new FtqPtr)
408    val ifuPtrPlus2_w  = Input(new FtqPtr)
409    val commPtr_w      = Input(new FtqPtr)
410    val commPtrPlus1_w = Input(new FtqPtr)
411    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
412    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
413    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
414    val commPtr_rdata      = Output(new Ftq_RF_Components)
415    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
416
417    val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W)))
418    val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components))
419
420    val wen = Input(Bool())
421    val waddr = Input(UInt(log2Ceil(FtqSize).W))
422    val wdata = Input(new Ftq_RF_Components)
423  })
424
425  val num_pc_read = numOtherReads + 5
426  val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize,
427    num_pc_read, 1, "FtqPC"))
428  mem.io.wen(0)   := io.wen
429  mem.io.waddr(0) := io.waddr
430  mem.io.wdata(0) := io.wdata
431
432  // read one cycle ahead for ftq local reads
433  val raddr_vec = VecInit(io.other_raddrs ++
434    Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value))
435
436  mem.io.raddr := raddr_vec
437
438  io.other_rdatas       := mem.io.rdata.dropRight(5)
439  io.ifuPtr_rdata       := mem.io.rdata.dropRight(4).last
440  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(3).last
441  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(2).last
442  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
443  io.commPtr_rdata      := mem.io.rdata.last
444}
445
446class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
447  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
448  with HasICacheParameters{
449  val io = IO(new Bundle {
450    val fromBpu = Flipped(new BpuToFtqIO)
451    val fromIfu = Flipped(new IfuToFtqIO)
452    val fromBackend = Flipped(new CtrlToFtqIO)
453
454    val toBpu = new FtqToBpuIO
455    val toIfu = new FtqToIfuIO
456    val toICache = new FtqToICacheIO
457    val toBackend = new FtqToCtrlIO
458
459    val toPrefetch = new FtqPrefechBundle
460
461    val bpuInfo = new Bundle {
462      val bpRight = Output(UInt(XLEN.W))
463      val bpWrong = Output(UInt(XLEN.W))
464    }
465
466    val mmioCommitRead = Flipped(new mmioCommitRead)
467
468    // for perf
469    val ControlBTBMissBubble = Output(Bool())
470    val TAGEMissBubble = Output(Bool())
471    val SCMissBubble = Output(Bool())
472    val ITTAGEMissBubble = Output(Bool())
473    val RASMissBubble = Output(Bool())
474  })
475  io.bpuInfo := DontCare
476
477  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
478  // only driven by clock, not valid-ready
479  topdown_stage := io.fromBpu.resp.bits.topdown_info
480  io.toIfu.req.bits.topdown_info := topdown_stage
481
482  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
483
484
485  // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception
486  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju
487  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0)
488
489  val aheadValid   = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid
490  val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
491  val backendRedirect = Wire(Valid(new BranchPredictionRedirect))
492  val backendRedirectReg = RegNext(backendRedirect)
493  backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid)
494  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
495  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
496
497  val stage2Flush = backendRedirect.valid
498  val backendFlush = stage2Flush || RegNext(stage2Flush)
499  val ifuFlush = Wire(Bool())
500
501  val flush = stage2Flush || RegNext(stage2Flush)
502
503  val allowBpuIn, allowToIfu = WireInit(false.B)
504  val flushToIfu = !allowToIfu
505  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
506  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
507
508  def copyNum = 5
509  val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U))
510  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
511  val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U))
512  val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
513  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
514  val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
515  require(FtqSize >= 4)
516  val ifuPtr_write       = WireInit(ifuPtr)
517  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
518  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
519  val ifuWbPtr_write     = WireInit(ifuWbPtr)
520  val commPtr_write      = WireInit(commPtr)
521  val commPtrPlus1_write = WireInit(commPtrPlus1)
522  val robCommPtr_write   = WireInit(robCommPtr)
523  ifuPtr       := ifuPtr_write
524  ifuPtrPlus1  := ifuPtrPlus1_write
525  ifuPtrPlus2  := ifuPtrPlus2_write
526  ifuWbPtr     := ifuWbPtr_write
527  commPtr      := commPtr_write
528  commPtrPlus1 := commPtrPlus1_write
529  copied_ifu_ptr.map{ptr =>
530    ptr := ifuPtr_write
531    dontTouch(ptr)
532  }
533  robCommPtr   := robCommPtr_write
534  val validEntries = distanceBetween(bpuPtr, commPtr)
535  val canCommit = Wire(Bool())
536
537  // **********************************************************************
538  // **************************** enq from bpu ****************************
539  // **********************************************************************
540  val new_entry_ready = validEntries < FtqSize.U || canCommit
541  io.fromBpu.resp.ready := new_entry_ready
542
543  val bpu_s2_resp = io.fromBpu.resp.bits.s2
544  val bpu_s3_resp = io.fromBpu.resp.bits.s3
545  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
546  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
547
548  io.toBpu.enq_ptr := bpuPtr
549  val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
550  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
551
552  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
553  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq
554  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
555  val bpu_in_resp_idx = bpu_in_resp_ptr.value
556
557  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
558  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
559  // resp from uBTB
560  ftq_pc_mem.io.wen := bpu_in_fire
561  ftq_pc_mem.io.waddr := bpu_in_resp_idx
562  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
563
564  //                                                            ifuRedirect + backendRedirect + commit
565  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1))
566  // these info is intended to enq at the last stage of bpu
567  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
568  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
569  ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info
570  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
571  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
572
573  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
574  // these info is intended to enq at the last stage of bpu
575  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
576  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
577  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta
578  //                                                            ifuRedirect + backendRedirect + commit
579  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1))
580  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3)
581  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
582  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
583
584
585  // multi-write
586  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
587  val newest_entry_target = Reg(UInt(VAddrBits.W))
588  val newest_entry_ptr = Reg(new FtqPtr)
589  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
590  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
591  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
592  val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
593
594  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
595  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
596    VecInit(Seq.fill(PredictWidth)(c_invalid))
597  }))
598
599  val f_to_send :: f_sent :: Nil = Enum(2)
600  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
601
602  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
603  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
604
605  // modify registers one cycle later to cut critical path
606  val last_cycle_bpu_in = RegNext(bpu_in_fire)
607  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
608  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
609  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3))
610  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3))
611  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
612
613  def extra_copyNum_for_commitStateQueue = 2
614  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
615  val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr)))
616
617  when (last_cycle_bpu_in) {
618    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
619    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
620    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
621
622    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
623    newest_entry_target := last_cycle_bpu_target
624    newest_entry_ptr := last_cycle_bpu_in_ptr
625  }
626
627  // reduce fanout by delay write for a cycle
628  when (RegNext(last_cycle_bpu_in)) {
629    mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
630  }
631
632  // record s1 pred cycles
633  pred_s1_cycle.map(vec => {
634    when (bpu_in_fire && (bpu_in_stage === BP_S1)) {
635      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
636    }
637  })
638
639  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
640  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
641  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
642    case ((in, ptr), i) =>
643      when (in) {
644        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
645        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
646        for (j <- 0 until perSetEntries) {
647          when (ptr.value === (i*perSetEntries+j).U) {
648            commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid))
649          }
650        }
651      }
652  }
653
654  // num cycle is fixed
655  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
656  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
657
658
659  bpuPtr := bpuPtr + enq_fire
660  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
661  when (io.toIfu.req.fire && allowToIfu) {
662    ifuPtr_write := ifuPtrPlus1
663    ifuPtrPlus1_write := ifuPtrPlus2
664    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
665  }
666
667  // only use ftb result to assign hit status
668  when (bpu_s2_resp.valid(3)) {
669    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
670  }
671
672
673  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
674  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
675  when (bpu_s2_redirect) {
676    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
677    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
678    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
679    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
680      ifuPtr_write := bpu_s2_resp.ftq_idx
681      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
682      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
683    }
684  }
685
686  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
687  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
688  when (bpu_s3_redirect) {
689    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
690    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
691    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
692    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
693      ifuPtr_write := bpu_s3_resp.ftq_idx
694      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
695      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
696    }
697  }
698
699  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
700  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
701
702  (0 until copyNum).map{i =>
703    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
704  }
705
706  // ****************************************************************
707  // **************************** to ifu ****************************
708  // ****************************************************************
709  // 0  for ifu, and 1-4 for ICache
710  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
711  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
712  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
713  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
714  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
715
716  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
717  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
718
719  // read pc and target
720  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
721  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
722  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
723  ftq_pc_mem.io.commPtr_w      := commPtr_write
724  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
725
726
727  io.toIfu.req.bits.ftqIdx := ifuPtr
728
729  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
730  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
731  val toIfuPcBundle = Wire(new Ftq_RF_Components)
732  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
733  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
734  val entry_next_addr  = Wire(UInt(VAddrBits.W))
735
736  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
737  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
738  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
739
740  val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1))))
741  val copied_ifu_ptr_to_send   = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr)))
742
743  for(i <- 0 until copyNum){
744    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
745      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
746      toICacheEntryToSend(i)   := true.B
747    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
748      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
749      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
750    }.otherwise{
751      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
752      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
753    }
754  }
755
756  // TODO: reconsider target address bypass logic
757  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
758    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
759    entry_is_to_send := true.B
760    entry_next_addr := last_cycle_bpu_target
761    entry_ftq_offset := last_cycle_cfiIndex
762    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
763  }.elsewhen (last_cycle_to_ifu_fire) {
764    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
765    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
766                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
767    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
768                          bpu_in_bypass_buf_for_ifu.startAddr,
769                          Mux(ifuPtr === newest_entry_ptr,
770                            newest_entry_target,
771                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
772  }.otherwise {
773    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
774    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
775                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
776    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
777                          bpu_in_bypass_buf_for_ifu.startAddr,
778                          Mux(ifuPtr === newest_entry_ptr,
779                            newest_entry_target,
780                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
781  }
782
783  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
784  io.toIfu.req.bits.nextStartAddr := entry_next_addr
785  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
786  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
787
788  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
789  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
790  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
791  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
792  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
793  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
794  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
795  // }
796
797  // TODO: remove this
798  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
799          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
800
801  // when fall through is smaller in value than start address, there must be a false hit
802  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
803    when (io.toIfu.req.fire &&
804      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
805      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
806    ) {
807      entry_hit_status(ifuPtr.value) := h_false_hit
808      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
809    }
810    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
811  }
812
813  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
814    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
815
816  val ifu_req_should_be_flushed =
817    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
818    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
819
820    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
821      entry_fetch_status(ifuPtr.value) := f_sent
822    }
823
824  // *********************************************************************
825  // **************************** wb from ifu ****************************
826  // *********************************************************************
827  val pdWb = io.fromIfu.pdWb
828  val pds = pdWb.bits.pd
829  val ifu_wb_valid = pdWb.valid
830  val ifu_wb_idx = pdWb.bits.ftqIdx.value
831  // read ports:                                                         commit update
832  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
833  ftq_pd_mem.io.wen(0) := ifu_wb_valid
834  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
835  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
836
837  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
838  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
839  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
840  val pd_reg       = RegEnable(pds,             pdWb.valid)
841  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
842  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
843
844  when (ifu_wb_valid) {
845    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
846      case (v, inRange) => v && inRange
847    })
848    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
849      case (qe, v) => when (v) { qe := c_valid }
850    }
851  }
852
853  when (ifu_wb_valid) {
854    ifuWbPtr_write := ifuWbPtr + 1.U
855  }
856
857  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
858
859  ftb_entry_mem.io.raddr.head := ifu_wb_idx
860  val has_false_hit = WireInit(false.B)
861  when (RegNext(hit_pd_valid)) {
862    // check for false hit
863    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
864    val brSlots = pred_ftb_entry.brSlots
865    val tailSlot = pred_ftb_entry.tailSlot
866    // we check cfis that bpu predicted
867
868    // bpu predicted branches but denied by predecode
869    val br_false_hit =
870      brSlots.map{
871        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
872      }.reduce(_||_) ||
873      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
874        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
875
876    val jmpOffset = tailSlot.offset
877    val jmp_pd = pd_reg(jmpOffset)
878    val jal_false_hit = pred_ftb_entry.jmpValid &&
879      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
880       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
881       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
882       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
883      )
884
885    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
886    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
887
888    // assert(!has_false_hit)
889  }
890
891  when (has_false_hit) {
892    entry_hit_status(wb_idx_reg) := h_false_hit
893  }
894
895
896  // **********************************************************************
897  // ***************************** to backend *****************************
898  // **********************************************************************
899  // to backend pc mem / target
900  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
901  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
902  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
903
904  // *******************************************************************************
905  // **************************** redirect from backend ****************************
906  // *******************************************************************************
907
908  // redirect read cfiInfo, couples to redirectGen s2
909  val redirectReadStart = 1 // 0 for ifuRedirect
910  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
911  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry))
912  for (i <- redirectReadStart until FtqRedirectAheadNum) {
913    ftq_redirect_sram.io.ren(i + redirectReadStart)   := ftqIdxAhead(i).valid
914    ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value
915    ftb_entry_mem.io.raddr(i + redirectReadStart)     := ftqIdxAhead(i).bits.value
916  }
917  ftq_redirect_sram.io.ren(redirectReadStart)   := Mux(aheadValid, ftqIdxAhead(0).valid,      backendRedirect.valid)
918  ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
919  ftb_entry_mem.io.raddr(redirectReadStart)     := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
920
921  for (i <- 0 until FtqRedirectAheadNum) {
922    ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart)
923    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart)
924  }
925  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart))
926  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
927  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
928
929
930  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart))
931  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
932
933  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
934  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
935  // FIXME: not portable
936  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
937  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
938    sc_disagree(0), sc_disagree(1))
939
940  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
941    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
942      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
943      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
944
945    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
946        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
947  }.otherwise {
948    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
949    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
950  }
951
952
953  // ***************************************************************************
954  // **************************** redirect from ifu ****************************
955  // ***************************************************************************
956  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
957  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
958  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
959  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
960  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
961  fromIfuRedirect.bits.BTBMissBubble := true.B
962  fromIfuRedirect.bits.debugIsMemVio := false.B
963  fromIfuRedirect.bits.debugIsCtrl := false.B
964
965  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
966  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
967  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
968  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
969  ifuRedirectCfiUpdate.target := pdWb.bits.target
970  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
971  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
972
973  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
974  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
975  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
976
977  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
978  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
979
980  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
981
982  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
983  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
984  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
985    toBpuCfi.target := toBpuCfi.topAddr
986  }
987
988  when (ifuRedirectReg.valid) {
989    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
990  } .elsewhen(RegNext(pdWb.valid)) {
991    // if pdWb and no redirect, set to false
992    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
993  }
994
995  // *********************************************************************
996  // **************************** wb from exu ****************************
997  // *********************************************************************
998
999  backendRedirect.valid := io.fromBackend.redirect.valid
1000  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1001  backendRedirect.bits.BTBMissBubble := false.B
1002
1003
1004  def extractRedirectInfo(wb: Valid[Redirect]) = {
1005    val ftqPtr = wb.bits.ftqIdx
1006    val ftqOffset = wb.bits.ftqOffset
1007    val taken = wb.bits.cfiUpdate.taken
1008    val mispred = wb.bits.cfiUpdate.isMisPred
1009    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
1010  }
1011
1012  // fix mispredict entry
1013  val lastIsMispredict = RegNext(
1014    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
1015  )
1016
1017  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
1018    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
1019    val r_idx = r_ptr.value
1020    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
1021    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
1022    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
1023      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
1024    } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
1025      cfiIndex_vec(r_idx).valid :=false.B
1026    }
1027    when (cfiIndex_bits_wen) {
1028      cfiIndex_vec(r_idx).bits := r_offset
1029    }
1030    newest_entry_target := redirect.bits.cfiUpdate.target
1031    newest_entry_ptr := r_ptr
1032    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
1033    if (isBackend) {
1034      mispredict_vec(r_idx)(r_offset) := r_mispred
1035    }
1036  }
1037
1038  when(fromBackendRedirect.valid) {
1039    updateCfiInfo(fromBackendRedirect)
1040  }.elsewhen (ifuRedirectToBpu.valid) {
1041    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
1042  }
1043
1044  when (fromBackendRedirect.valid) {
1045    when (fromBackendRedirect.bits.ControlRedirectBubble) {
1046      when (fromBackendRedirect.bits.ControlBTBMissBubble) {
1047        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1048        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1049      } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) {
1050        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1051        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1052      } .elsewhen (fromBackendRedirect.bits.SCMissBubble) {
1053        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
1054        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1055      } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) {
1056        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1057        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1058      } .elsewhen (fromBackendRedirect.bits.RASMissBubble) {
1059        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
1060        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1061      }
1062
1063
1064    } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) {
1065      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1066      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1067    } .otherwise {
1068      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1069      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1070    }
1071  } .elsewhen (ifuRedirectReg.valid) {
1072    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1073    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1074  }
1075
1076  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1077  io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble
1078  io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble
1079  io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble
1080  io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble
1081
1082  // ***********************************************************************************
1083  // **************************** flush ptr and state queue ****************************
1084  // ***********************************************************************************
1085
1086  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
1087
1088  // when redirect, we should reset ptrs and status queues
1089  when(redirectVec.map(r => r.valid).reduce(_||_)){
1090    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1091    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1092    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1093    val next = idx + 1.U
1094    bpuPtr := next
1095    copied_bpu_ptr.map(_ := next)
1096    ifuPtr_write := next
1097    ifuWbPtr_write := next
1098    ifuPtrPlus1_write := idx + 2.U
1099    ifuPtrPlus2_write := idx + 3.U
1100
1101  }
1102  when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){
1103    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1104    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1105    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1106    when (RegNext(notIfu)) {
1107      commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) =>
1108        when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){
1109          s := c_invalid
1110        }
1111      })
1112    }
1113  }
1114
1115
1116  // only the valid bit is actually needed
1117  io.toIfu.redirect.bits    := backendRedirect.bits
1118  io.toIfu.redirect.valid   := stage2Flush
1119  io.toIfu.topdown_redirect := fromBackendRedirect
1120
1121  // commit
1122  for (c <- io.fromBackend.rob_commits) {
1123    when(c.valid) {
1124      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
1125      // TODO: remove this
1126      // For instruction fusions, we also update the next instruction
1127      when (c.bits.commitType === 4.U) {
1128        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
1129      }.elsewhen(c.bits.commitType === 5.U) {
1130        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
1131      }.elsewhen(c.bits.commitType === 6.U) {
1132        val index = (c.bits.ftqIdx + 1.U).value
1133        commitStateQueue(index)(0) := c_commited
1134      }.elsewhen(c.bits.commitType === 7.U) {
1135        val index = (c.bits.ftqIdx + 1.U).value
1136        commitStateQueue(index)(1) := c_commited
1137      }
1138    }
1139  }
1140
1141  robCommPtr_write := Mux(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _), ParallelPriorityMux(io.fromBackend.rob_commits.map(_.valid).reverse, io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse), robCommPtr)
1142
1143  // ****************************************************************
1144  // **************************** to bpu ****************************
1145  // ****************************************************************
1146
1147  io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1148  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W)))
1149  val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1150  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1151  XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1)
1152
1153  XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay")
1154
1155  val may_have_stall_from_bpu = Wire(Bool())
1156  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
1157  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
1158  val notInvalidSeq = commitStateQueue(commPtr.value).map(s => s =/= c_invalid).reverse
1159  // Todo: @huxuan check it
1160  //  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1161  //    Cat(commitStateQueue(commPtr.value).map(s => {
1162  //      s === c_invalid || s === c_commited
1163  //    })).andR
1164  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1165    (isAfter(robCommPtr, commPtr) || PriorityMuxDefault(notInvalidSeq.zip(commitStateQueue(commPtr.value).reverse), c_invalid) === c_commited)
1166
1167  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
1168  val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr)  ||  mmioReadPtr ===   ifuPtr) &&
1169                       Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR
1170  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
1171
1172  // commit reads
1173  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1174  val commit_target =
1175    Mux(RegNext(commPtr === newest_entry_ptr),
1176      RegNext(newest_entry_target),
1177      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1178  ftq_pd_mem.io.raddr.last := commPtr.value
1179  val commit_pd = ftq_pd_mem.io.rdata.last
1180  ftq_redirect_sram.io.ren.last := canCommit
1181  ftq_redirect_sram.io.raddr.last := commPtr.value
1182  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
1183  ftq_meta_1r_sram.io.ren(0) := canCommit
1184  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1185  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
1186  ftb_entry_mem.io.raddr.last := commPtr.value
1187  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
1188
1189  // need one cycle to read mem and srams
1190  val do_commit_ptr = RegNext(commPtr)
1191  val do_commit = RegNext(canCommit, init=false.B)
1192  when (canCommit) {
1193    commPtr_write := commPtrPlus1
1194    commPtrPlus1_write := commPtrPlus1 + 1.U
1195  }
1196  val commit_state = RegNext(commitStateQueue(commPtr.value))
1197  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1198  val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value))
1199  //
1200  //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1201  //  can_commit_cfi.valid := false.B
1202  //}
1203  val commit_cfi = RegNext(can_commit_cfi)
1204  val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid
1205
1206  val commit_mispredict  : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
1207    case (mis, state) => mis && state === c_commited
1208  })
1209  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth]
1210  val can_commit_hit                 = entry_hit_status(commPtr.value)
1211  val commit_hit                     = RegNext(can_commit_hit)
1212  val diff_commit_target             = RegNext(update_target(commPtr.value)) // TODO: remove this
1213  val commit_stage                   = RegNext(pred_stage(commPtr.value))
1214  val commit_valid                   = commit_hit === h_hit || commit_cfi.valid // hit or taken
1215
1216  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1217  switch (bpu_ftb_update_stall) {
1218    is (0.U) {
1219      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1220        bpu_ftb_update_stall := 2.U // 2-cycle stall
1221      }
1222    }
1223    is (2.U) {
1224      bpu_ftb_update_stall := 1.U
1225    }
1226    is (1.U) {
1227      bpu_ftb_update_stall := 0.U
1228    }
1229    is (3.U) {
1230      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1231    }
1232  }
1233
1234  // TODO: remove this
1235  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1236
1237  // update latency stats
1238  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1239  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1240
1241  io.toBpu.update := DontCare
1242  io.toBpu.update.valid := commit_valid && do_commit
1243  val update = io.toBpu.update.bits
1244  update.false_hit   := commit_hit === h_false_hit
1245  update.pc          := commit_pc_bundle.startAddr
1246  update.meta        := commit_meta.meta
1247  update.cfi_idx     := commit_cfi
1248  update.full_target := commit_target
1249  update.from_stage  := commit_stage
1250  update.spec_info   := commit_spec_meta
1251  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
1252
1253  val commit_real_hit = commit_hit === h_hit
1254  val update_ftb_entry = update.ftb_entry
1255
1256  val ftbEntryGen = Module(new FTBEntryGen).io
1257  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1258  ftbEntryGen.old_entry      := commit_ftb_entry
1259  ftbEntryGen.pd             := commit_pd
1260  ftbEntryGen.cfiIndex       := commit_cfi
1261  ftbEntryGen.target         := commit_target
1262  ftbEntryGen.hit            := commit_real_hit
1263  ftbEntryGen.mispredict_vec := commit_mispredict
1264
1265  update_ftb_entry         := ftbEntryGen.new_entry
1266  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1267  update.mispred_mask      := ftbEntryGen.mispred_mask
1268  update.old_entry         := ftbEntryGen.is_old_entry
1269  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1270  update.br_taken_mask     := ftbEntryGen.taken_mask
1271  update.br_committed      := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1272    case (valid, offset) => valid && commit_instCommited(offset)
1273  }
1274  update.jmp_taken         := ftbEntryGen.jmp_taken
1275
1276  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1277  // update.full_pred.jalr_target := commit_target
1278  // update.full_pred.hit := true.B
1279  // when (update.full_pred.is_jalr) {
1280  //   update.full_pred.targets.last := commit_target
1281  // }
1282
1283  // ****************************************************************
1284  // *********************** to prefetch ****************************
1285  // ****************************************************************
1286  /**
1287    ******************************************************************************
1288    * prefetchPtr control
1289    * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2
1290    * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange]
1291    * - 3. flush prefetchPtr when receive redirect from ifu or backend
1292    ******************************************************************************
1293    */
1294  val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1295  val nextPrefetchPtr = WireInit(prefetchPtr)
1296
1297  prefetchPtr := nextPrefetchPtr
1298
1299  // TODO: consider req which cross cacheline
1300  when(io.toPrefetch.req.fire) {
1301    when(prefetchPtr < bpuPtr - 2.U) {
1302      nextPrefetchPtr := prefetchPtr + 1.U
1303    }
1304  }
1305
1306  when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) {
1307    nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U
1308  }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) {
1309    nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U
1310  }
1311
1312  when(redirectVec.map(r => r.valid).reduce(_||_)){
1313    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1314    val next = r.ftqIdx + minRangeFromIFUptr.U
1315    nextPrefetchPtr := next
1316  }
1317
1318  // data from ftq_pc_mem has 1 cycle delay
1319  io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send)
1320  ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value
1321  io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr)
1322
1323  // record position relationship between ifuPtr, pfPtr and bpuPtr
1324  val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString))
1325  val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB)
1326  val prefetchPtrDumpData = Wire(new PrefetchPtrDB)
1327  prefetchPtrDumpData.fromFtqPtr  := distanceBetween(bpuPtr, prefetchPtr)
1328  prefetchPtrDumpData.fromIfuPtr  := distanceBetween(prefetchPtr, ifuPtr)
1329
1330  prefetchPtrTable.log(
1331    data = prefetchPtrDumpData,
1332    en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire,
1333    site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1334    clock = clock,
1335    reset = reset
1336  )
1337
1338
1339  // ******************************************************************************
1340  // **************************** commit perf counters ****************************
1341  // ******************************************************************************
1342
1343  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1344  val commit_mispred_mask = commit_mispredict.asUInt
1345  val commit_not_mispred_mask = ~commit_mispred_mask
1346
1347  val commit_br_mask = commit_pd.brMask.asUInt
1348  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1349  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1350
1351  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1352
1353  val mbpRights = mbpInstrs & commit_not_mispred_mask
1354  val mbpWrongs = mbpInstrs & commit_mispred_mask
1355
1356  io.bpuInfo.bpRight := PopCount(mbpRights)
1357  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1358
1359  val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString))
1360  val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle)
1361  // Cfi Info
1362  for (i <- 0 until PredictWidth) {
1363    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1364    val v = commit_state(i) === c_commited
1365    val isBr = commit_pd.brMask(i)
1366    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1367    val isCfi = isBr || isJmp
1368    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1369    val misPred = commit_mispredict(i)
1370    // val ghist = commit_spec_meta.ghist.predHist
1371    val histPtr = commit_spec_meta.histPtr
1372    val predCycle = commit_meta.meta(63, 0)
1373    val target = commit_target
1374
1375    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1376    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1377    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1378    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1379    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1380    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1381    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1382
1383    val logbundle = Wire(new FtqDebugBundle)
1384    logbundle.pc := pc
1385    logbundle.target := target
1386    logbundle.isBr := isBr
1387    logbundle.isJmp := isJmp
1388    logbundle.isCall := isJmp && commit_pd.hasCall
1389    logbundle.isRet := isJmp && commit_pd.hasRet
1390    logbundle.misPred := misPred
1391    logbundle.isTaken := isTaken
1392    logbundle.predStage := commit_stage
1393
1394    ftqBranchTraceDB.log(
1395      data = logbundle /* hardware of type T */,
1396      en = isWriteFTQTable.orR && v && do_commit && isCfi,
1397      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1398      clock = clock,
1399      reset = reset
1400    )
1401  }
1402
1403  val enq = io.fromBpu.resp
1404  val perf_redirect = backendRedirect
1405
1406  XSPerfAccumulate("entry", validEntries)
1407  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1408  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1409  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1410  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1411
1412  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1413
1414  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1415  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1416  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1417  XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready)
1418
1419  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_))
1420  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
1421  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
1422
1423  val from_bpu = io.fromBpu.resp.bits
1424  val to_ifu = io.toIfu.req.bits
1425
1426
1427  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1)
1428
1429
1430
1431
1432  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1433  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1434  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1435  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1436
1437
1438  val mbpBRights = mbpRights & commit_br_mask
1439  val mbpJRights = mbpRights & commit_jal_mask
1440  val mbpIRights = mbpRights & commit_jalr_mask
1441  val mbpCRights = mbpRights & commit_call_mask
1442  val mbpRRights = mbpRights & commit_ret_mask
1443
1444  val mbpBWrongs = mbpWrongs & commit_br_mask
1445  val mbpJWrongs = mbpWrongs & commit_jal_mask
1446  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1447  val mbpCWrongs = mbpWrongs & commit_call_mask
1448  val mbpRWrongs = mbpWrongs & commit_ret_mask
1449
1450  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1451
1452  def pred_stage_map(src: UInt, name: String) = {
1453    (0 until numBpStages).map(i =>
1454      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1455    ).foldLeft(Map[String, UInt]())(_+_)
1456  }
1457
1458  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1459  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1460  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1461  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1462  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1463  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1464
1465  val update_valid = io.toBpu.update.valid
1466  def u(cond: Bool) = update_valid && cond
1467  val ftb_false_hit = u(update.false_hit)
1468  // assert(!ftb_false_hit)
1469  val ftb_hit = u(commit_hit === h_hit)
1470
1471  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1472  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1473  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1474  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1475
1476  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1477
1478  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1479  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1480  val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value))
1481  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1482  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1483  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1484
1485  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1486  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1487  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1)
1488  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1)
1489  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1490  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1)
1491
1492  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1)
1493
1494  val perfCountsMap = Map(
1495    "BpInstr" -> PopCount(mbpInstrs),
1496    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1497    "BpRight"  -> PopCount(mbpRights),
1498    "BpWrong"  -> PopCount(mbpWrongs),
1499    "BpBRight" -> PopCount(mbpBRights),
1500    "BpBWrong" -> PopCount(mbpBWrongs),
1501    "BpJRight" -> PopCount(mbpJRights),
1502    "BpJWrong" -> PopCount(mbpJWrongs),
1503    "BpIRight" -> PopCount(mbpIRights),
1504    "BpIWrong" -> PopCount(mbpIWrongs),
1505    "BpCRight" -> PopCount(mbpCRights),
1506    "BpCWrong" -> PopCount(mbpCWrongs),
1507    "BpRRight" -> PopCount(mbpRRights),
1508    "BpRWrong" -> PopCount(mbpRWrongs),
1509
1510    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1511    "ftb_hit"                      -> PopCount(ftb_hit),
1512    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1513    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1514    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1515    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1516    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1517    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1518    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1519    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1520    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1521    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1522  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1523       correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1524
1525  for((key, value) <- perfCountsMap) {
1526    XSPerfAccumulate(key, value)
1527  }
1528
1529  // --------------------------- Debug --------------------------------
1530  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1531  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1532  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1533  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1534  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1535    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1536  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1537
1538  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1539  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1540  //       case (((valid, pd), ans), taken) =>
1541  //       Mux(valid && pd.isBr,
1542  //         isWrong ^ Mux(ans.hit.asBool,
1543  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1544  //           !taken),
1545  //         !taken),
1546  //       false.B)
1547  //     }
1548  //   }
1549
1550  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1551  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1552  //       case (((valid, pd), ans), taken) =>
1553  //       Mux(valid && pd.isBr,
1554  //         isWrong ^ Mux(ans.hit.asBool,
1555  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1556  //           !taken),
1557  //         !taken),
1558  //       false.B)
1559  //     }
1560  //   }
1561
1562  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1563  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1564  //       case (((valid, pd), ans), taken) =>
1565  //       Mux(valid && pd.isBr,
1566  //         isWrong ^ (ans.taken.asBool === taken),
1567  //       false.B)
1568  //     }
1569  //   }
1570
1571  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1572  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1573  //       case (((valid, pd), ans), taken) =>
1574  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1575  //         isWrong ^ (!taken),
1576  //           false.B)
1577  //     }
1578  //   }
1579
1580  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1581  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1582  //       case (((valid, pd), ans), taken) =>
1583  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1584  //         isWrong ^ (ans.target === commitEntry.target),
1585  //           false.B)
1586  //     }
1587  //   }
1588
1589  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1590  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1591  //   // btb and ubtb pred jal and jalr as well
1592  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1593  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1594  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1595  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1596
1597  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1598  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1599
1600  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1601  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1602
1603  val perfEvents = Seq(
1604    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1605    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1606    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1607    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1608    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1609    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1610    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1611    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1612    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1613    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1614    ("BpRight                ", PopCount(mbpRights)                                                         ),
1615    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1616    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1617    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1618    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1619    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1620    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1621    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1622    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1623    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1624    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1625    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1626    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1627    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1628  )
1629  generatePerfEvent()
1630}
1631