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