xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision 45f43e6e5f88874a7573ff096d1e5c2855bd16c7)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.frontend
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import utility._
24import xiangshan._
25import xiangshan.frontend.icache._
26import xiangshan.backend.CtrlToFtqIO
27import xiangshan.backend.decode.ImmUnion
28import utility.ChiselDB
29
30class FtqDebugBundle extends Bundle {
31  val pc = UInt(39.W)
32  val target = UInt(39.W)
33  val isBr = Bool()
34  val isJmp = Bool()
35  val isCall = Bool()
36  val isRet = Bool()
37  val misPred = Bool()
38  val isTaken = Bool()
39  val predStage = UInt(2.W)
40}
41
42class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr](
43  p => p(XSCoreParamsKey).FtqSize
44){
45}
46
47object FtqPtr {
48  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
49    val ptr = Wire(new FtqPtr)
50    ptr.flag := f
51    ptr.value := v
52    ptr
53  }
54  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
55    apply(!ptr.flag, ptr.value)
56  }
57}
58
59class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
60
61  val io = IO(new Bundle() {
62    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
63    val ren = Input(Vec(numRead, Bool()))
64    val rdata = Output(Vec(numRead, gen))
65    val waddr = Input(UInt(log2Up(FtqSize).W))
66    val wen = Input(Bool())
67    val wdata = Input(gen)
68  })
69
70  for(i <- 0 until numRead){
71    val sram = Module(new SRAMTemplate(gen, FtqSize))
72    sram.io.r.req.valid := io.ren(i)
73    sram.io.r.req.bits.setIdx := io.raddr(i)
74    io.rdata(i) := sram.io.r.resp.data(0)
75    sram.io.w.req.valid := io.wen
76    sram.io.w.req.bits.setIdx := io.waddr
77    sram.io.w.req.bits.data := VecInit(io.wdata)
78  }
79
80}
81
82class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
83  val startAddr = UInt(VAddrBits.W)
84  val nextLineAddr = UInt(VAddrBits.W)
85  val isNextMask = Vec(PredictWidth, Bool())
86  val fallThruError = Bool()
87  // val carry = Bool()
88  def getPc(offset: UInt) = {
89    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
90    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits)
91    Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)),
92        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
93  }
94  def fromBranchPrediction(resp: BranchPredictionBundle) = {
95    def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1)
96    this.startAddr := resp.pc(3)
97    this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs
98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
99      (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool
100    ))
101    this.fallThruError := resp.fallThruError(3)
102    this
103  }
104  override def toPrintable: Printable = {
105    p"startAddr:${Hexadecimal(startAddr)}"
106  }
107}
108
109class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
110  val brMask = Vec(PredictWidth, Bool())
111  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
112  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
113  val jalTarget = UInt(VAddrBits.W)
114  val rvcMask = Vec(PredictWidth, Bool())
115  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
116  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
117  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
118  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
119
120  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
121    val pds = pdWb.pd
122    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
123    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
124    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
125                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
126    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
127    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
128    this.jalTarget := pdWb.jalTarget
129  }
130
131  def toPd(offset: UInt) = {
132    require(offset.getWidth == log2Ceil(PredictWidth))
133    val pd = Wire(new PreDecodeInfo)
134    pd.valid := true.B
135    pd.isRVC := rvcMask(offset)
136    val isBr = brMask(offset)
137    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
138    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
139    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
140    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
141    pd
142  }
143}
144
145class PrefetchPtrDB(implicit p: Parameters) extends Bundle {
146  val fromFtqPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
147  val fromIfuPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
148}
149
150class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo {
151  val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None
152}
153
154class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
155  val meta = UInt(MaxMetaLength.W)
156}
157
158class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
159  val target = UInt(VAddrBits.W)
160  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
161}
162
163
164class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
165  val ptr = Output(new FtqPtr)
166  val offset = Output(UInt(log2Ceil(PredictWidth).W))
167  val data = Input(gen)
168  def apply(ptr: FtqPtr, offset: UInt) = {
169    this.ptr := ptr
170    this.offset := offset
171    this.data
172  }
173}
174
175
176class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
177  val redirect = Valid(new BranchPredictionRedirect)
178  val update = Valid(new BranchPredictionUpdate)
179  val enq_ptr = Output(new FtqPtr)
180}
181
182class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
183  val req = Decoupled(new FetchRequestBundle)
184  val redirect = Valid(new BranchPredictionRedirect)
185  val topdown_redirect = Valid(new BranchPredictionRedirect)
186  val flushFromBpu = new Bundle {
187    // when ifu pipeline is not stalled,
188    // a packet from bpu s3 can reach f1 at most
189    val s2 = Valid(new FtqPtr)
190    val s3 = Valid(new FtqPtr)
191    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
192      src.valid && !isAfter(src.bits, idx_to_flush)
193    }
194    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
195    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
196  }
197}
198
199class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
200  //NOTE: req.bits must be prepare in T cycle
201  // while req.valid is set true in T + 1 cycle
202  val req = Decoupled(new FtqToICacheRequestBundle)
203}
204
205trait HasBackendRedirectInfo extends HasXSParameter {
206  def numRedirectPcRead = exuParameters.JmpCnt + exuParameters.AluCnt + 1
207  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
208}
209
210class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
211  // write to backend pc mem
212  val pc_mem_wen = Output(Bool())
213  val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W))
214  val pc_mem_wdata = Output(new Ftq_RF_Components)
215  // newest target
216  val newest_entry_target = Output(UInt(VAddrBits.W))
217  val newest_entry_ptr = Output(new FtqPtr)
218}
219
220
221class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
222  val io = IO(new Bundle {
223    val start_addr = Input(UInt(VAddrBits.W))
224    val old_entry = Input(new FTBEntry)
225    val pd = Input(new Ftq_pd_Entry)
226    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
227    val target = Input(UInt(VAddrBits.W))
228    val hit = Input(Bool())
229    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
230
231    val new_entry = Output(new FTBEntry)
232    val new_br_insert_pos = Output(Vec(numBr, Bool()))
233    val taken_mask = Output(Vec(numBr, Bool()))
234    val jmp_taken = Output(Bool())
235    val mispred_mask = Output(Vec(numBr+1, Bool()))
236
237    // for perf counters
238    val is_init_entry = Output(Bool())
239    val is_old_entry = Output(Bool())
240    val is_new_br = Output(Bool())
241    val is_jalr_target_modified = Output(Bool())
242    val is_always_taken_modified = Output(Bool())
243    val is_br_full = Output(Bool())
244  })
245
246  // no mispredictions detected at predecode
247  val hit = io.hit
248  val pd = io.pd
249
250  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
251
252
253  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
254  val entry_has_jmp = pd.jmpInfo.valid
255  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
256  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
257  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
258  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
259  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
260  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
261
262  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
263  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
264
265  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
266  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
267  // if not hit, establish a new entry
268  init_entry.valid := true.B
269  // tag is left for ftb to assign
270
271  // case br
272  val init_br_slot = init_entry.getSlotForBr(0)
273  when (cfi_is_br) {
274    init_br_slot.valid := true.B
275    init_br_slot.offset := io.cfiIndex.bits
276    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
277    init_entry.always_taken(0) := true.B // set to always taken on init
278  }
279
280  // case jmp
281  when (entry_has_jmp) {
282    init_entry.tailSlot.offset := pd.jmpOffset
283    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
284    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
285  }
286
287  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
288  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
289  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
290  init_entry.isJalr := new_jmp_is_jalr
291  init_entry.isCall := new_jmp_is_call
292  init_entry.isRet  := new_jmp_is_ret
293  // that means fall thru points to the middle of an inst
294  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
295
296  // if hit, check whether a new cfi(only br is possible) is detected
297  val oe = io.old_entry
298  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
299  val br_recorded = br_recorded_vec.asUInt.orR
300  val is_new_br = cfi_is_br && !br_recorded
301  val new_br_offset = io.cfiIndex.bits
302  // vec(i) means new br will be inserted BEFORE old br(i)
303  val allBrSlotsVec = oe.allSlotsForBr
304  val new_br_insert_onehot = VecInit((0 until numBr).map{
305    i => i match {
306      case 0 =>
307        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
308      case idx =>
309        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
310        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
311    }
312  })
313
314  val old_entry_modified = WireInit(io.old_entry)
315  for (i <- 0 until numBr) {
316    val slot = old_entry_modified.allSlotsForBr(i)
317    when (new_br_insert_onehot(i)) {
318      slot.valid := true.B
319      slot.offset := new_br_offset
320      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
321      old_entry_modified.always_taken(i) := true.B
322    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
323      old_entry_modified.always_taken(i) := false.B
324      // all other fields remain unchanged
325    }.otherwise {
326      // case i == 0, remain unchanged
327      if (i != 0) {
328        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
329        when (!noNeedToMoveFromFormerSlot) {
330          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
331          old_entry_modified.always_taken(i) := oe.always_taken(i)
332        }
333      }
334    }
335  }
336
337  // two circumstances:
338  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
339  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
340  //        the previous last br or the new br
341  val may_have_to_replace = oe.noEmptySlotForNewBr
342  val pft_need_to_change = is_new_br && may_have_to_replace
343  // it should either be the given last br or the new br
344  when (pft_need_to_change) {
345    val new_pft_offset =
346      Mux(!new_br_insert_onehot.asUInt.orR,
347        new_br_offset, oe.allSlotsForBr.last.offset)
348
349    // set jmp to invalid
350    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
351    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
352    old_entry_modified.last_may_be_rvi_call := false.B
353    old_entry_modified.isCall := false.B
354    old_entry_modified.isRet := false.B
355    old_entry_modified.isJalr := false.B
356  }
357
358  val old_entry_jmp_target_modified = WireInit(oe)
359  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
360  val old_tail_is_jmp = !oe.tailSlot.sharing
361  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
362  when (jalr_target_modified) {
363    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
364    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
365  }
366
367  val old_entry_always_taken = WireInit(oe)
368  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
369  for (i <- 0 until numBr) {
370    old_entry_always_taken.always_taken(i) :=
371      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
372    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
373  }
374  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
375
376
377
378  val derived_from_old_entry =
379    Mux(is_new_br, old_entry_modified,
380      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
381
382
383  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
384
385  io.new_br_insert_pos := new_br_insert_onehot
386  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
387    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
388  })
389  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
390  for (i <- 0 until numBr) {
391    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
392  }
393  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
394
395  // for perf counters
396  io.is_init_entry := !hit
397  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
398  io.is_new_br := hit && is_new_br
399  io.is_jalr_target_modified := hit && jalr_target_modified
400  io.is_always_taken_modified := hit && always_taken_modified
401  io.is_br_full := hit && is_new_br && may_have_to_replace
402}
403
404class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
405  val io = IO(new Bundle {
406    val ifuPtr_w       = Input(new FtqPtr)
407    val ifuPtrPlus1_w  = Input(new FtqPtr)
408    val ifuPtrPlus2_w  = Input(new FtqPtr)
409    val commPtr_w      = Input(new FtqPtr)
410    val commPtrPlus1_w = Input(new FtqPtr)
411    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
412    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
413    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
414    val commPtr_rdata      = Output(new Ftq_RF_Components)
415    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
416
417    val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W)))
418    val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components))
419
420    val wen = Input(Bool())
421    val waddr = Input(UInt(log2Ceil(FtqSize).W))
422    val wdata = Input(new Ftq_RF_Components)
423  })
424
425  val num_pc_read = numOtherReads + 5
426  val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize,
427    num_pc_read, 1, "FtqPC"))
428  mem.io.wen(0)   := io.wen
429  mem.io.waddr(0) := io.waddr
430  mem.io.wdata(0) := io.wdata
431
432  // read one cycle ahead for ftq local reads
433  val raddr_vec = VecInit(io.other_raddrs ++
434    Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value))
435
436  mem.io.raddr := raddr_vec
437
438  io.other_rdatas       := mem.io.rdata.dropRight(5)
439  io.ifuPtr_rdata       := mem.io.rdata.dropRight(4).last
440  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(3).last
441  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(2).last
442  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
443  io.commPtr_rdata      := mem.io.rdata.last
444}
445
446class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
447  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
448  with HasICacheParameters{
449  val io = IO(new Bundle {
450    val fromBpu = Flipped(new BpuToFtqIO)
451    val fromIfu = Flipped(new IfuToFtqIO)
452    val fromBackend = Flipped(new CtrlToFtqIO)
453
454    val toBpu = new FtqToBpuIO
455    val toIfu = new FtqToIfuIO
456    val toICache = new FtqToICacheIO
457    val toBackend = new FtqToCtrlIO
458
459    val toPrefetch = new FtqPrefechBundle
460
461    val bpuInfo = new Bundle {
462      val bpRight = Output(UInt(XLEN.W))
463      val bpWrong = Output(UInt(XLEN.W))
464    }
465
466    val mmioCommitRead = Flipped(new mmioCommitRead)
467
468    // for perf
469    val ControlBTBMissBubble = Output(Bool())
470    val TAGEMissBubble = Output(Bool())
471    val SCMissBubble = Output(Bool())
472    val ITTAGEMissBubble = Output(Bool())
473    val RASMissBubble = Output(Bool())
474  })
475  io.bpuInfo := DontCare
476
477  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
478  // only driven by clock, not valid-ready
479  topdown_stage := io.fromBpu.resp.bits.topdown_info
480  io.toIfu.req.bits.topdown_info := topdown_stage
481
482  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
483
484
485  // io.fromBackend.ftqIdxAhead: jmp + alu(aluCnt) + ldReplay + exception
486  val aluAheadStart = 1
487  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i + aluAheadStart))) // only alu
488  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum, 1)
489
490  val aheadValid   = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid
491  val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
492  val backendRedirect = Wire(Valid(new BranchPredictionRedirect))
493  val backendRedirectReg = RegNext(backendRedirect)
494  backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid)
495  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
496  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
497
498  val stage2Flush = backendRedirect.valid
499  val backendFlush = stage2Flush || RegNext(stage2Flush)
500  val ifuFlush = Wire(Bool())
501
502  val flush = stage2Flush || RegNext(stage2Flush)
503
504  val allowBpuIn, allowToIfu = WireInit(false.B)
505  val flushToIfu = !allowToIfu
506  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
507  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
508
509  def copyNum = 5
510  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
511  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
512  val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U))
513  val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
514  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
515  val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
516  require(FtqSize >= 4)
517  val ifuPtr_write       = WireInit(ifuPtr)
518  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
519  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
520  val ifuWbPtr_write     = WireInit(ifuWbPtr)
521  val commPtr_write      = WireInit(commPtr)
522  val commPtrPlus1_write = WireInit(commPtrPlus1)
523  ifuPtr       := ifuPtr_write
524  ifuPtrPlus1  := ifuPtrPlus1_write
525  ifuPtrPlus2  := ifuPtrPlus2_write
526  ifuWbPtr     := ifuWbPtr_write
527  commPtr      := commPtr_write
528  commPtrPlus1 := commPtrPlus1_write
529  copied_ifu_ptr.map{ptr =>
530    ptr := ifuPtr_write
531    dontTouch(ptr)
532  }
533  val validEntries = distanceBetween(bpuPtr, commPtr)
534  val canCommit = Wire(Bool())
535
536  // **********************************************************************
537  // **************************** enq from bpu ****************************
538  // **********************************************************************
539  val new_entry_ready = validEntries < FtqSize.U || canCommit
540  io.fromBpu.resp.ready := new_entry_ready
541
542  val bpu_s2_resp = io.fromBpu.resp.bits.s2
543  val bpu_s3_resp = io.fromBpu.resp.bits.s3
544  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
545  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
546
547  io.toBpu.enq_ptr := bpuPtr
548  val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
549  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
550
551  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
552  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq
553  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
554  val bpu_in_resp_idx = bpu_in_resp_ptr.value
555
556  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
557  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
558  // resp from uBTB
559  ftq_pc_mem.io.wen := bpu_in_fire
560  ftq_pc_mem.io.waddr := bpu_in_resp_idx
561  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
562
563  //                                                            ifuRedirect + backendRedirect + commit
564  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1))
565  // these info is intended to enq at the last stage of bpu
566  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
567  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
568  ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info
569  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
570  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
571
572  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
573  // these info is intended to enq at the last stage of bpu
574  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
575  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
576  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta
577  //                                                            ifuRedirect + backendRedirect + commit
578  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1))
579  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3)
580  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
581  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
582
583
584  // multi-write
585  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
586  val newest_entry_target = Reg(UInt(VAddrBits.W))
587  val newest_entry_ptr = Reg(new FtqPtr)
588  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
589  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
590  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
591  val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
592
593  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
594  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
595    VecInit(Seq.fill(PredictWidth)(c_invalid))
596  }))
597
598  val f_to_send :: f_sent :: Nil = Enum(2)
599  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
600
601  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
602  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
603
604  // modify registers one cycle later to cut critical path
605  val last_cycle_bpu_in = RegNext(bpu_in_fire)
606  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
607  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
608  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3))
609  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3))
610  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
611
612  def extra_copyNum_for_commitStateQueue = 2
613  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
614  val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr)))
615
616  when (last_cycle_bpu_in) {
617    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
618    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
619    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
620
621    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
622    newest_entry_target := last_cycle_bpu_target
623    newest_entry_ptr := last_cycle_bpu_in_ptr
624  }
625
626  // reduce fanout by delay write for a cycle
627  when (RegNext(last_cycle_bpu_in)) {
628    mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
629  }
630
631  // record s1 pred cycles
632  pred_s1_cycle.map(vec => {
633    when (bpu_in_fire && (bpu_in_stage === BP_S1)) {
634      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
635    }
636  })
637
638  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
639  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
640  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
641    case ((in, ptr), i) =>
642      when (in) {
643        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
644        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
645        for (j <- 0 until perSetEntries) {
646          when (ptr.value === (i*perSetEntries+j).U) {
647            commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid))
648          }
649        }
650      }
651  }
652
653  // num cycle is fixed
654  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
655  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
656
657
658  bpuPtr := bpuPtr + enq_fire
659  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
660  when (io.toIfu.req.fire && allowToIfu) {
661    ifuPtr_write := ifuPtrPlus1
662    ifuPtrPlus1_write := ifuPtrPlus2
663    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
664  }
665
666  // only use ftb result to assign hit status
667  when (bpu_s2_resp.valid(3)) {
668    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
669  }
670
671
672  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
673  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
674  when (bpu_s2_redirect) {
675    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
676    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
677    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
678    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
679      ifuPtr_write := bpu_s2_resp.ftq_idx
680      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
681      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
682    }
683  }
684
685  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
686  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
687  when (bpu_s3_redirect) {
688    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
689    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
690    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
691    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
692      ifuPtr_write := bpu_s3_resp.ftq_idx
693      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
694      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
695    }
696  }
697
698  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
699  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
700
701  (0 until copyNum).map{i =>
702    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
703  }
704
705  // ****************************************************************
706  // **************************** to ifu ****************************
707  // ****************************************************************
708  // 0  for ifu, and 1-4 for ICache
709  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
710  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
711  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
712  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
713  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
714
715  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
716  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
717
718  // read pc and target
719  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
720  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
721  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
722  ftq_pc_mem.io.commPtr_w      := commPtr_write
723  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
724
725
726  io.toIfu.req.bits.ftqIdx := ifuPtr
727
728  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
729  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
730  val toIfuPcBundle = Wire(new Ftq_RF_Components)
731  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
732  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
733  val entry_next_addr  = Wire(UInt(VAddrBits.W))
734
735  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
736  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
737  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
738
739  val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1))))
740  val copied_ifu_ptr_to_send   = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr)))
741
742  for(i <- 0 until copyNum){
743    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
744      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
745      toICacheEntryToSend(i)   := true.B
746    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
747      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
748      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
749    }.otherwise{
750      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
751      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
752    }
753  }
754
755  // TODO: reconsider target address bypass logic
756  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
757    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
758    entry_is_to_send := true.B
759    entry_next_addr := last_cycle_bpu_target
760    entry_ftq_offset := last_cycle_cfiIndex
761    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
762  }.elsewhen (last_cycle_to_ifu_fire) {
763    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
764    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
765                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
766    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
767                          bpu_in_bypass_buf_for_ifu.startAddr,
768                          Mux(ifuPtr === newest_entry_ptr,
769                            newest_entry_target,
770                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
771  }.otherwise {
772    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
773    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
774                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
775    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
776                          bpu_in_bypass_buf_for_ifu.startAddr,
777                          Mux(ifuPtr === newest_entry_ptr,
778                            newest_entry_target,
779                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
780  }
781
782  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
783  io.toIfu.req.bits.nextStartAddr := entry_next_addr
784  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
785  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
786
787  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
788  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
789  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
790  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
791  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
792  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
793  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
794  // }
795
796  // TODO: remove this
797  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
798          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
799
800  // when fall through is smaller in value than start address, there must be a false hit
801  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
802    when (io.toIfu.req.fire &&
803      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
804      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
805    ) {
806      entry_hit_status(ifuPtr.value) := h_false_hit
807      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
808    }
809    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
810  }
811
812  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
813    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
814
815  val ifu_req_should_be_flushed =
816    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
817    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
818
819    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
820      entry_fetch_status(ifuPtr.value) := f_sent
821    }
822
823  // *********************************************************************
824  // **************************** wb from ifu ****************************
825  // *********************************************************************
826  val pdWb = io.fromIfu.pdWb
827  val pds = pdWb.bits.pd
828  val ifu_wb_valid = pdWb.valid
829  val ifu_wb_idx = pdWb.bits.ftqIdx.value
830  // read ports:                                                         commit update
831  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
832  ftq_pd_mem.io.wen(0) := ifu_wb_valid
833  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
834  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
835
836  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
837  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
838  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
839  val pd_reg       = RegEnable(pds,             pdWb.valid)
840  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
841  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
842
843  when (ifu_wb_valid) {
844    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
845      case (v, inRange) => v && inRange
846    })
847    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
848      case (qe, v) => when (v) { qe := c_valid }
849    }
850  }
851
852  when (ifu_wb_valid) {
853    ifuWbPtr_write := ifuWbPtr + 1.U
854  }
855
856  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
857
858  ftb_entry_mem.io.raddr.head := ifu_wb_idx
859  val has_false_hit = WireInit(false.B)
860  when (RegNext(hit_pd_valid)) {
861    // check for false hit
862    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
863    val brSlots = pred_ftb_entry.brSlots
864    val tailSlot = pred_ftb_entry.tailSlot
865    // we check cfis that bpu predicted
866
867    // bpu predicted branches but denied by predecode
868    val br_false_hit =
869      brSlots.map{
870        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
871      }.reduce(_||_) ||
872      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
873        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
874
875    val jmpOffset = tailSlot.offset
876    val jmp_pd = pd_reg(jmpOffset)
877    val jal_false_hit = pred_ftb_entry.jmpValid &&
878      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
879       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
880       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
881       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
882      )
883
884    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
885    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
886
887    // assert(!has_false_hit)
888  }
889
890  when (has_false_hit) {
891    entry_hit_status(wb_idx_reg) := h_false_hit
892  }
893
894
895  // **********************************************************************
896  // ***************************** to backend *****************************
897  // **********************************************************************
898  // to backend pc mem / target
899  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
900  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
901  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
902
903  // *******************************************************************************
904  // **************************** redirect from backend ****************************
905  // *******************************************************************************
906
907  // redirect read cfiInfo, couples to redirectGen s2
908  val redirectReadStart = 1 // 0 for ifuRedirect
909  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
910  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry))
911  for (i <- redirectReadStart until FtqRedirectAheadNum) {
912    ftq_redirect_sram.io.ren(i + redirectReadStart)   := ftqIdxAhead(i).valid
913    ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value
914    ftb_entry_mem.io.raddr(i + redirectReadStart)     := ftqIdxAhead(i).bits.value
915  }
916  ftq_redirect_sram.io.ren(redirectReadStart)   := Mux(aheadValid, ftqIdxAhead(0).valid,      backendRedirect.valid)
917  ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
918  ftb_entry_mem.io.raddr(redirectReadStart)     := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
919
920  for (i <- 0 until FtqRedirectAheadNum) {
921    ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart)
922    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart)
923  }
924  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart))
925  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
926  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
927
928
929  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart))
930  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
931
932  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
933  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
934  // FIXME: not portable
935  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
936  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
937    sc_disagree(0), sc_disagree(1))
938
939  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
940    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
941      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
942      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
943
944    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
945        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
946  }.otherwise {
947    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
948    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
949  }
950
951
952  // ***************************************************************************
953  // **************************** redirect from ifu ****************************
954  // ***************************************************************************
955  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
956  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
957  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
958  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
959  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
960  fromIfuRedirect.bits.BTBMissBubble := true.B
961  fromIfuRedirect.bits.debugIsMemVio := false.B
962  fromIfuRedirect.bits.debugIsCtrl := false.B
963
964  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
965  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
966  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
967  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
968  ifuRedirectCfiUpdate.target := pdWb.bits.target
969  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
970  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
971
972  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
973  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
974  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
975
976  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
977  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
978
979  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
980
981  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
982  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
983  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
984    toBpuCfi.target := toBpuCfi.topAddr
985  }
986
987  when (ifuRedirectReg.valid) {
988    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
989  } .elsewhen(RegNext(pdWb.valid)) {
990    // if pdWb and no redirect, set to false
991    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
992  }
993
994  // *********************************************************************
995  // **************************** wb from exu ****************************
996  // *********************************************************************
997
998  backendRedirect.valid := io.fromBackend.redirect.valid
999  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1000  backendRedirect.bits.BTBMissBubble := false.B
1001
1002
1003  def extractRedirectInfo(wb: Valid[Redirect]) = {
1004    val ftqPtr = wb.bits.ftqIdx
1005    val ftqOffset = wb.bits.ftqOffset
1006    val taken = wb.bits.cfiUpdate.taken
1007    val mispred = wb.bits.cfiUpdate.isMisPred
1008    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
1009  }
1010
1011  // fix mispredict entry
1012  val lastIsMispredict = RegNext(
1013    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
1014  )
1015
1016  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
1017    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
1018    val r_idx = r_ptr.value
1019    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
1020    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
1021    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
1022      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
1023    } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
1024      cfiIndex_vec(r_idx).valid :=false.B
1025    }
1026    when (cfiIndex_bits_wen) {
1027      cfiIndex_vec(r_idx).bits := r_offset
1028    }
1029    newest_entry_target := redirect.bits.cfiUpdate.target
1030    newest_entry_ptr := r_ptr
1031    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
1032    if (isBackend) {
1033      mispredict_vec(r_idx)(r_offset) := r_mispred
1034    }
1035  }
1036
1037  when(fromBackendRedirect.valid) {
1038    updateCfiInfo(fromBackendRedirect)
1039  }.elsewhen (ifuRedirectToBpu.valid) {
1040    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
1041  }
1042
1043  when (fromBackendRedirect.valid) {
1044    when (fromBackendRedirect.bits.ControlRedirectBubble) {
1045      when (fromBackendRedirect.bits.ControlBTBMissBubble) {
1046        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1047        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1048      } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) {
1049        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1050        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1051      } .elsewhen (fromBackendRedirect.bits.SCMissBubble) {
1052        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
1053        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1054      } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) {
1055        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1056        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1057      } .elsewhen (fromBackendRedirect.bits.RASMissBubble) {
1058        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
1059        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1060      }
1061
1062
1063    } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) {
1064      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1065      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1066    } .otherwise {
1067      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1068      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1069    }
1070  } .elsewhen (ifuRedirectReg.valid) {
1071    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1072    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1073  }
1074
1075  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1076  io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble
1077  io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble
1078  io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble
1079  io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble
1080
1081  // ***********************************************************************************
1082  // **************************** flush ptr and state queue ****************************
1083  // ***********************************************************************************
1084
1085  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
1086
1087  // when redirect, we should reset ptrs and status queues
1088  when(redirectVec.map(r => r.valid).reduce(_||_)){
1089    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1090    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1091    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1092    val next = idx + 1.U
1093    bpuPtr := next
1094    copied_bpu_ptr.map(_ := next)
1095    ifuPtr_write := next
1096    ifuWbPtr_write := next
1097    ifuPtrPlus1_write := idx + 2.U
1098    ifuPtrPlus2_write := idx + 3.U
1099
1100  }
1101  when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){
1102    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1103    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1104    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1105    when (RegNext(notIfu)) {
1106      commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) =>
1107        when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){
1108          s := c_invalid
1109        }
1110      })
1111    }
1112  }
1113
1114
1115  // only the valid bit is actually needed
1116  io.toIfu.redirect.bits    := backendRedirect.bits
1117  io.toIfu.redirect.valid   := stage2Flush
1118  io.toIfu.topdown_redirect := fromBackendRedirect
1119
1120  // commit
1121  for (c <- io.fromBackend.rob_commits) {
1122    when(c.valid) {
1123      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
1124      // TODO: remove this
1125      // For instruction fusions, we also update the next instruction
1126      when (c.bits.commitType === 4.U) {
1127        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
1128      }.elsewhen(c.bits.commitType === 5.U) {
1129        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
1130      }.elsewhen(c.bits.commitType === 6.U) {
1131        val index = (c.bits.ftqIdx + 1.U).value
1132        commitStateQueue(index)(0) := c_commited
1133      }.elsewhen(c.bits.commitType === 7.U) {
1134        val index = (c.bits.ftqIdx + 1.U).value
1135        commitStateQueue(index)(1) := c_commited
1136      }
1137    }
1138  }
1139
1140  // ****************************************************************
1141  // **************************** to bpu ****************************
1142  // ****************************************************************
1143
1144  io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1145  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W)))
1146  val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1147  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1148  XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1)
1149
1150  XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay")
1151
1152  val may_have_stall_from_bpu = Wire(Bool())
1153  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
1154  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
1155  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1156    Cat(commitStateQueue(commPtr.value).map(s => {
1157      s === c_invalid || s === c_commited
1158    })).andR
1159
1160  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
1161  val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr)  ||  mmioReadPtr ===   ifuPtr) &&
1162                       Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR
1163  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
1164
1165  // commit reads
1166  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1167  val commit_target =
1168    Mux(RegNext(commPtr === newest_entry_ptr),
1169      RegNext(newest_entry_target),
1170      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1171  ftq_pd_mem.io.raddr.last := commPtr.value
1172  val commit_pd = ftq_pd_mem.io.rdata.last
1173  ftq_redirect_sram.io.ren.last := canCommit
1174  ftq_redirect_sram.io.raddr.last := commPtr.value
1175  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
1176  ftq_meta_1r_sram.io.ren(0) := canCommit
1177  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1178  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
1179  ftb_entry_mem.io.raddr.last := commPtr.value
1180  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
1181
1182  // need one cycle to read mem and srams
1183  val do_commit_ptr = RegNext(commPtr)
1184  val do_commit = RegNext(canCommit, init=false.B)
1185  when (canCommit) {
1186    commPtr_write := commPtrPlus1
1187    commPtrPlus1_write := commPtrPlus1 + 1.U
1188  }
1189  val commit_state = RegNext(commitStateQueue(commPtr.value))
1190  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1191  val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value))
1192  //
1193  //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1194  //  can_commit_cfi.valid := false.B
1195  //}
1196  val commit_cfi = RegNext(can_commit_cfi)
1197  val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid
1198
1199  val commit_mispredict  : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
1200    case (mis, state) => mis && state === c_commited
1201  })
1202  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth]
1203  val can_commit_hit                 = entry_hit_status(commPtr.value)
1204  val commit_hit                     = RegNext(can_commit_hit)
1205  val diff_commit_target             = RegNext(update_target(commPtr.value)) // TODO: remove this
1206  val commit_stage                   = RegNext(pred_stage(commPtr.value))
1207  val commit_valid                   = commit_hit === h_hit || commit_cfi.valid // hit or taken
1208
1209  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1210  switch (bpu_ftb_update_stall) {
1211    is (0.U) {
1212      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1213        bpu_ftb_update_stall := 2.U // 2-cycle stall
1214      }
1215    }
1216    is (2.U) {
1217      bpu_ftb_update_stall := 1.U
1218    }
1219    is (1.U) {
1220      bpu_ftb_update_stall := 0.U
1221    }
1222    is (3.U) {
1223      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1224    }
1225  }
1226
1227  // TODO: remove this
1228  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1229
1230  // update latency stats
1231  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1232  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1233
1234  io.toBpu.update := DontCare
1235  io.toBpu.update.valid := commit_valid && do_commit
1236  val update = io.toBpu.update.bits
1237  update.false_hit   := commit_hit === h_false_hit
1238  update.pc          := commit_pc_bundle.startAddr
1239  update.meta        := commit_meta.meta
1240  update.cfi_idx     := commit_cfi
1241  update.full_target := commit_target
1242  update.from_stage  := commit_stage
1243  update.spec_info   := commit_spec_meta
1244  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
1245
1246  val commit_real_hit = commit_hit === h_hit
1247  val update_ftb_entry = update.ftb_entry
1248
1249  val ftbEntryGen = Module(new FTBEntryGen).io
1250  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1251  ftbEntryGen.old_entry      := commit_ftb_entry
1252  ftbEntryGen.pd             := commit_pd
1253  ftbEntryGen.cfiIndex       := commit_cfi
1254  ftbEntryGen.target         := commit_target
1255  ftbEntryGen.hit            := commit_real_hit
1256  ftbEntryGen.mispredict_vec := commit_mispredict
1257
1258  update_ftb_entry         := ftbEntryGen.new_entry
1259  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1260  update.mispred_mask      := ftbEntryGen.mispred_mask
1261  update.old_entry         := ftbEntryGen.is_old_entry
1262  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1263  update.br_taken_mask     := ftbEntryGen.taken_mask
1264  update.br_committed      := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1265    case (valid, offset) => valid && commit_instCommited(offset)
1266  }
1267  update.jmp_taken         := ftbEntryGen.jmp_taken
1268
1269  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1270  // update.full_pred.jalr_target := commit_target
1271  // update.full_pred.hit := true.B
1272  // when (update.full_pred.is_jalr) {
1273  //   update.full_pred.targets.last := commit_target
1274  // }
1275
1276  // ****************************************************************
1277  // *********************** to prefetch ****************************
1278  // ****************************************************************
1279  /**
1280    ******************************************************************************
1281    * prefetchPtr control
1282    * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2
1283    * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange]
1284    * - 3. flush prefetchPtr when receive redirect from ifu or backend
1285    ******************************************************************************
1286    */
1287  val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1288  val nextPrefetchPtr = WireInit(prefetchPtr)
1289
1290  prefetchPtr := nextPrefetchPtr
1291
1292  // TODO: consider req which cross cacheline
1293  when(io.toPrefetch.req.fire) {
1294    when(prefetchPtr < bpuPtr - 2.U) {
1295      nextPrefetchPtr := prefetchPtr + 1.U
1296    }
1297  }
1298
1299  when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) {
1300    nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U
1301  }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) {
1302    nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U
1303  }
1304
1305  when(redirectVec.map(r => r.valid).reduce(_||_)){
1306    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1307    val next = r.ftqIdx + minRangeFromIFUptr.U
1308    nextPrefetchPtr := next
1309  }
1310
1311  // data from ftq_pc_mem has 1 cycle delay
1312  io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send)
1313  ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value
1314  io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr)
1315
1316  // record position relationship between ifuPtr, pfPtr and bpuPtr
1317  val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString))
1318  val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB)
1319  val prefetchPtrDumpData = Wire(new PrefetchPtrDB)
1320  prefetchPtrDumpData.fromFtqPtr  := distanceBetween(bpuPtr, prefetchPtr)
1321  prefetchPtrDumpData.fromIfuPtr  := distanceBetween(prefetchPtr, ifuPtr)
1322
1323  prefetchPtrTable.log(
1324    data = prefetchPtrDumpData,
1325    en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire,
1326    site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1327    clock = clock,
1328    reset = reset
1329  )
1330
1331
1332  // ******************************************************************************
1333  // **************************** commit perf counters ****************************
1334  // ******************************************************************************
1335
1336  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1337  val commit_mispred_mask = commit_mispredict.asUInt
1338  val commit_not_mispred_mask = ~commit_mispred_mask
1339
1340  val commit_br_mask = commit_pd.brMask.asUInt
1341  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1342  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1343
1344  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1345
1346  val mbpRights = mbpInstrs & commit_not_mispred_mask
1347  val mbpWrongs = mbpInstrs & commit_mispred_mask
1348
1349  io.bpuInfo.bpRight := PopCount(mbpRights)
1350  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1351
1352  val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString))
1353  val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle)
1354  // Cfi Info
1355  for (i <- 0 until PredictWidth) {
1356    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1357    val v = commit_state(i) === c_commited
1358    val isBr = commit_pd.brMask(i)
1359    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1360    val isCfi = isBr || isJmp
1361    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1362    val misPred = commit_mispredict(i)
1363    // val ghist = commit_spec_meta.ghist.predHist
1364    val histPtr = commit_spec_meta.histPtr
1365    val predCycle = commit_meta.meta(63, 0)
1366    val target = commit_target
1367
1368    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1369    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1370    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1371    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1372    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1373    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1374    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1375
1376    val logbundle = Wire(new FtqDebugBundle)
1377    logbundle.pc := pc
1378    logbundle.target := target
1379    logbundle.isBr := isBr
1380    logbundle.isJmp := isJmp
1381    logbundle.isCall := isJmp && commit_pd.hasCall
1382    logbundle.isRet := isJmp && commit_pd.hasRet
1383    logbundle.misPred := misPred
1384    logbundle.isTaken := isTaken
1385    logbundle.predStage := commit_stage
1386
1387    ftqBranchTraceDB.log(
1388      data = logbundle /* hardware of type T */,
1389      en = isWriteFTQTable.orR && v && do_commit && isCfi,
1390      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1391      clock = clock,
1392      reset = reset
1393    )
1394  }
1395
1396  val enq = io.fromBpu.resp
1397  val perf_redirect = backendRedirect
1398
1399  XSPerfAccumulate("entry", validEntries)
1400  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1401  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1402  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1403  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1404
1405  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1406
1407  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1408  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1409  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1410  XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready)
1411
1412  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_))
1413  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
1414  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
1415
1416  val from_bpu = io.fromBpu.resp.bits
1417  val to_ifu = io.toIfu.req.bits
1418
1419
1420  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1)
1421
1422
1423
1424
1425  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1426  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1427  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1428  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1429
1430
1431  val mbpBRights = mbpRights & commit_br_mask
1432  val mbpJRights = mbpRights & commit_jal_mask
1433  val mbpIRights = mbpRights & commit_jalr_mask
1434  val mbpCRights = mbpRights & commit_call_mask
1435  val mbpRRights = mbpRights & commit_ret_mask
1436
1437  val mbpBWrongs = mbpWrongs & commit_br_mask
1438  val mbpJWrongs = mbpWrongs & commit_jal_mask
1439  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1440  val mbpCWrongs = mbpWrongs & commit_call_mask
1441  val mbpRWrongs = mbpWrongs & commit_ret_mask
1442
1443  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1444
1445  def pred_stage_map(src: UInt, name: String) = {
1446    (0 until numBpStages).map(i =>
1447      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1448    ).foldLeft(Map[String, UInt]())(_+_)
1449  }
1450
1451  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1452  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1453  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1454  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1455  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1456  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1457
1458  val update_valid = io.toBpu.update.valid
1459  def u(cond: Bool) = update_valid && cond
1460  val ftb_false_hit = u(update.false_hit)
1461  // assert(!ftb_false_hit)
1462  val ftb_hit = u(commit_hit === h_hit)
1463
1464  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1465  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1466  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1467  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1468
1469  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1470
1471  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1472  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1473  val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value))
1474  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1475  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1476  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1477
1478  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1479  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1480  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1)
1481  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1)
1482  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1483  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1)
1484
1485  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1)
1486
1487  val perfCountsMap = Map(
1488    "BpInstr" -> PopCount(mbpInstrs),
1489    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1490    "BpRight"  -> PopCount(mbpRights),
1491    "BpWrong"  -> PopCount(mbpWrongs),
1492    "BpBRight" -> PopCount(mbpBRights),
1493    "BpBWrong" -> PopCount(mbpBWrongs),
1494    "BpJRight" -> PopCount(mbpJRights),
1495    "BpJWrong" -> PopCount(mbpJWrongs),
1496    "BpIRight" -> PopCount(mbpIRights),
1497    "BpIWrong" -> PopCount(mbpIWrongs),
1498    "BpCRight" -> PopCount(mbpCRights),
1499    "BpCWrong" -> PopCount(mbpCWrongs),
1500    "BpRRight" -> PopCount(mbpRRights),
1501    "BpRWrong" -> PopCount(mbpRWrongs),
1502
1503    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1504    "ftb_hit"                      -> PopCount(ftb_hit),
1505    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1506    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1507    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1508    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1509    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1510    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1511    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1512    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1513    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1514    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1515  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1516       correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1517
1518  for((key, value) <- perfCountsMap) {
1519    XSPerfAccumulate(key, value)
1520  }
1521
1522  // --------------------------- Debug --------------------------------
1523  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1524  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1525  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1526  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1527  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1528    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1529  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1530
1531  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1532  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1533  //       case (((valid, pd), ans), taken) =>
1534  //       Mux(valid && pd.isBr,
1535  //         isWrong ^ Mux(ans.hit.asBool,
1536  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1537  //           !taken),
1538  //         !taken),
1539  //       false.B)
1540  //     }
1541  //   }
1542
1543  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1544  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1545  //       case (((valid, pd), ans), taken) =>
1546  //       Mux(valid && pd.isBr,
1547  //         isWrong ^ Mux(ans.hit.asBool,
1548  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1549  //           !taken),
1550  //         !taken),
1551  //       false.B)
1552  //     }
1553  //   }
1554
1555  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1556  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1557  //       case (((valid, pd), ans), taken) =>
1558  //       Mux(valid && pd.isBr,
1559  //         isWrong ^ (ans.taken.asBool === taken),
1560  //       false.B)
1561  //     }
1562  //   }
1563
1564  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1565  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1566  //       case (((valid, pd), ans), taken) =>
1567  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1568  //         isWrong ^ (!taken),
1569  //           false.B)
1570  //     }
1571  //   }
1572
1573  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1574  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1575  //       case (((valid, pd), ans), taken) =>
1576  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1577  //         isWrong ^ (ans.target === commitEntry.target),
1578  //           false.B)
1579  //     }
1580  //   }
1581
1582  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1583  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1584  //   // btb and ubtb pred jal and jalr as well
1585  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1586  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1587  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1588  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1589
1590  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1591  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1592
1593  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1594  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1595
1596  val perfEvents = Seq(
1597    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1598    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1599    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1600    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1601    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1602    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1603    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1604    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1605    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1606    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1607    ("BpRight                ", PopCount(mbpRights)                                                         ),
1608    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1609    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1610    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1611    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1612    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1613    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1614    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1615    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1616    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1617    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1618    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1619    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1620    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1621  )
1622  generatePerfEvent()
1623}