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