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