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