xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision 8241cb85f7d34397435cf2810442754e2a0f477d)
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: jmp + alu(aluCnt) + ldReplay + exception
486  val aluAheadStart = 1
487  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i + aluAheadStart))) // only alu
488  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum, 1)
489
490  val aheadValid   = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid
491  val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
492  val backendRedirect = Wire(Valid(new BranchPredictionRedirect))
493  val backendRedirectReg = RegNext(backendRedirect)
494  backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid)
495  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
496  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
497
498  val stage2Flush = backendRedirect.valid
499  val backendFlush = stage2Flush || RegNext(stage2Flush)
500  val ifuFlush = Wire(Bool())
501
502  val flush = stage2Flush || RegNext(stage2Flush)
503
504  val allowBpuIn, allowToIfu = WireInit(false.B)
505  val flushToIfu = !allowToIfu
506  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
507  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
508
509  def copyNum = 5
510  val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U))
511  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
512  val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U))
513  val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
514  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
515  val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
516  require(FtqSize >= 4)
517  val ifuPtr_write       = WireInit(ifuPtr)
518  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
519  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
520  val ifuWbPtr_write     = WireInit(ifuWbPtr)
521  val commPtr_write      = WireInit(commPtr)
522  val commPtrPlus1_write = WireInit(commPtrPlus1)
523  val robCommPtr_write   = WireInit(robCommPtr)
524  ifuPtr       := ifuPtr_write
525  ifuPtrPlus1  := ifuPtrPlus1_write
526  ifuPtrPlus2  := ifuPtrPlus2_write
527  ifuWbPtr     := ifuWbPtr_write
528  commPtr      := commPtr_write
529  commPtrPlus1 := commPtrPlus1_write
530  copied_ifu_ptr.map{ptr =>
531    ptr := ifuPtr_write
532    dontTouch(ptr)
533  }
534  robCommPtr   := robCommPtr_write
535  val validEntries = distanceBetween(bpuPtr, commPtr)
536  val canCommit = Wire(Bool())
537
538  // **********************************************************************
539  // **************************** enq from bpu ****************************
540  // **********************************************************************
541  val new_entry_ready = validEntries < FtqSize.U || canCommit
542  io.fromBpu.resp.ready := new_entry_ready
543
544  val bpu_s2_resp = io.fromBpu.resp.bits.s2
545  val bpu_s3_resp = io.fromBpu.resp.bits.s3
546  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
547  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
548
549  io.toBpu.enq_ptr := bpuPtr
550  val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
551  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
552
553  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
554  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq
555  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
556  val bpu_in_resp_idx = bpu_in_resp_ptr.value
557
558  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
559  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
560  // resp from uBTB
561  ftq_pc_mem.io.wen := bpu_in_fire
562  ftq_pc_mem.io.waddr := bpu_in_resp_idx
563  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
564
565  //                                                            ifuRedirect + backendRedirect + commit
566  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1))
567  // these info is intended to enq at the last stage of bpu
568  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
569  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
570  ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info
571  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
572  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
573
574  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
575  // these info is intended to enq at the last stage of bpu
576  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
577  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
578  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta
579  //                                                            ifuRedirect + backendRedirect + commit
580  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1))
581  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3)
582  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
583  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
584
585
586  // multi-write
587  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
588  val newest_entry_target = Reg(UInt(VAddrBits.W))
589  val newest_entry_ptr = Reg(new FtqPtr)
590  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
591  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
592  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
593  val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
594
595  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
596  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
597    VecInit(Seq.fill(PredictWidth)(c_invalid))
598  }))
599
600  val f_to_send :: f_sent :: Nil = Enum(2)
601  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
602
603  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
604  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
605
606  // modify registers one cycle later to cut critical path
607  val last_cycle_bpu_in = RegNext(bpu_in_fire)
608  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
609  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
610  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3))
611  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3))
612  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
613
614  def extra_copyNum_for_commitStateQueue = 2
615  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
616  val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr)))
617
618  when (last_cycle_bpu_in) {
619    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
620    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
621    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
622
623    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
624    newest_entry_target := last_cycle_bpu_target
625    newest_entry_ptr := last_cycle_bpu_in_ptr
626  }
627
628  // reduce fanout by delay write for a cycle
629  when (RegNext(last_cycle_bpu_in)) {
630    mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
631  }
632
633  // record s1 pred cycles
634  pred_s1_cycle.map(vec => {
635    when (bpu_in_fire && (bpu_in_stage === BP_S1)) {
636      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
637    }
638  })
639
640  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
641  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
642  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
643    case ((in, ptr), i) =>
644      when (in) {
645        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
646        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
647        for (j <- 0 until perSetEntries) {
648          when (ptr.value === (i*perSetEntries+j).U) {
649            commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid))
650          }
651        }
652      }
653  }
654
655  // num cycle is fixed
656  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
657  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
658
659
660  bpuPtr := bpuPtr + enq_fire
661  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
662  when (io.toIfu.req.fire && allowToIfu) {
663    ifuPtr_write := ifuPtrPlus1
664    ifuPtrPlus1_write := ifuPtrPlus2
665    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
666  }
667
668  // only use ftb result to assign hit status
669  when (bpu_s2_resp.valid(3)) {
670    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
671  }
672
673
674  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
675  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
676  when (bpu_s2_redirect) {
677    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
678    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
679    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
680    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
681      ifuPtr_write := bpu_s2_resp.ftq_idx
682      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
683      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
684    }
685  }
686
687  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
688  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
689  when (bpu_s3_redirect) {
690    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
691    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
692    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
693    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
694      ifuPtr_write := bpu_s3_resp.ftq_idx
695      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
696      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
697    }
698  }
699
700  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
701  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
702
703  (0 until copyNum).map{i =>
704    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
705  }
706
707  // ****************************************************************
708  // **************************** to ifu ****************************
709  // ****************************************************************
710  // 0  for ifu, and 1-4 for ICache
711  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
712  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
713  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
714  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
715  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
716
717  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
718  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
719
720  // read pc and target
721  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
722  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
723  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
724  ftq_pc_mem.io.commPtr_w      := commPtr_write
725  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
726
727
728  io.toIfu.req.bits.ftqIdx := ifuPtr
729
730  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
731  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
732  val toIfuPcBundle = Wire(new Ftq_RF_Components)
733  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
734  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
735  val entry_next_addr  = Wire(UInt(VAddrBits.W))
736
737  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
738  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
739  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
740
741  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))))
742  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)))
743
744  for(i <- 0 until copyNum){
745    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
746      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
747      toICacheEntryToSend(i)   := true.B
748    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
749      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
750      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
751    }.otherwise{
752      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
753      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
754    }
755  }
756
757  // TODO: reconsider target address bypass logic
758  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
759    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
760    entry_is_to_send := true.B
761    entry_next_addr := last_cycle_bpu_target
762    entry_ftq_offset := last_cycle_cfiIndex
763    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
764  }.elsewhen (last_cycle_to_ifu_fire) {
765    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
766    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
767                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
768    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
769                          bpu_in_bypass_buf_for_ifu.startAddr,
770                          Mux(ifuPtr === newest_entry_ptr,
771                            newest_entry_target,
772                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
773  }.otherwise {
774    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
775    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
776                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
777    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
778                          bpu_in_bypass_buf_for_ifu.startAddr,
779                          Mux(ifuPtr === newest_entry_ptr,
780                            newest_entry_target,
781                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
782  }
783
784  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
785  io.toIfu.req.bits.nextStartAddr := entry_next_addr
786  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
787  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
788
789  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
790  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
791  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
792  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
793  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
794  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
795  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
796  // }
797
798  // TODO: remove this
799  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
800          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
801
802  // when fall through is smaller in value than start address, there must be a false hit
803  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
804    when (io.toIfu.req.fire &&
805      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
806      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
807    ) {
808      entry_hit_status(ifuPtr.value) := h_false_hit
809      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
810    }
811    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
812  }
813
814  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
815    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
816
817  val ifu_req_should_be_flushed =
818    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
819    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
820
821    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
822      entry_fetch_status(ifuPtr.value) := f_sent
823    }
824
825  // *********************************************************************
826  // **************************** wb from ifu ****************************
827  // *********************************************************************
828  val pdWb = io.fromIfu.pdWb
829  val pds = pdWb.bits.pd
830  val ifu_wb_valid = pdWb.valid
831  val ifu_wb_idx = pdWb.bits.ftqIdx.value
832  // read ports:                                                         commit update
833  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
834  ftq_pd_mem.io.wen(0) := ifu_wb_valid
835  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
836  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
837
838  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
839  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
840  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
841  val pd_reg       = RegEnable(pds,             pdWb.valid)
842  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
843  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
844
845  when (ifu_wb_valid) {
846    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
847      case (v, inRange) => v && inRange
848    })
849    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
850      case (qe, v) => when (v) { qe := c_valid }
851    }
852  }
853
854  when (ifu_wb_valid) {
855    ifuWbPtr_write := ifuWbPtr + 1.U
856  }
857
858  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
859
860  ftb_entry_mem.io.raddr.head := ifu_wb_idx
861  val has_false_hit = WireInit(false.B)
862  when (RegNext(hit_pd_valid)) {
863    // check for false hit
864    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
865    val brSlots = pred_ftb_entry.brSlots
866    val tailSlot = pred_ftb_entry.tailSlot
867    // we check cfis that bpu predicted
868
869    // bpu predicted branches but denied by predecode
870    val br_false_hit =
871      brSlots.map{
872        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
873      }.reduce(_||_) ||
874      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
875        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
876
877    val jmpOffset = tailSlot.offset
878    val jmp_pd = pd_reg(jmpOffset)
879    val jal_false_hit = pred_ftb_entry.jmpValid &&
880      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
881       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
882       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
883       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
884      )
885
886    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
887    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
888
889    // assert(!has_false_hit)
890  }
891
892  when (has_false_hit) {
893    entry_hit_status(wb_idx_reg) := h_false_hit
894  }
895
896
897  // **********************************************************************
898  // ***************************** to backend *****************************
899  // **********************************************************************
900  // to backend pc mem / target
901  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
902  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
903  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
904
905  // *******************************************************************************
906  // **************************** redirect from backend ****************************
907  // *******************************************************************************
908
909  // redirect read cfiInfo, couples to redirectGen s2
910  val redirectReadStart = 1 // 0 for ifuRedirect
911  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
912  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry))
913  for (i <- redirectReadStart until FtqRedirectAheadNum) {
914    ftq_redirect_sram.io.ren(i + redirectReadStart)   := ftqIdxAhead(i).valid
915    ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value
916    ftb_entry_mem.io.raddr(i + redirectReadStart)     := ftqIdxAhead(i).bits.value
917  }
918  ftq_redirect_sram.io.ren(redirectReadStart)   := Mux(aheadValid, ftqIdxAhead(0).valid,      backendRedirect.valid)
919  ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
920  ftb_entry_mem.io.raddr(redirectReadStart)     := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
921
922  for (i <- 0 until FtqRedirectAheadNum) {
923    ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart)
924    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart)
925  }
926  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart))
927  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
928  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
929
930
931  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart))
932  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
933
934  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
935  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
936  // FIXME: not portable
937  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
938  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
939    sc_disagree(0), sc_disagree(1))
940
941  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
942    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
943      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
944      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
945
946    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
947        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
948  }.otherwise {
949    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
950    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
951  }
952
953
954  // ***************************************************************************
955  // **************************** redirect from ifu ****************************
956  // ***************************************************************************
957  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
958  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
959  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
960  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
961  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
962  fromIfuRedirect.bits.BTBMissBubble := true.B
963  fromIfuRedirect.bits.debugIsMemVio := false.B
964  fromIfuRedirect.bits.debugIsCtrl := false.B
965
966  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
967  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
968  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
969  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
970  ifuRedirectCfiUpdate.target := pdWb.bits.target
971  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
972  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
973
974  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
975  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
976  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
977
978  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
979  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
980
981  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
982
983  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
984  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
985  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
986    toBpuCfi.target := toBpuCfi.topAddr
987  }
988
989  when (ifuRedirectReg.valid) {
990    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
991  } .elsewhen(RegNext(pdWb.valid)) {
992    // if pdWb and no redirect, set to false
993    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
994  }
995
996  // *********************************************************************
997  // **************************** wb from exu ****************************
998  // *********************************************************************
999
1000  backendRedirect.valid := io.fromBackend.redirect.valid
1001  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1002  backendRedirect.bits.BTBMissBubble := false.B
1003
1004
1005  def extractRedirectInfo(wb: Valid[Redirect]) = {
1006    val ftqPtr = wb.bits.ftqIdx
1007    val ftqOffset = wb.bits.ftqOffset
1008    val taken = wb.bits.cfiUpdate.taken
1009    val mispred = wb.bits.cfiUpdate.isMisPred
1010    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
1011  }
1012
1013  // fix mispredict entry
1014  val lastIsMispredict = RegNext(
1015    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
1016  )
1017
1018  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
1019    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
1020    val r_idx = r_ptr.value
1021    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
1022    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
1023    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
1024      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
1025    } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
1026      cfiIndex_vec(r_idx).valid :=false.B
1027    }
1028    when (cfiIndex_bits_wen) {
1029      cfiIndex_vec(r_idx).bits := r_offset
1030    }
1031    newest_entry_target := redirect.bits.cfiUpdate.target
1032    newest_entry_ptr := r_ptr
1033    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
1034    if (isBackend) {
1035      mispredict_vec(r_idx)(r_offset) := r_mispred
1036    }
1037  }
1038
1039  when(fromBackendRedirect.valid) {
1040    updateCfiInfo(fromBackendRedirect)
1041  }.elsewhen (ifuRedirectToBpu.valid) {
1042    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
1043  }
1044
1045  when (fromBackendRedirect.valid) {
1046    when (fromBackendRedirect.bits.ControlRedirectBubble) {
1047      when (fromBackendRedirect.bits.ControlBTBMissBubble) {
1048        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1049        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1050      } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) {
1051        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1052        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1053      } .elsewhen (fromBackendRedirect.bits.SCMissBubble) {
1054        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
1055        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1056      } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) {
1057        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1058        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1059      } .elsewhen (fromBackendRedirect.bits.RASMissBubble) {
1060        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
1061        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1062      }
1063
1064
1065    } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) {
1066      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1067      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1068    } .otherwise {
1069      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1070      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1071    }
1072  } .elsewhen (ifuRedirectReg.valid) {
1073    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1074    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1075  }
1076
1077  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1078  io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble
1079  io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble
1080  io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble
1081  io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble
1082
1083  // ***********************************************************************************
1084  // **************************** flush ptr and state queue ****************************
1085  // ***********************************************************************************
1086
1087  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
1088
1089  // when redirect, we should reset ptrs and status queues
1090  when(redirectVec.map(r => r.valid).reduce(_||_)){
1091    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1092    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1093    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1094    val next = idx + 1.U
1095    bpuPtr := next
1096    copied_bpu_ptr.map(_ := next)
1097    ifuPtr_write := next
1098    ifuWbPtr_write := next
1099    ifuPtrPlus1_write := idx + 2.U
1100    ifuPtrPlus2_write := idx + 3.U
1101
1102  }
1103  when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){
1104    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1105    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1106    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1107    when (RegNext(notIfu)) {
1108      commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) =>
1109        when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){
1110          s := c_invalid
1111        }
1112      })
1113    }
1114  }
1115
1116
1117  // only the valid bit is actually needed
1118  io.toIfu.redirect.bits    := backendRedirect.bits
1119  io.toIfu.redirect.valid   := stage2Flush
1120  io.toIfu.topdown_redirect := fromBackendRedirect
1121
1122  // commit
1123  for (c <- io.fromBackend.rob_commits) {
1124    when(c.valid) {
1125      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
1126      // TODO: remove this
1127      // For instruction fusions, we also update the next instruction
1128      when (c.bits.commitType === 4.U) {
1129        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
1130      }.elsewhen(c.bits.commitType === 5.U) {
1131        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
1132      }.elsewhen(c.bits.commitType === 6.U) {
1133        val index = (c.bits.ftqIdx + 1.U).value
1134        commitStateQueue(index)(0) := c_commited
1135      }.elsewhen(c.bits.commitType === 7.U) {
1136        val index = (c.bits.ftqIdx + 1.U).value
1137        commitStateQueue(index)(1) := c_commited
1138      }
1139    }
1140  }
1141
1142  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)
1143
1144  // ****************************************************************
1145  // **************************** to bpu ****************************
1146  // ****************************************************************
1147
1148  io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1149  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W)))
1150  val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1151  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1152  XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1)
1153
1154  XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay")
1155
1156  val may_have_stall_from_bpu = Wire(Bool())
1157  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
1158  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
1159  val notInvalidSeq = commitStateQueue(commPtr.value).map(s => s =/= c_invalid).reverse
1160  // Todo: @huxuan check it
1161  //  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1162  //    Cat(commitStateQueue(commPtr.value).map(s => {
1163  //      s === c_invalid || s === c_commited
1164  //    })).andR
1165  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1166    (isAfter(robCommPtr, commPtr) || PriorityMuxDefault(notInvalidSeq.zip(commitStateQueue(commPtr.value).reverse), c_invalid) === c_commited)
1167
1168  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
1169  val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr)  ||  mmioReadPtr ===   ifuPtr) &&
1170                       Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR
1171  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
1172
1173  // commit reads
1174  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1175  val commit_target =
1176    Mux(RegNext(commPtr === newest_entry_ptr),
1177      RegNext(newest_entry_target),
1178      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1179  ftq_pd_mem.io.raddr.last := commPtr.value
1180  val commit_pd = ftq_pd_mem.io.rdata.last
1181  ftq_redirect_sram.io.ren.last := canCommit
1182  ftq_redirect_sram.io.raddr.last := commPtr.value
1183  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
1184  ftq_meta_1r_sram.io.ren(0) := canCommit
1185  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1186  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
1187  ftb_entry_mem.io.raddr.last := commPtr.value
1188  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
1189
1190  // need one cycle to read mem and srams
1191  val do_commit_ptr = RegNext(commPtr)
1192  val do_commit = RegNext(canCommit, init=false.B)
1193  when (canCommit) {
1194    commPtr_write := commPtrPlus1
1195    commPtrPlus1_write := commPtrPlus1 + 1.U
1196  }
1197  val commit_state = RegNext(commitStateQueue(commPtr.value))
1198  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1199  val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value))
1200  //
1201  //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1202  //  can_commit_cfi.valid := false.B
1203  //}
1204  val commit_cfi = RegNext(can_commit_cfi)
1205  val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid
1206
1207  val commit_mispredict  : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
1208    case (mis, state) => mis && state === c_commited
1209  })
1210  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth]
1211  val can_commit_hit                 = entry_hit_status(commPtr.value)
1212  val commit_hit                     = RegNext(can_commit_hit)
1213  val diff_commit_target             = RegNext(update_target(commPtr.value)) // TODO: remove this
1214  val commit_stage                   = RegNext(pred_stage(commPtr.value))
1215  val commit_valid                   = commit_hit === h_hit || commit_cfi.valid // hit or taken
1216
1217  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1218  switch (bpu_ftb_update_stall) {
1219    is (0.U) {
1220      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1221        bpu_ftb_update_stall := 2.U // 2-cycle stall
1222      }
1223    }
1224    is (2.U) {
1225      bpu_ftb_update_stall := 1.U
1226    }
1227    is (1.U) {
1228      bpu_ftb_update_stall := 0.U
1229    }
1230    is (3.U) {
1231      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1232    }
1233  }
1234
1235  // TODO: remove this
1236  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1237
1238  // update latency stats
1239  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1240  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1241
1242  io.toBpu.update := DontCare
1243  io.toBpu.update.valid := commit_valid && do_commit
1244  val update = io.toBpu.update.bits
1245  update.false_hit   := commit_hit === h_false_hit
1246  update.pc          := commit_pc_bundle.startAddr
1247  update.meta        := commit_meta.meta
1248  update.cfi_idx     := commit_cfi
1249  update.full_target := commit_target
1250  update.from_stage  := commit_stage
1251  update.spec_info   := commit_spec_meta
1252  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
1253
1254  val commit_real_hit = commit_hit === h_hit
1255  val update_ftb_entry = update.ftb_entry
1256
1257  val ftbEntryGen = Module(new FTBEntryGen).io
1258  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1259  ftbEntryGen.old_entry      := commit_ftb_entry
1260  ftbEntryGen.pd             := commit_pd
1261  ftbEntryGen.cfiIndex       := commit_cfi
1262  ftbEntryGen.target         := commit_target
1263  ftbEntryGen.hit            := commit_real_hit
1264  ftbEntryGen.mispredict_vec := commit_mispredict
1265
1266  update_ftb_entry         := ftbEntryGen.new_entry
1267  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1268  update.mispred_mask      := ftbEntryGen.mispred_mask
1269  update.old_entry         := ftbEntryGen.is_old_entry
1270  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1271  update.br_taken_mask     := ftbEntryGen.taken_mask
1272  update.br_committed      := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1273    case (valid, offset) => valid && commit_instCommited(offset)
1274  }
1275  update.jmp_taken         := ftbEntryGen.jmp_taken
1276
1277  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1278  // update.full_pred.jalr_target := commit_target
1279  // update.full_pred.hit := true.B
1280  // when (update.full_pred.is_jalr) {
1281  //   update.full_pred.targets.last := commit_target
1282  // }
1283
1284  // ****************************************************************
1285  // *********************** to prefetch ****************************
1286  // ****************************************************************
1287  /**
1288    ******************************************************************************
1289    * prefetchPtr control
1290    * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2
1291    * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange]
1292    * - 3. flush prefetchPtr when receive redirect from ifu or backend
1293    ******************************************************************************
1294    */
1295  val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1296  val nextPrefetchPtr = WireInit(prefetchPtr)
1297
1298  prefetchPtr := nextPrefetchPtr
1299
1300  // TODO: consider req which cross cacheline
1301  when(io.toPrefetch.req.fire) {
1302    when(prefetchPtr < bpuPtr - 2.U) {
1303      nextPrefetchPtr := prefetchPtr + 1.U
1304    }
1305  }
1306
1307  when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) {
1308    nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U
1309  }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) {
1310    nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U
1311  }
1312
1313  when(redirectVec.map(r => r.valid).reduce(_||_)){
1314    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1315    val next = r.ftqIdx + minRangeFromIFUptr.U
1316    nextPrefetchPtr := next
1317  }
1318
1319  // data from ftq_pc_mem has 1 cycle delay
1320  io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send)
1321  ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value
1322  io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr)
1323
1324  // record position relationship between ifuPtr, pfPtr and bpuPtr
1325  val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString))
1326  val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB)
1327  val prefetchPtrDumpData = Wire(new PrefetchPtrDB)
1328  prefetchPtrDumpData.fromFtqPtr  := distanceBetween(bpuPtr, prefetchPtr)
1329  prefetchPtrDumpData.fromIfuPtr  := distanceBetween(prefetchPtr, ifuPtr)
1330
1331  prefetchPtrTable.log(
1332    data = prefetchPtrDumpData,
1333    en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire,
1334    site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1335    clock = clock,
1336    reset = reset
1337  )
1338
1339
1340  // ******************************************************************************
1341  // **************************** commit perf counters ****************************
1342  // ******************************************************************************
1343
1344  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1345  val commit_mispred_mask = commit_mispredict.asUInt
1346  val commit_not_mispred_mask = ~commit_mispred_mask
1347
1348  val commit_br_mask = commit_pd.brMask.asUInt
1349  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1350  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1351
1352  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1353
1354  val mbpRights = mbpInstrs & commit_not_mispred_mask
1355  val mbpWrongs = mbpInstrs & commit_mispred_mask
1356
1357  io.bpuInfo.bpRight := PopCount(mbpRights)
1358  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1359
1360  val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString))
1361  val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle)
1362  // Cfi Info
1363  for (i <- 0 until PredictWidth) {
1364    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1365    val v = commit_state(i) === c_commited
1366    val isBr = commit_pd.brMask(i)
1367    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1368    val isCfi = isBr || isJmp
1369    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1370    val misPred = commit_mispredict(i)
1371    // val ghist = commit_spec_meta.ghist.predHist
1372    val histPtr = commit_spec_meta.histPtr
1373    val predCycle = commit_meta.meta(63, 0)
1374    val target = commit_target
1375
1376    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1377    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1378    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1379    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1380    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1381    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1382    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1383
1384    val logbundle = Wire(new FtqDebugBundle)
1385    logbundle.pc := pc
1386    logbundle.target := target
1387    logbundle.isBr := isBr
1388    logbundle.isJmp := isJmp
1389    logbundle.isCall := isJmp && commit_pd.hasCall
1390    logbundle.isRet := isJmp && commit_pd.hasRet
1391    logbundle.misPred := misPred
1392    logbundle.isTaken := isTaken
1393    logbundle.predStage := commit_stage
1394
1395    ftqBranchTraceDB.log(
1396      data = logbundle /* hardware of type T */,
1397      en = isWriteFTQTable.orR && v && do_commit && isCfi,
1398      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1399      clock = clock,
1400      reset = reset
1401    )
1402  }
1403
1404  val enq = io.fromBpu.resp
1405  val perf_redirect = backendRedirect
1406
1407  XSPerfAccumulate("entry", validEntries)
1408  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1409  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1410  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1411  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1412
1413  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1414
1415  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1416  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1417  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1418  XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready)
1419
1420  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_))
1421  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
1422  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
1423
1424  val from_bpu = io.fromBpu.resp.bits
1425  val to_ifu = io.toIfu.req.bits
1426
1427
1428  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1)
1429
1430
1431
1432
1433  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1434  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1435  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1436  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1437
1438
1439  val mbpBRights = mbpRights & commit_br_mask
1440  val mbpJRights = mbpRights & commit_jal_mask
1441  val mbpIRights = mbpRights & commit_jalr_mask
1442  val mbpCRights = mbpRights & commit_call_mask
1443  val mbpRRights = mbpRights & commit_ret_mask
1444
1445  val mbpBWrongs = mbpWrongs & commit_br_mask
1446  val mbpJWrongs = mbpWrongs & commit_jal_mask
1447  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1448  val mbpCWrongs = mbpWrongs & commit_call_mask
1449  val mbpRWrongs = mbpWrongs & commit_ret_mask
1450
1451  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1452
1453  def pred_stage_map(src: UInt, name: String) = {
1454    (0 until numBpStages).map(i =>
1455      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1456    ).foldLeft(Map[String, UInt]())(_+_)
1457  }
1458
1459  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1460  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1461  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1462  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1463  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1464  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1465
1466  val update_valid = io.toBpu.update.valid
1467  def u(cond: Bool) = update_valid && cond
1468  val ftb_false_hit = u(update.false_hit)
1469  // assert(!ftb_false_hit)
1470  val ftb_hit = u(commit_hit === h_hit)
1471
1472  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1473  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1474  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1475  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1476
1477  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1478
1479  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1480  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1481  val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value))
1482  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1483  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1484  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1485
1486  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1487  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1488  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1)
1489  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1)
1490  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1491  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1)
1492
1493  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1)
1494
1495  val perfCountsMap = Map(
1496    "BpInstr" -> PopCount(mbpInstrs),
1497    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1498    "BpRight"  -> PopCount(mbpRights),
1499    "BpWrong"  -> PopCount(mbpWrongs),
1500    "BpBRight" -> PopCount(mbpBRights),
1501    "BpBWrong" -> PopCount(mbpBWrongs),
1502    "BpJRight" -> PopCount(mbpJRights),
1503    "BpJWrong" -> PopCount(mbpJWrongs),
1504    "BpIRight" -> PopCount(mbpIRights),
1505    "BpIWrong" -> PopCount(mbpIWrongs),
1506    "BpCRight" -> PopCount(mbpCRights),
1507    "BpCWrong" -> PopCount(mbpCWrongs),
1508    "BpRRight" -> PopCount(mbpRRights),
1509    "BpRWrong" -> PopCount(mbpRWrongs),
1510
1511    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1512    "ftb_hit"                      -> PopCount(ftb_hit),
1513    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1514    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1515    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1516    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1517    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1518    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1519    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1520    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1521    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1522    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1523  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1524       correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1525
1526  for((key, value) <- perfCountsMap) {
1527    XSPerfAccumulate(key, value)
1528  }
1529
1530  // --------------------------- Debug --------------------------------
1531  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1532  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1533  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1534  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1535  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1536    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1537  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1538
1539  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1540  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1541  //       case (((valid, pd), ans), taken) =>
1542  //       Mux(valid && pd.isBr,
1543  //         isWrong ^ Mux(ans.hit.asBool,
1544  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1545  //           !taken),
1546  //         !taken),
1547  //       false.B)
1548  //     }
1549  //   }
1550
1551  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1552  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1553  //       case (((valid, pd), ans), taken) =>
1554  //       Mux(valid && pd.isBr,
1555  //         isWrong ^ Mux(ans.hit.asBool,
1556  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1557  //           !taken),
1558  //         !taken),
1559  //       false.B)
1560  //     }
1561  //   }
1562
1563  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1564  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1565  //       case (((valid, pd), ans), taken) =>
1566  //       Mux(valid && pd.isBr,
1567  //         isWrong ^ (ans.taken.asBool === taken),
1568  //       false.B)
1569  //     }
1570  //   }
1571
1572  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1573  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1574  //       case (((valid, pd), ans), taken) =>
1575  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1576  //         isWrong ^ (!taken),
1577  //           false.B)
1578  //     }
1579  //   }
1580
1581  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1582  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1583  //       case (((valid, pd), ans), taken) =>
1584  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1585  //         isWrong ^ (ans.target === commitEntry.target),
1586  //           false.B)
1587  //     }
1588  //   }
1589
1590  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1591  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1592  //   // btb and ubtb pred jal and jalr as well
1593  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1594  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1595  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1596  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1597
1598  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1599  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1600
1601  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1602  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1603
1604  val perfEvents = Seq(
1605    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1606    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1607    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1608    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1609    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1610    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1611    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1612    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1613    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1614    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1615    ("BpRight                ", PopCount(mbpRights)                                                         ),
1616    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1617    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1618    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1619    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1620    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1621    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1622    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1623    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1624    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1625    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1626    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1627    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1628    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1629  )
1630  generatePerfEvent()
1631}
1632