xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision f56177cb059557286ffcac168b69ce3d30cc609a)
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  def copyNum = 5
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  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
487  require(FtqSize >= 4)
488  val ifuPtr_write       = WireInit(ifuPtr)
489  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
490  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
491  val ifuWbPtr_write     = WireInit(ifuWbPtr)
492  val commPtr_write      = WireInit(commPtr)
493  val commPtrPlus1_write = WireInit(commPtrPlus1)
494  ifuPtr       := ifuPtr_write
495  ifuPtrPlus1  := ifuPtrPlus1_write
496  ifuPtrPlus2  := ifuPtrPlus2_write
497  ifuWbPtr     := ifuWbPtr_write
498  commPtr      := commPtr_write
499  commPtrPlus1 := commPtrPlus1_write
500  copied_ifu_ptr.map{ptr =>
501    ptr := ifuPtr_write
502    dontTouch(ptr)
503  }
504  val validEntries = distanceBetween(bpuPtr, commPtr)
505
506  // **********************************************************************
507  // **************************** enq from bpu ****************************
508  // **********************************************************************
509  val new_entry_ready = validEntries < FtqSize.U
510  io.fromBpu.resp.ready := new_entry_ready
511
512  val bpu_s2_resp = io.fromBpu.resp.bits.s2
513  val bpu_s3_resp = io.fromBpu.resp.bits.s3
514  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
515  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
516
517  io.toBpu.enq_ptr := bpuPtr
518  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
519  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
520
521  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
522  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx
523  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
524  val bpu_in_resp_idx = bpu_in_resp_ptr.value
525
526  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
527  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
528  // resp from uBTB
529  ftq_pc_mem.io.wen := bpu_in_fire
530  ftq_pc_mem.io.waddr := bpu_in_resp_idx
531  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
532
533  //                                                            ifuRedirect + backendRedirect + commit
534  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
535  // these info is intended to enq at the last stage of bpu
536  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
537  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
538  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
539  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
540  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
541
542  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
543  // these info is intended to enq at the last stage of bpu
544  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
545  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
546  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
547  //                                                            ifuRedirect + backendRedirect + commit
548  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
549  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
550  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
551  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
552
553
554  // multi-write
555  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
556  val newest_entry_target = Reg(UInt(VAddrBits.W))
557  val newest_entry_ptr = Reg(new FtqPtr)
558  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
559  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
560  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
561
562  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
563  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
564    VecInit(Seq.fill(PredictWidth)(c_invalid))
565  }))
566
567  val f_to_send :: f_sent :: Nil = Enum(2)
568  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
569
570  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
571  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
572
573  // modify registers one cycle later to cut critical path
574  val last_cycle_bpu_in = RegNext(bpu_in_fire)
575  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
576  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
577  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget)
578  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex)
579  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
580
581  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_fire)))
582
583  when (last_cycle_bpu_in) {
584    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
585    commitStateQueue(last_cycle_bpu_in_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
586    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
587    mispredict_vec(last_cycle_bpu_in_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
588    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
589
590    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
591    newest_entry_target := last_cycle_bpu_target
592    newest_entry_ptr := last_cycle_bpu_in_ptr
593  }
594
595  // num cycle is fixed
596  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
597  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
598
599
600  bpuPtr := bpuPtr + enq_fire
601  when (io.toIfu.req.fire && allowToIfu) {
602    ifuPtr_write := ifuPtrPlus1
603    ifuPtrPlus1_write := ifuPtrPlus2
604    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
605  }
606
607  // only use ftb result to assign hit status
608  when (bpu_s2_resp.valid) {
609    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit)
610  }
611
612
613  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
614  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
615  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
616    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
617    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
618    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
619      ifuPtr_write := bpu_s2_resp.ftq_idx
620      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
621      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
622    }
623  }
624
625  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
626  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
627  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
628    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
629    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
630    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
631      ifuPtr_write := bpu_s3_resp.ftq_idx
632      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
633      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
634    }
635  }
636
637  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
638
639  // ****************************************************************
640  // **************************** to ifu ****************************
641  // ****************************************************************
642  // 0  for ifu, and 1-4 for ICache
643  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, enable=bpu_in_fire)
644  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, enable=bpu_in_fire)))
645  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
646  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
647  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
648
649  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
650  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
651
652  // read pc and target
653  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
654  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
655  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
656  ftq_pc_mem.io.commPtr_w      := commPtr_write
657  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
658
659
660  io.toIfu.req.bits.ftqIdx := ifuPtr
661
662  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
663  val toIfuPcBundle = Wire(new Ftq_RF_Components)
664  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
665  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
666  val entry_next_addr  = Wire(UInt(VAddrBits.W))
667
668  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
669  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
670  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
671
672  for(i <- 0 until copyNum){
673    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
674      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
675    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
676      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
677    }.otherwise{
678      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
679    }
680  }
681
682  // TODO: reconsider target address bypass logic
683  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
684    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
685    entry_is_to_send := true.B
686    entry_next_addr := last_cycle_bpu_target
687    entry_ftq_offset := last_cycle_cfiIndex
688    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
689  }.elsewhen (last_cycle_to_ifu_fire) {
690    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
691    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
692                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
693    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
694                          bpu_in_bypass_buf_for_ifu.startAddr,
695                          Mux(ifuPtr === newest_entry_ptr,
696                            newest_entry_target,
697                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
698  }.otherwise {
699    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
700    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
701                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
702    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
703                          bpu_in_bypass_buf_for_ifu.startAddr,
704                          Mux(ifuPtr === newest_entry_ptr,
705                            newest_entry_target,
706                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
707  }
708
709  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
710  io.toIfu.req.bits.nextStartAddr := entry_next_addr
711  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
712  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
713
714  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
715  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
716  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
717  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
718  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
719  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
720  // }
721
722  // TODO: remove this
723  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
724          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
725
726  // when fall through is smaller in value than start address, there must be a false hit
727  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
728    when (io.toIfu.req.fire &&
729      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
730      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
731    ) {
732      entry_hit_status(ifuPtr.value) := h_false_hit
733      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
734    }
735    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
736  }
737
738  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
739    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
740
741  val ifu_req_should_be_flushed =
742    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
743    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
744
745    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
746      entry_fetch_status(ifuPtr.value) := f_sent
747    }
748
749  // *********************************************************************
750  // **************************** wb from ifu ****************************
751  // *********************************************************************
752  val pdWb = io.fromIfu.pdWb
753  val pds = pdWb.bits.pd
754  val ifu_wb_valid = pdWb.valid
755  val ifu_wb_idx = pdWb.bits.ftqIdx.value
756  // read ports:                                                         commit update
757  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
758  ftq_pd_mem.io.wen(0) := ifu_wb_valid
759  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
760  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
761
762  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
763  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
764  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
765  val pd_reg       = RegEnable(pds,             pdWb.valid)
766  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
767  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
768
769  when (ifu_wb_valid) {
770    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
771      case (v, inRange) => v && inRange
772    })
773    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
774      case (qe, v) => when (v) { qe := c_valid }
775    }
776  }
777
778  when (ifu_wb_valid) {
779    ifuWbPtr_write := ifuWbPtr + 1.U
780  }
781
782  ftb_entry_mem.io.raddr.head := ifu_wb_idx
783  val has_false_hit = WireInit(false.B)
784  when (RegNext(hit_pd_valid)) {
785    // check for false hit
786    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
787    val brSlots = pred_ftb_entry.brSlots
788    val tailSlot = pred_ftb_entry.tailSlot
789    // we check cfis that bpu predicted
790
791    // bpu predicted branches but denied by predecode
792    val br_false_hit =
793      brSlots.map{
794        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
795      }.reduce(_||_) ||
796      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
797        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
798
799    val jmpOffset = tailSlot.offset
800    val jmp_pd = pd_reg(jmpOffset)
801    val jal_false_hit = pred_ftb_entry.jmpValid &&
802      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
803       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
804       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
805       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
806      )
807
808    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
809    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
810
811    // assert(!has_false_hit)
812  }
813
814  when (has_false_hit) {
815    entry_hit_status(wb_idx_reg) := h_false_hit
816  }
817
818
819  // **********************************************************************
820  // ***************************** to backend *****************************
821  // **********************************************************************
822  // to backend pc mem / target
823  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
824  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
825  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
826
827  // *******************************************************************************
828  // **************************** redirect from backend ****************************
829  // *******************************************************************************
830
831  // redirect read cfiInfo, couples to redirectGen s2
832  ftq_redirect_sram.io.ren.init.last := backendRedirect.valid
833  ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
834
835  ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
836
837  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
838  val fromBackendRedirect = WireInit(backendRedirectReg)
839  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
840  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
841
842  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
843  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
844
845  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
846    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
847      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
848      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
849
850    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
851        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
852  }.otherwise {
853    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
854    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
855  }
856
857
858  // ***************************************************************************
859  // **************************** redirect from ifu ****************************
860  // ***************************************************************************
861  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
862  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
863  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
864  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
865  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
866
867  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
868  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
869  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
870  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
871  ifuRedirectCfiUpdate.target := pdWb.bits.target
872  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
873  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
874
875  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
876  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
877  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
878
879  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
880  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
881
882  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
883
884  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
885  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
886  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
887    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
888  }
889
890  // *********************************************************************
891  // **************************** wb from exu ****************************
892  // *********************************************************************
893
894  backendRedirect := io.fromBackend.redirect
895
896  def extractRedirectInfo(wb: Valid[Redirect]) = {
897    val ftqPtr = wb.bits.ftqIdx
898    val ftqOffset = wb.bits.ftqOffset
899    val taken = wb.bits.cfiUpdate.taken
900    val mispred = wb.bits.cfiUpdate.isMisPred
901    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
902  }
903
904  // fix mispredict entry
905  val lastIsMispredict = RegNext(
906    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
907  )
908
909  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
910    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
911    val r_idx = r_ptr.value
912    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
913    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
914    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
915      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
916    }
917    when (cfiIndex_bits_wen) {
918      cfiIndex_vec(r_idx).bits := r_offset
919    }
920    newest_entry_target := redirect.bits.cfiUpdate.target
921    newest_entry_ptr := r_ptr
922    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
923    if (isBackend) {
924      mispredict_vec(r_idx)(r_offset) := r_mispred
925    }
926  }
927
928  when(backendRedirectReg.valid) {
929    updateCfiInfo(backendRedirectReg)
930  }.elsewhen (ifuRedirectToBpu.valid) {
931    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
932  }
933
934  // ***********************************************************************************
935  // **************************** flush ptr and state queue ****************************
936  // ***********************************************************************************
937
938  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
939
940  // when redirect, we should reset ptrs and status queues
941  when(redirectVec.map(r => r.valid).reduce(_||_)){
942    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
943    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
944    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
945    val next = idx + 1.U
946    bpuPtr := next
947    ifuPtr_write := next
948    ifuWbPtr_write := next
949    ifuPtrPlus1_write := idx + 2.U
950    ifuPtrPlus2_write := idx + 3.U
951    when (notIfu) {
952      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
953        when(i.U > offset || i.U === offset && flushItSelf){
954          s := c_invalid
955        }
956      })
957    }
958  }
959
960  // only the valid bit is actually needed
961  io.toIfu.redirect.bits    := backendRedirect.bits
962  io.toIfu.redirect.valid   := stage2Flush
963
964  // commit
965  for (c <- io.fromBackend.rob_commits) {
966    when(c.valid) {
967      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
968      // TODO: remove this
969      // For instruction fusions, we also update the next instruction
970      when (c.bits.commitType === 4.U) {
971        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
972      }.elsewhen(c.bits.commitType === 5.U) {
973        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
974      }.elsewhen(c.bits.commitType === 6.U) {
975        val index = (c.bits.ftqIdx + 1.U).value
976        commitStateQueue(index)(0) := c_commited
977      }.elsewhen(c.bits.commitType === 7.U) {
978        val index = (c.bits.ftqIdx + 1.U).value
979        commitStateQueue(index)(1) := c_commited
980      }
981    }
982  }
983
984  // ****************************************************************
985  // **************************** to bpu ****************************
986  // ****************************************************************
987
988  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
989
990  val may_have_stall_from_bpu = Wire(Bool())
991  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
992  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
993  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
994    Cat(commitStateQueue(commPtr.value).map(s => {
995      s === c_invalid || s === c_commited
996    })).andR()
997
998  // commit reads
999  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1000  val commit_target =
1001    Mux(RegNext(commPtr === newest_entry_ptr),
1002      RegNext(newest_entry_target),
1003      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1004  ftq_pd_mem.io.raddr.last := commPtr.value
1005  val commit_pd = ftq_pd_mem.io.rdata.last
1006  ftq_redirect_sram.io.ren.last := canCommit
1007  ftq_redirect_sram.io.raddr.last := commPtr.value
1008  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
1009  ftq_meta_1r_sram.io.ren(0) := canCommit
1010  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1011  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
1012  ftb_entry_mem.io.raddr.last := commPtr.value
1013  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
1014
1015  // need one cycle to read mem and srams
1016  val do_commit_ptr = RegNext(commPtr)
1017  val do_commit = RegNext(canCommit, init=false.B)
1018  when (canCommit) {
1019    commPtr_write := commPtrPlus1
1020    commPtrPlus1_write := commPtrPlus1 + 1.U
1021  }
1022  val commit_state = RegNext(commitStateQueue(commPtr.value))
1023  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1024  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1025    can_commit_cfi.valid := false.B
1026  }
1027  val commit_cfi = RegNext(can_commit_cfi)
1028
1029  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
1030    case (mis, state) => mis && state === c_commited
1031  })
1032  val can_commit_hit = entry_hit_status(commPtr.value)
1033  val commit_hit = RegNext(can_commit_hit)
1034  val diff_commit_target = RegNext(update_target(commPtr.value)) // TODO: remove this
1035  val commit_stage = RegNext(pred_stage(commPtr.value))
1036  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
1037
1038  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1039  switch (bpu_ftb_update_stall) {
1040    is (0.U) {
1041      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1042        bpu_ftb_update_stall := 2.U // 2-cycle stall
1043      }
1044    }
1045    is (2.U) {
1046      bpu_ftb_update_stall := 1.U
1047    }
1048    is (1.U) {
1049      bpu_ftb_update_stall := 0.U
1050    }
1051    is (3.U) {
1052      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1053    }
1054  }
1055
1056  // TODO: remove this
1057  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1058
1059  io.toBpu.update := DontCare
1060  io.toBpu.update.valid := commit_valid && do_commit
1061  val update = io.toBpu.update.bits
1062  update.false_hit   := commit_hit === h_false_hit
1063  update.pc          := commit_pc_bundle.startAddr
1064  update.meta        := commit_meta.meta
1065  update.full_target := commit_target
1066  update.from_stage  := commit_stage
1067  update.fromFtqRedirectSram(commit_spec_meta)
1068
1069  val commit_real_hit = commit_hit === h_hit
1070  val update_ftb_entry = update.ftb_entry
1071
1072  val ftbEntryGen = Module(new FTBEntryGen).io
1073  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1074  ftbEntryGen.old_entry      := commit_ftb_entry
1075  ftbEntryGen.pd             := commit_pd
1076  ftbEntryGen.cfiIndex       := commit_cfi
1077  ftbEntryGen.target         := commit_target
1078  ftbEntryGen.hit            := commit_real_hit
1079  ftbEntryGen.mispredict_vec := commit_mispredict
1080
1081  update_ftb_entry         := ftbEntryGen.new_entry
1082  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1083  update.mispred_mask      := ftbEntryGen.mispred_mask
1084  update.old_entry         := ftbEntryGen.is_old_entry
1085  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1086
1087  update.is_minimal := false.B
1088  update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1089  update.full_pred.br_taken_mask  := ftbEntryGen.taken_mask
1090  update.full_pred.jalr_target := commit_target
1091  update.full_pred.hit := true.B
1092  when (update.full_pred.is_jalr) {
1093    update.full_pred.targets.last := commit_target
1094  }
1095
1096  // ****************************************************************
1097  // *********************** to prefetch ****************************
1098  // ****************************************************************
1099
1100  ftq_pc_mem.io.other_raddrs(0) := DontCare
1101  if(cacheParams.hasPrefetch){
1102    val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1103    val diff_prefetch_addr = WireInit(update_target(prefetchPtr.value)) //TODO: remove this
1104
1105    prefetchPtr := prefetchPtr + io.toPrefetch.req.fire()
1106
1107    ftq_pc_mem.io.other_raddrs(0) := prefetchPtr.value
1108
1109    when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) {
1110      prefetchPtr := bpu_s2_resp.ftq_idx
1111    }
1112
1113    when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) {
1114      prefetchPtr := bpu_s3_resp.ftq_idx
1115      // XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
1116    }
1117
1118
1119    val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send)
1120    val prefetch_addr = Wire(UInt(VAddrBits.W))
1121
1122    when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) {
1123      prefetch_is_to_send := true.B
1124      prefetch_addr := last_cycle_bpu_target
1125      diff_prefetch_addr := last_cycle_bpu_target // TODO: remove this
1126    }.otherwise{
1127      prefetch_addr := RegNext( ftq_pc_mem.io.other_rdatas(0).startAddr)
1128    }
1129    io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send
1130    io.toPrefetch.req.bits.target := prefetch_addr
1131
1132    when(redirectVec.map(r => r.valid).reduce(_||_)){
1133      val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1134      val next = r.ftqIdx + 1.U
1135      prefetchPtr := next
1136    }
1137
1138    // TODO: remove this
1139    // XSError(io.toPrefetch.req.valid && diff_prefetch_addr =/= prefetch_addr,
1140    //         f"\nprefetch_req_target wrong! prefetchPtr: ${prefetchPtr}, prefetch_addr: ${Hexadecimal(prefetch_addr)} diff_prefetch_addr: ${Hexadecimal(diff_prefetch_addr)}\n")
1141
1142
1143    XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n")
1144    XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n")
1145  }
1146  else {
1147    io.toPrefetch.req <> DontCare
1148  }
1149
1150  // ******************************************************************************
1151  // **************************** commit perf counters ****************************
1152  // ******************************************************************************
1153
1154  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1155  val commit_mispred_mask = commit_mispredict.asUInt
1156  val commit_not_mispred_mask = ~commit_mispred_mask
1157
1158  val commit_br_mask = commit_pd.brMask.asUInt
1159  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1160  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1161
1162  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1163
1164  val mbpRights = mbpInstrs & commit_not_mispred_mask
1165  val mbpWrongs = mbpInstrs & commit_mispred_mask
1166
1167  io.bpuInfo.bpRight := PopCount(mbpRights)
1168  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1169
1170  // Cfi Info
1171  for (i <- 0 until PredictWidth) {
1172    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1173    val v = commit_state(i) === c_commited
1174    val isBr = commit_pd.brMask(i)
1175    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1176    val isCfi = isBr || isJmp
1177    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1178    val misPred = commit_mispredict(i)
1179    // val ghist = commit_spec_meta.ghist.predHist
1180    val histPtr = commit_spec_meta.histPtr
1181    val predCycle = commit_meta.meta(63, 0)
1182    val target = commit_target
1183
1184    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1185    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1186    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1187    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1188    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1189    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1190    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1191  }
1192
1193  val enq = io.fromBpu.resp
1194  val perf_redirect = backendRedirect
1195
1196  XSPerfAccumulate("entry", validEntries)
1197  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1198  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1199  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1200  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1201
1202  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1203
1204  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1205  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1206  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1207
1208  val from_bpu = io.fromBpu.resp.bits
1209  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
1210    assert(!resp.is_minimal)
1211    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
1212    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
1213    val entry_len_map = (1 to PredictWidth+1).map(i =>
1214      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
1215    ).foldLeft(Map[String, UInt]())(_+_)
1216    entry_len_map
1217  }
1218  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
1219  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
1220
1221  val to_ifu = io.toIfu.req.bits
1222
1223
1224
1225  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
1226  val commit_num_inst_map = (1 to PredictWidth).map(i =>
1227    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
1228  ).foldLeft(Map[String, UInt]())(_+_)
1229
1230
1231
1232  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1233  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1234  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1235  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1236
1237
1238  val mbpBRights = mbpRights & commit_br_mask
1239  val mbpJRights = mbpRights & commit_jal_mask
1240  val mbpIRights = mbpRights & commit_jalr_mask
1241  val mbpCRights = mbpRights & commit_call_mask
1242  val mbpRRights = mbpRights & commit_ret_mask
1243
1244  val mbpBWrongs = mbpWrongs & commit_br_mask
1245  val mbpJWrongs = mbpWrongs & commit_jal_mask
1246  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1247  val mbpCWrongs = mbpWrongs & commit_call_mask
1248  val mbpRWrongs = mbpWrongs & commit_ret_mask
1249
1250  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1251
1252  def pred_stage_map(src: UInt, name: String) = {
1253    (0 until numBpStages).map(i =>
1254      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1255    ).foldLeft(Map[String, UInt]())(_+_)
1256  }
1257
1258  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1259  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1260  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1261  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1262  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1263  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1264
1265  val update_valid = io.toBpu.update.valid
1266  def u(cond: Bool) = update_valid && cond
1267  val ftb_false_hit = u(update.false_hit)
1268  // assert(!ftb_false_hit)
1269  val ftb_hit = u(commit_hit === h_hit)
1270
1271  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1272  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1273  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1274  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1275
1276  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1277
1278  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1279  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1280  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1281  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1282  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1283
1284  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
1285  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
1286  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
1287    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
1288  ).foldLeft(Map[String, UInt]())(_+_)
1289  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
1290    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
1291  ).foldLeft(Map[String, UInt]())(_+_)
1292
1293  val ftq_occupancy_map = (0 to FtqSize).map(i =>
1294    f"ftq_has_entry_$i" ->( validEntries === i.U)
1295  ).foldLeft(Map[String, UInt]())(_+_)
1296
1297  val perfCountsMap = Map(
1298    "BpInstr" -> PopCount(mbpInstrs),
1299    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1300    "BpRight"  -> PopCount(mbpRights),
1301    "BpWrong"  -> PopCount(mbpWrongs),
1302    "BpBRight" -> PopCount(mbpBRights),
1303    "BpBWrong" -> PopCount(mbpBWrongs),
1304    "BpJRight" -> PopCount(mbpJRights),
1305    "BpJWrong" -> PopCount(mbpJWrongs),
1306    "BpIRight" -> PopCount(mbpIRights),
1307    "BpIWrong" -> PopCount(mbpIWrongs),
1308    "BpCRight" -> PopCount(mbpCRights),
1309    "BpCWrong" -> PopCount(mbpCWrongs),
1310    "BpRRight" -> PopCount(mbpRRights),
1311    "BpRWrong" -> PopCount(mbpRWrongs),
1312
1313    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1314    "ftb_hit"                      -> PopCount(ftb_hit),
1315    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1316    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1317    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1318    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1319    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1320    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1321    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1322    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1323    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1324    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1325  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++
1326  s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++
1327  mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1328  correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1329
1330  for((key, value) <- perfCountsMap) {
1331    XSPerfAccumulate(key, value)
1332  }
1333
1334  // --------------------------- Debug --------------------------------
1335  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1336  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1337  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1338  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1339  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1340    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1341  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1342
1343  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1344  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1345  //       case (((valid, pd), ans), taken) =>
1346  //       Mux(valid && pd.isBr,
1347  //         isWrong ^ Mux(ans.hit.asBool,
1348  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1349  //           !taken),
1350  //         !taken),
1351  //       false.B)
1352  //     }
1353  //   }
1354
1355  //   def btbCheck(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,
1359  //         isWrong ^ Mux(ans.hit.asBool,
1360  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1361  //           !taken),
1362  //         !taken),
1363  //       false.B)
1364  //     }
1365  //   }
1366
1367  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1368  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1369  //       case (((valid, pd), ans), taken) =>
1370  //       Mux(valid && pd.isBr,
1371  //         isWrong ^ (ans.taken.asBool === taken),
1372  //       false.B)
1373  //     }
1374  //   }
1375
1376  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1377  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1378  //       case (((valid, pd), ans), taken) =>
1379  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1380  //         isWrong ^ (!taken),
1381  //           false.B)
1382  //     }
1383  //   }
1384
1385  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1386  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1387  //       case (((valid, pd), ans), taken) =>
1388  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1389  //         isWrong ^ (ans.target === commitEntry.target),
1390  //           false.B)
1391  //     }
1392  //   }
1393
1394  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1395  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1396  //   // btb and ubtb pred jal and jalr as well
1397  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1398  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1399  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1400  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1401
1402  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1403  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1404
1405  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1406  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1407
1408  val perfEvents = Seq(
1409    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1410    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1411    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1412    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1413    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1414    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1415    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1416    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1417    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1418    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1419    ("BpRight                ", PopCount(mbpRights)                                                         ),
1420    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1421    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1422    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1423    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1424    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1425    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1426    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1427    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1428    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1429    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1430    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1431    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1432    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1433  )
1434  generatePerfEvent()
1435}