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