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