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