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