xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision ff3fcdf11874ffacafd64ec81fd1c4893f58150b)
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_en = Output(Bool())
217  val newest_entry_target = Output(UInt(VAddrBits.W))
218  val newest_entry_ptr = Output(new FtqPtr)
219}
220
221
222class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
223  val io = IO(new Bundle {
224    val start_addr = Input(UInt(VAddrBits.W))
225    val old_entry = Input(new FTBEntry)
226    val pd = Input(new Ftq_pd_Entry)
227    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
228    val target = Input(UInt(VAddrBits.W))
229    val hit = Input(Bool())
230    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
231
232    val new_entry = Output(new FTBEntry)
233    val new_br_insert_pos = Output(Vec(numBr, Bool()))
234    val taken_mask = Output(Vec(numBr, Bool()))
235    val jmp_taken = Output(Bool())
236    val mispred_mask = Output(Vec(numBr+1, Bool()))
237
238    // for perf counters
239    val is_init_entry = Output(Bool())
240    val is_old_entry = Output(Bool())
241    val is_new_br = Output(Bool())
242    val is_jalr_target_modified = Output(Bool())
243    val is_always_taken_modified = Output(Bool())
244    val is_br_full = Output(Bool())
245  })
246
247  // no mispredictions detected at predecode
248  val hit = io.hit
249  val pd = io.pd
250
251  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
252
253
254  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
255  val entry_has_jmp = pd.jmpInfo.valid
256  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
257  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
258  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
259  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
260  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
261  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
262
263  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
264  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
265
266  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
267  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
268  // if not hit, establish a new entry
269  init_entry.valid := true.B
270  // tag is left for ftb to assign
271
272  // case br
273  val init_br_slot = init_entry.getSlotForBr(0)
274  when (cfi_is_br) {
275    init_br_slot.valid := true.B
276    init_br_slot.offset := io.cfiIndex.bits
277    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
278    init_entry.always_taken(0) := true.B // set to always taken on init
279  }
280
281  // case jmp
282  when (entry_has_jmp) {
283    init_entry.tailSlot.offset := pd.jmpOffset
284    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
285    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
286  }
287
288  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
289  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
290  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
291  init_entry.isJalr := new_jmp_is_jalr
292  init_entry.isCall := new_jmp_is_call
293  init_entry.isRet  := new_jmp_is_ret
294  // that means fall thru points to the middle of an inst
295  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
296
297  // if hit, check whether a new cfi(only br is possible) is detected
298  val oe = io.old_entry
299  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
300  val br_recorded = br_recorded_vec.asUInt.orR
301  val is_new_br = cfi_is_br && !br_recorded
302  val new_br_offset = io.cfiIndex.bits
303  // vec(i) means new br will be inserted BEFORE old br(i)
304  val allBrSlotsVec = oe.allSlotsForBr
305  val new_br_insert_onehot = VecInit((0 until numBr).map{
306    i => i match {
307      case 0 =>
308        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
309      case idx =>
310        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
311        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
312    }
313  })
314
315  val old_entry_modified = WireInit(io.old_entry)
316  for (i <- 0 until numBr) {
317    val slot = old_entry_modified.allSlotsForBr(i)
318    when (new_br_insert_onehot(i)) {
319      slot.valid := true.B
320      slot.offset := new_br_offset
321      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
322      old_entry_modified.always_taken(i) := true.B
323    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
324      old_entry_modified.always_taken(i) := false.B
325      // all other fields remain unchanged
326    }.otherwise {
327      // case i == 0, remain unchanged
328      if (i != 0) {
329        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
330        when (!noNeedToMoveFromFormerSlot) {
331          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
332          old_entry_modified.always_taken(i) := oe.always_taken(i)
333        }
334      }
335    }
336  }
337
338  // two circumstances:
339  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
340  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
341  //        the previous last br or the new br
342  val may_have_to_replace = oe.noEmptySlotForNewBr
343  val pft_need_to_change = is_new_br && may_have_to_replace
344  // it should either be the given last br or the new br
345  when (pft_need_to_change) {
346    val new_pft_offset =
347      Mux(!new_br_insert_onehot.asUInt.orR,
348        new_br_offset, oe.allSlotsForBr.last.offset)
349
350    // set jmp to invalid
351    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
352    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
353    old_entry_modified.last_may_be_rvi_call := false.B
354    old_entry_modified.isCall := false.B
355    old_entry_modified.isRet := false.B
356    old_entry_modified.isJalr := false.B
357  }
358
359  val old_entry_jmp_target_modified = WireInit(oe)
360  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
361  val old_tail_is_jmp = !oe.tailSlot.sharing
362  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
363  when (jalr_target_modified) {
364    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
365    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
366  }
367
368  val old_entry_always_taken = WireInit(oe)
369  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
370  for (i <- 0 until numBr) {
371    old_entry_always_taken.always_taken(i) :=
372      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
373    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
374  }
375  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
376
377
378
379  val derived_from_old_entry =
380    Mux(is_new_br, old_entry_modified,
381      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
382
383
384  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
385
386  io.new_br_insert_pos := new_br_insert_onehot
387  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
388    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
389  })
390  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
391  for (i <- 0 until numBr) {
392    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
393  }
394  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
395
396  // for perf counters
397  io.is_init_entry := !hit
398  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
399  io.is_new_br := hit && is_new_br
400  io.is_jalr_target_modified := hit && jalr_target_modified
401  io.is_always_taken_modified := hit && always_taken_modified
402  io.is_br_full := hit && is_new_br && may_have_to_replace
403}
404
405class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
406  val io = IO(new Bundle {
407    val ifuPtr_w       = Input(new FtqPtr)
408    val ifuPtrPlus1_w  = Input(new FtqPtr)
409    val ifuPtrPlus2_w  = Input(new FtqPtr)
410    val commPtr_w      = Input(new FtqPtr)
411    val commPtrPlus1_w = Input(new FtqPtr)
412    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
413    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
414    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
415    val commPtr_rdata      = Output(new Ftq_RF_Components)
416    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
417
418    val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W)))
419    val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components))
420
421    val wen = Input(Bool())
422    val waddr = Input(UInt(log2Ceil(FtqSize).W))
423    val wdata = Input(new Ftq_RF_Components)
424  })
425
426  val num_pc_read = numOtherReads + 5
427  val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize,
428    num_pc_read, 1, "FtqPC"))
429  mem.io.wen(0)   := io.wen
430  mem.io.waddr(0) := io.waddr
431  mem.io.wdata(0) := io.wdata
432
433  // read one cycle ahead for ftq local reads
434  val raddr_vec = VecInit(io.other_raddrs ++
435    Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value))
436
437  mem.io.raddr := raddr_vec
438
439  io.other_rdatas       := mem.io.rdata.dropRight(5)
440  io.ifuPtr_rdata       := mem.io.rdata.dropRight(4).last
441  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(3).last
442  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(2).last
443  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
444  io.commPtr_rdata      := mem.io.rdata.last
445}
446
447class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
448  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
449  with HasICacheParameters{
450  val io = IO(new Bundle {
451    val fromBpu = Flipped(new BpuToFtqIO)
452    val fromIfu = Flipped(new IfuToFtqIO)
453    val fromBackend = Flipped(new CtrlToFtqIO)
454
455    val toBpu = new FtqToBpuIO
456    val toIfu = new FtqToIfuIO
457    val toICache = new FtqToICacheIO
458    val toBackend = new FtqToCtrlIO
459
460    val toPrefetch = new FtqPrefechBundle
461
462    val bpuInfo = new Bundle {
463      val bpRight = Output(UInt(XLEN.W))
464      val bpWrong = Output(UInt(XLEN.W))
465    }
466
467    val mmioCommitRead = Flipped(new mmioCommitRead)
468
469    // for perf
470    val ControlBTBMissBubble = Output(Bool())
471    val TAGEMissBubble = Output(Bool())
472    val SCMissBubble = Output(Bool())
473    val ITTAGEMissBubble = Output(Bool())
474    val RASMissBubble = Output(Bool())
475  })
476  io.bpuInfo := DontCare
477
478  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
479  // only driven by clock, not valid-ready
480  topdown_stage := io.fromBpu.resp.bits.topdown_info
481  io.toIfu.req.bits.topdown_info := topdown_stage
482
483  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
484
485
486  // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception
487  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju
488  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0)
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  bpuPtr := bpuPtr + enq_fire
656  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
657  when (io.toIfu.req.fire && allowToIfu) {
658    ifuPtr_write := ifuPtrPlus1
659    ifuPtrPlus1_write := ifuPtrPlus2
660    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
661  }
662
663  // only use ftb result to assign hit status
664  when (bpu_s2_resp.valid(3)) {
665    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
666  }
667
668
669  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
670  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
671  when (bpu_s2_redirect) {
672    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
673    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
674    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
675    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
676      ifuPtr_write := bpu_s2_resp.ftq_idx
677      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
678      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
679    }
680  }
681
682  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
683  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
684  when (bpu_s3_redirect) {
685    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
686    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
687    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
688    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
689      ifuPtr_write := bpu_s3_resp.ftq_idx
690      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
691      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
692    }
693  }
694
695  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
696  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
697
698  (0 until copyNum).map{i =>
699    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
700  }
701
702  // ****************************************************************
703  // **************************** to ifu ****************************
704  // ****************************************************************
705  // 0  for ifu, and 1-4 for ICache
706  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
707  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
708  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
709  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
710  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
711
712  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
713  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
714
715  // read pc and target
716  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
717  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
718  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
719  ftq_pc_mem.io.commPtr_w      := commPtr_write
720  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
721
722
723  io.toIfu.req.bits.ftqIdx := ifuPtr
724
725  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
726  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
727  val toIfuPcBundle = Wire(new Ftq_RF_Components)
728  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
729  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
730  val entry_next_addr  = Wire(UInt(VAddrBits.W))
731
732  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
733  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
734  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
735
736  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))))
737  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)))
738
739  for(i <- 0 until copyNum){
740    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
741      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
742      toICacheEntryToSend(i)   := true.B
743    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
744      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
745      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
746    }.otherwise{
747      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
748      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
749    }
750  }
751
752  // TODO: reconsider target address bypass logic
753  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
754    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
755    entry_is_to_send := true.B
756    entry_next_addr := last_cycle_bpu_target
757    entry_ftq_offset := last_cycle_cfiIndex
758    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
759  }.elsewhen (last_cycle_to_ifu_fire) {
760    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
761    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
762                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
763    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
764                          bpu_in_bypass_buf_for_ifu.startAddr,
765                          Mux(ifuPtr === newest_entry_ptr,
766                            newest_entry_target,
767                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
768  }.otherwise {
769    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
770    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
771                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
772    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
773                          bpu_in_bypass_buf_for_ifu.startAddr,
774                          Mux(ifuPtr === newest_entry_ptr,
775                            newest_entry_target,
776                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
777  }
778
779  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
780  io.toIfu.req.bits.nextStartAddr := entry_next_addr
781  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
782  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
783
784  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
785  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
786  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
787  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
788  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
789  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
790  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
791  // }
792
793  // TODO: remove this
794  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
795          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
796
797  // when fall through is smaller in value than start address, there must be a false hit
798  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
799    when (io.toIfu.req.fire &&
800      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
801      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
802    ) {
803      entry_hit_status(ifuPtr.value) := h_false_hit
804      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
805    }
806    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
807  }
808
809  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
810    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
811
812  val ifu_req_should_be_flushed =
813    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
814    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
815
816    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
817      entry_fetch_status(ifuPtr.value) := f_sent
818    }
819
820  // *********************************************************************
821  // **************************** wb from ifu ****************************
822  // *********************************************************************
823  val pdWb = io.fromIfu.pdWb
824  val pds = pdWb.bits.pd
825  val ifu_wb_valid = pdWb.valid
826  val ifu_wb_idx = pdWb.bits.ftqIdx.value
827  // read ports:                                                         commit update
828  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
829  ftq_pd_mem.io.wen(0) := ifu_wb_valid
830  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
831  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
832
833  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
834  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
835  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
836  val pd_reg       = RegEnable(pds,             pdWb.valid)
837  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
838  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
839
840  when (ifu_wb_valid) {
841    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
842      case (v, inRange) => v && inRange
843    })
844    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
845      case (qe, v) => when (v) { qe := c_valid }
846    }
847  }
848
849  when (ifu_wb_valid) {
850    ifuWbPtr_write := ifuWbPtr + 1.U
851  }
852
853  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
854
855  ftb_entry_mem.io.raddr.head := ifu_wb_idx
856  val has_false_hit = WireInit(false.B)
857  when (RegNext(hit_pd_valid)) {
858    // check for false hit
859    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
860    val brSlots = pred_ftb_entry.brSlots
861    val tailSlot = pred_ftb_entry.tailSlot
862    // we check cfis that bpu predicted
863
864    // bpu predicted branches but denied by predecode
865    val br_false_hit =
866      brSlots.map{
867        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
868      }.reduce(_||_) ||
869      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
870        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
871
872    val jmpOffset = tailSlot.offset
873    val jmp_pd = pd_reg(jmpOffset)
874    val jal_false_hit = pred_ftb_entry.jmpValid &&
875      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
876       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
877       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
878       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
879      )
880
881    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
882    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
883
884    // assert(!has_false_hit)
885  }
886
887  when (has_false_hit) {
888    entry_hit_status(wb_idx_reg) := h_false_hit
889  }
890
891  // *******************************************************************************
892  // **************************** redirect from backend ****************************
893  // *******************************************************************************
894
895  // redirect read cfiInfo, couples to redirectGen s2
896  val redirectReadStart = 1 // 0 for ifuRedirect
897  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
898  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry))
899  for (i <- redirectReadStart until FtqRedirectAheadNum) {
900    ftq_redirect_sram.io.ren(i + redirectReadStart)   := ftqIdxAhead(i).valid
901    ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value
902    ftb_entry_mem.io.raddr(i + redirectReadStart)     := ftqIdxAhead(i).bits.value
903  }
904  ftq_redirect_sram.io.ren(redirectReadStart)   := Mux(aheadValid, ftqIdxAhead(0).valid,      backendRedirect.valid)
905  ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
906  ftb_entry_mem.io.raddr(redirectReadStart)     := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
907
908  for (i <- 0 until FtqRedirectAheadNum) {
909    ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart)
910    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart)
911  }
912  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart))
913  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
914  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
915
916
917  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart))
918  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
919
920  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
921  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
922  // FIXME: not portable
923  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
924  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
925    sc_disagree(0), sc_disagree(1))
926
927  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
928    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
929      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
930      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
931
932    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
933        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
934  }.otherwise {
935    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
936    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
937  }
938
939
940  // ***************************************************************************
941  // **************************** redirect from ifu ****************************
942  // ***************************************************************************
943  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
944  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
945  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
946  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
947  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
948  fromIfuRedirect.bits.BTBMissBubble := true.B
949  fromIfuRedirect.bits.debugIsMemVio := false.B
950  fromIfuRedirect.bits.debugIsCtrl := false.B
951
952  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
953  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
954  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
955  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
956  ifuRedirectCfiUpdate.target := pdWb.bits.target
957  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
958  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
959
960  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
961  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
962  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
963
964  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
965  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
966
967  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
968
969  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
970  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
971  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
972    toBpuCfi.target := toBpuCfi.topAddr
973  }
974
975  when (ifuRedirectReg.valid) {
976    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
977  } .elsewhen(RegNext(pdWb.valid)) {
978    // if pdWb and no redirect, set to false
979    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
980  }
981
982  // **********************************************************************
983  // ***************************** to backend *****************************
984  // **********************************************************************
985  // to backend pc mem / target
986  io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in)
987  io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)
988  io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in)
989
990  // num cycle is fixed
991  val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid)
992  io.toBackend.newest_entry_en := RegNext(newest_entry_en)
993  io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en)
994  io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en)
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