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