xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision a38d1eab87777ed93b417106a7dfd58a062cee18)
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 nextCycleToPrefetchPcBundle = Wire(new Ftq_RF_Components)
810  val nextCycleToPrefetchEntryToSend = Wire(Bool())
811  val toPrefetchPcBundle = RegNext(nextCycleToPrefetchPcBundle)
812  val toPrefetchEntryToSend = RegNext(nextCycleToPrefetchEntryToSend)
813  val toIfuPcBundle = Wire(new Ftq_RF_Components)
814  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
815  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
816  val entry_next_addr  = Wire(UInt(VAddrBits.W))
817
818  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
819  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
820  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
821
822  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))))
823  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)))
824
825  for(i <- 0 until copyNum){
826    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
827      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
828      toICacheEntryToSend(i)   := true.B
829    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
830      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
831      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
832    }.otherwise{
833      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
834      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
835    }
836  }
837
838  // Calculate requests sent to prefetcher one cycle in advance to cut critical path
839  when(bpu_in_fire && bpu_in_resp_ptr === pfPtr_write) {
840    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.wdata
841    nextCycleToPrefetchEntryToSend := true.B
842  }.elsewhen(io.toPrefetch.req.fire) {
843    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.pfPtrPlus1_rdata
844    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtrPlus1.value) === f_to_send ||
845      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtrPlus1
846  }.otherwise {
847    nextCycleToPrefetchPcBundle    := ftq_pc_mem.io.pfPtr_rdata
848    nextCycleToPrefetchEntryToSend := entry_fetch_status(pfPtr.value) === f_to_send ||
849      last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr // reduce potential bubbles
850  }
851
852  // TODO: reconsider target address bypass logic
853  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
854    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
855    entry_is_to_send := true.B
856    entry_next_addr := last_cycle_bpu_target
857    entry_ftq_offset := last_cycle_cfiIndex
858    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
859  }.elsewhen (last_cycle_to_ifu_fire) {
860    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
861    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
862                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
863    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
864                          bpu_in_bypass_buf_for_ifu.startAddr,
865                          Mux(ifuPtr === newest_entry_ptr,
866                            newest_entry_target,
867                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
868  }.otherwise {
869    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
870    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
871                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
872    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
873                          bpu_in_bypass_buf_for_ifu.startAddr,
874                          Mux(ifuPtr === newest_entry_ptr,
875                            newest_entry_target,
876                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
877  }
878
879  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
880  io.toIfu.req.bits.nextStartAddr := entry_next_addr
881  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
882  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
883
884  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
885  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
886  io.toICache.req.bits.pcMemRead.zipWithIndex.foreach{case(copy,i) =>
887    copy.fromFtqPcBundle(toICachePcBundle(i))
888    copy.ftqIdx := ifuPtr
889  }
890  io.toICache.req.bits.backendIpf := backendIpf && backendPcFaultPtr === ifuPtr
891  io.toICache.req.bits.backendIgpf := backendIgpf && backendPcFaultPtr === ifuPtr
892  io.toICache.req.bits.backendIaf := backendIaf && backendPcFaultPtr === ifuPtr
893
894  io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
895  io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle)
896  io.toPrefetch.req.bits.ftqIdx := pfPtr
897  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
898  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
899  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
900  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
901  // }
902
903  // TODO: remove this
904  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
905          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
906
907  // when fall through is smaller in value than start address, there must be a false hit
908  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
909    when (io.toIfu.req.fire &&
910      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
911      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
912    ) {
913      entry_hit_status(ifuPtr.value) := h_false_hit
914      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
915    }
916    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
917  }
918
919  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
920    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
921
922  val ifu_req_should_be_flushed =
923    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
924    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
925
926    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
927      entry_fetch_status(ifuPtr.value) := f_sent
928    }
929
930  // *********************************************************************
931  // **************************** wb from ifu ****************************
932  // *********************************************************************
933  val pdWb = io.fromIfu.pdWb
934  val pds = pdWb.bits.pd
935  val ifu_wb_valid = pdWb.valid
936  val ifu_wb_idx = pdWb.bits.ftqIdx.value
937  // read ports:                                                         commit update
938  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum+1, 1, hasRen = true))
939  ftq_pd_mem.io.wen(0) := ifu_wb_valid
940  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
941  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
942
943  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
944  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
945  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
946  val pd_reg       = RegEnable(pds,             pdWb.valid)
947  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
948  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
949
950  when (ifu_wb_valid) {
951    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
952      case (v, inRange) => v && inRange
953    })
954    commitStateQueueEnable(ifu_wb_idx) := true.B
955    (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map {
956      case (qe, v) => when(v) {
957        qe := c_toCommit
958      }
959    }
960  }
961
962  when (ifu_wb_valid) {
963    ifuWbPtr_write := ifuWbPtr + 1.U
964  }
965
966  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
967
968  ftb_entry_mem.io.ren.get.head := ifu_wb_valid
969  ftb_entry_mem.io.raddr.head := ifu_wb_idx
970  val has_false_hit = WireInit(false.B)
971  when (RegNext(hit_pd_valid)) {
972    // check for false hit
973    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
974    val brSlots = pred_ftb_entry.brSlots
975    val tailSlot = pred_ftb_entry.tailSlot
976    // we check cfis that bpu predicted
977
978    // bpu predicted branches but denied by predecode
979    val br_false_hit =
980      brSlots.map{
981        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
982      }.reduce(_||_) ||
983      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
984        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
985
986    val jmpOffset = tailSlot.offset
987    val jmp_pd = pd_reg(jmpOffset)
988    val jal_false_hit = pred_ftb_entry.jmpValid &&
989      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
990       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
991       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
992       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
993      )
994
995    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
996    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
997
998    // assert(!has_false_hit)
999  }
1000
1001  when (has_false_hit) {
1002    entry_hit_status(wb_idx_reg) := h_false_hit
1003  }
1004
1005  // *******************************************************************************
1006  // **************************** redirect from backend ****************************
1007  // *******************************************************************************
1008
1009  // redirect read cfiInfo, couples to redirectGen s2
1010  // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1)
1011  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
1012  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem))
1013
1014  val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry))
1015  for (i <- 1 until FtqRedirectAheadNum) {
1016    ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid
1017    ftq_redirect_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value
1018    ftb_entry_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid
1019    ftb_entry_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value
1020
1021    ftq_pd_mem.io.ren.get(i)  := ftqIdxAhead(i).valid
1022    ftq_pd_mem.io.raddr(i)    := ftqIdxAhead(i).bits.value
1023  }
1024  ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1025  ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1026  ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1027  ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1028
1029  ftq_pd_mem.io.ren.get(0)  := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid)
1030  ftq_pd_mem.io.raddr(0)    := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
1031
1032  for (i <- 0 until FtqRedirectAheadNum) {
1033    ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum)
1034    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum)
1035
1036    ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i)
1037  }
1038  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum))
1039  val stage3PdInfo  = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0))
1040  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
1041  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
1042  backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset)
1043
1044
1045  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum))
1046  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
1047
1048  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
1049  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
1050  // FIXME: not portable
1051  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
1052  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
1053    sc_disagree(0), sc_disagree(1))
1054
1055  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
1056    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
1057      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
1058      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
1059
1060    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
1061        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
1062  }.otherwise {
1063    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
1064    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
1065  }
1066
1067
1068  // ***************************************************************************
1069  // **************************** redirect from ifu ****************************
1070  // ***************************************************************************
1071  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
1072  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
1073  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
1074  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
1075  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
1076  fromIfuRedirect.bits.BTBMissBubble := true.B
1077  fromIfuRedirect.bits.debugIsMemVio := false.B
1078  fromIfuRedirect.bits.debugIsCtrl := false.B
1079
1080  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
1081  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
1082  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
1083  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
1084  ifuRedirectCfiUpdate.target := pdWb.bits.target
1085  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
1086  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
1087
1088  val ifuRedirectReg = RegNextWithEnable(fromIfuRedirect, hasInit = true)
1089  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
1090  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
1091
1092  ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid
1093  ftq_redirect_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
1094
1095  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
1096  toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head)
1097  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
1098    toBpuCfi.target := toBpuCfi.topAddr
1099  }
1100
1101  when (ifuRedirectReg.valid) {
1102    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
1103  } .elsewhen(RegNext(pdWb.valid)) {
1104    // if pdWb and no redirect, set to false
1105    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
1106  }
1107
1108  // **********************************************************************
1109  // ***************************** to backend *****************************
1110  // **********************************************************************
1111  // to backend pc mem / target
1112  io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in)
1113  io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)
1114  io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in)
1115
1116  // num cycle is fixed
1117  val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid)
1118  io.toBackend.newest_entry_en := RegNext(newest_entry_en)
1119  io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en)
1120  io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en)
1121
1122  // *********************************************************************
1123  // **************************** wb from exu ****************************
1124  // *********************************************************************
1125
1126  backendRedirect.valid := io.fromBackend.redirect.valid
1127  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1128  backendRedirect.bits.BTBMissBubble := false.B
1129
1130
1131  def extractRedirectInfo(wb: Valid[Redirect]) = {
1132    val ftqPtr = wb.bits.ftqIdx
1133    val ftqOffset = wb.bits.ftqOffset
1134    val taken = wb.bits.cfiUpdate.taken
1135    val mispred = wb.bits.cfiUpdate.isMisPred
1136    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
1137  }
1138
1139  // fix mispredict entry
1140  val lastIsMispredict = RegNext(
1141    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
1142  )
1143
1144  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
1145    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
1146    val r_idx = r_ptr.value
1147    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
1148    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
1149    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
1150      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
1151    } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
1152      cfiIndex_vec(r_idx).valid :=false.B
1153    }
1154    when (cfiIndex_bits_wen) {
1155      cfiIndex_vec(r_idx).bits := r_offset
1156    }
1157    newest_entry_target_modified := true.B
1158    newest_entry_target := redirect.bits.cfiUpdate.target
1159    newest_entry_ptr_modified := true.B
1160    newest_entry_ptr := r_ptr
1161
1162    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
1163    if (isBackend) {
1164      mispredict_vec(r_idx)(r_offset) := r_mispred
1165    }
1166  }
1167
1168  when(fromBackendRedirect.valid) {
1169    updateCfiInfo(fromBackendRedirect)
1170  }.elsewhen (ifuRedirectToBpu.valid) {
1171    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
1172  }
1173
1174  when (fromBackendRedirect.valid) {
1175    when (fromBackendRedirect.bits.ControlRedirectBubble) {
1176      when (fromBackendRedirect.bits.ControlBTBMissBubble) {
1177        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1178        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1179      } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) {
1180        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1181        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1182      } .elsewhen (fromBackendRedirect.bits.SCMissBubble) {
1183        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
1184        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1185      } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) {
1186        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1187        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1188      } .elsewhen (fromBackendRedirect.bits.RASMissBubble) {
1189        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
1190        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1191      }
1192
1193
1194    } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) {
1195      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1196      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1197    } .otherwise {
1198      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1199      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1200    }
1201  } .elsewhen (ifuRedirectReg.valid) {
1202    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1203    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1204  }
1205
1206  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1207  io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble
1208  io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble
1209  io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble
1210  io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble
1211
1212  // ***********************************************************************************
1213  // **************************** flush ptr and state queue ****************************
1214  // ***********************************************************************************
1215
1216  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
1217
1218  // when redirect, we should reset ptrs and status queues
1219  io.icacheFlush := redirectVec.map(r => r.valid).reduce(_||_)
1220  XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid)
1221  XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid)
1222  when(redirectVec.map(r => r.valid).reduce(_||_)){
1223    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1224    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1225    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1226    val next = idx + 1.U
1227    bpuPtr := next
1228    copied_bpu_ptr.map(_ := next)
1229    ifuPtr_write := next
1230    ifuWbPtr_write := next
1231    ifuPtrPlus1_write := idx + 2.U
1232    ifuPtrPlus2_write := idx + 3.U
1233    pfPtr_write := next
1234    pfPtrPlus1_write := idx + 2.U
1235  }
1236  when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){
1237    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1238    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
1239    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
1240    when (RegNext(notIfu)) {
1241      commitStateQueueEnable(RegNext(idx.value)) := true.B
1242      commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) =>
1243        when(i.U > RegNext(offset)) {
1244          s := c_empty
1245        }
1246        when (i.U === RegNext(offset) && RegNext(flushItSelf)) {
1247          s := c_flushed
1248        }
1249      })
1250    }
1251  }
1252
1253
1254  // only the valid bit is actually needed
1255  io.toIfu.redirect.bits    := backendRedirect.bits
1256  io.toIfu.redirect.valid   := stage2Flush
1257  io.toIfu.topdown_redirect := fromBackendRedirect
1258
1259  // commit
1260  for (c <- io.fromBackend.rob_commits) {
1261    when(c.valid) {
1262      commitStateQueueEnable(c.bits.ftqIdx.value) := true.B
1263      commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed
1264      // TODO: remove this
1265      // For instruction fusions, we also update the next instruction
1266      when (c.bits.commitType === 4.U) {
1267        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed
1268      }.elsewhen(c.bits.commitType === 5.U) {
1269        commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed
1270      }.elsewhen(c.bits.commitType === 6.U) {
1271        val index = (c.bits.ftqIdx + 1.U).value
1272        commitStateQueueEnable(index) := true.B
1273        commitStateQueueNext(index)(0) := c_committed
1274      }.elsewhen(c.bits.commitType === 7.U) {
1275        val index = (c.bits.ftqIdx + 1.U).value
1276        commitStateQueueEnable(index) := true.B
1277        commitStateQueueNext(index)(1) := c_committed
1278      }
1279    }
1280  }
1281
1282  // ****************************************************************
1283  // **************************** to bpu ****************************
1284  // ****************************************************************
1285
1286  io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid
1287  io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1288  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W)))
1289  val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1290  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1291  XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1)
1292
1293  XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay")
1294
1295  val may_have_stall_from_bpu = Wire(Bool())
1296  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
1297  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
1298
1299  val validInstructions = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed)
1300  val lastInstructionStatus = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse))
1301  val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed
1302  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1303    (isAfter(robCommPtr, commPtr) ||
1304      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed)
1305  val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1306    (isAfter(robCommPtr, commPtr) ||
1307      validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed ||
1308      firstInstructionFlushed)
1309
1310  when (io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) {
1311    robCommPtr_write := ParallelPriorityMux(io.fromBackend.rob_commits.map(_.valid).reverse, io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse)
1312  } .elsewhen (isAfter(commPtr, robCommPtr)) {
1313    robCommPtr_write := commPtr
1314  } .otherwise {
1315    robCommPtr_write := robCommPtr
1316  }
1317
1318  /**
1319    *************************************************************************************
1320    * MMIO instruction fetch is allowed only if MMIO is the oldest instruction.
1321    *************************************************************************************
1322    */
1323  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
1324  val mmioLastCommit = isAfter(commPtr, mmioReadPtr) ||
1325    commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed
1326  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
1327
1328  // commit reads
1329  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1330  val commit_target =
1331    Mux(RegNext(commPtr === newest_entry_ptr),
1332      RegEnable(newest_entry_target, newest_entry_target_modified),
1333      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1334  ftq_pd_mem.io.ren.get.last := canCommit
1335  ftq_pd_mem.io.raddr.last := commPtr.value
1336  val commit_pd = ftq_pd_mem.io.rdata.last
1337  ftq_redirect_mem.io.ren.get.last := canCommit
1338  ftq_redirect_mem.io.raddr.last := commPtr.value
1339  val commit_spec_meta = ftq_redirect_mem.io.rdata.last
1340  ftq_meta_1r_sram.io.ren(0) := canCommit
1341  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1342  val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta
1343  val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry
1344
1345  // need one cycle to read mem and srams
1346  val do_commit_ptr = RegEnable(commPtr, canCommit)
1347  val do_commit = RegNext(canCommit, init=false.B)
1348  when (canMoveCommPtr) {
1349    commPtr_write := commPtrPlus1
1350    commPtrPlus1_write := commPtrPlus1 + 1.U
1351  }
1352  val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit)
1353  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1354  val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value))
1355  //
1356  //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1357  //  can_commit_cfi.valid := false.B
1358  //}
1359  val commit_cfi = RegEnable(can_commit_cfi, canCommit)
1360  val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid
1361
1362  val commit_mispredict  : Vec[Bool] = VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map {
1363    case (mis, state) => mis && state === c_committed
1364  })
1365  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth]
1366  val can_commit_hit                 = entry_hit_status(commPtr.value)
1367  val commit_hit                     = RegEnable(can_commit_hit, canCommit)
1368  val diff_commit_target             = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this
1369  val commit_stage                   = RegEnable(pred_stage(commPtr.value), canCommit)
1370  val commit_valid                   = commit_hit === h_hit || commit_cfi.valid // hit or taken
1371
1372  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1373  switch (bpu_ftb_update_stall) {
1374    is (0.U) {
1375      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1376        bpu_ftb_update_stall := 2.U // 2-cycle stall
1377      }
1378    }
1379    is (2.U) {
1380      bpu_ftb_update_stall := 1.U
1381    }
1382    is (1.U) {
1383      bpu_ftb_update_stall := 0.U
1384    }
1385    is (3.U) {
1386      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1387    }
1388  }
1389
1390  // TODO: remove this
1391  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1392
1393  // update latency stats
1394  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1395  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1396
1397  io.toBpu.update := DontCare
1398  io.toBpu.update.valid := commit_valid && do_commit
1399  val update = io.toBpu.update.bits
1400  update.false_hit   := commit_hit === h_false_hit
1401  update.pc          := commit_pc_bundle.startAddr
1402  update.meta        := commit_meta
1403  update.cfi_idx     := commit_cfi
1404  update.full_target := commit_target
1405  update.from_stage  := commit_stage
1406  update.spec_info   := commit_spec_meta
1407  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
1408
1409  val commit_real_hit = commit_hit === h_hit
1410  val update_ftb_entry = update.ftb_entry
1411
1412  val ftbEntryGen = Module(new FTBEntryGen).io
1413  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1414  ftbEntryGen.old_entry      := commit_ftb_entry
1415  ftbEntryGen.pd             := commit_pd
1416  ftbEntryGen.cfiIndex       := commit_cfi
1417  ftbEntryGen.target         := commit_target
1418  ftbEntryGen.hit            := commit_real_hit
1419  ftbEntryGen.mispredict_vec := commit_mispredict
1420
1421  update_ftb_entry         := ftbEntryGen.new_entry
1422  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1423  update.mispred_mask      := ftbEntryGen.mispred_mask
1424  update.old_entry         := ftbEntryGen.is_old_entry
1425  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1426  update.br_taken_mask     := ftbEntryGen.taken_mask
1427  update.br_committed      := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1428    case (valid, offset) => valid && commit_instCommited(offset)
1429  }
1430  update.jmp_taken         := ftbEntryGen.jmp_taken
1431
1432  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1433  // update.full_pred.jalr_target := commit_target
1434  // update.full_pred.hit := true.B
1435  // when (update.full_pred.is_jalr) {
1436  //   update.full_pred.targets.last := commit_target
1437  // }
1438
1439  // ******************************************************************************
1440  // **************************** commit perf counters ****************************
1441  // ******************************************************************************
1442
1443  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt
1444  val commit_mispred_mask = commit_mispredict.asUInt
1445  val commit_not_mispred_mask = ~commit_mispred_mask
1446
1447  val commit_br_mask = commit_pd.brMask.asUInt
1448  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1449  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1450
1451  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1452
1453  val mbpRights = mbpInstrs & commit_not_mispred_mask
1454  val mbpWrongs = mbpInstrs & commit_mispred_mask
1455
1456  io.bpuInfo.bpRight := PopCount(mbpRights)
1457  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1458
1459  val hartId = p(XSCoreParamsKey).HartId
1460  val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId")
1461  val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle)
1462  // Cfi Info
1463  for (i <- 0 until PredictWidth) {
1464    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1465    val v = commit_state(i) === c_committed
1466    val isBr = commit_pd.brMask(i)
1467    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1468    val isCfi = isBr || isJmp
1469    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1470    val misPred = commit_mispredict(i)
1471    // val ghist = commit_spec_meta.ghist.predHist
1472    val histPtr = commit_spec_meta.histPtr
1473    val predCycle = commit_meta(63, 0)
1474    val target = commit_target
1475
1476    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1477    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1478    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1479    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1480    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1481    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1482    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1483
1484    val logbundle = Wire(new FtqDebugBundle)
1485    logbundle.pc := pc
1486    logbundle.target := target
1487    logbundle.isBr := isBr
1488    logbundle.isJmp := isJmp
1489    logbundle.isCall := isJmp && commit_pd.hasCall
1490    logbundle.isRet := isJmp && commit_pd.hasRet
1491    logbundle.misPred := misPred
1492    logbundle.isTaken := isTaken
1493    logbundle.predStage := commit_stage
1494
1495    ftqBranchTraceDB.log(
1496      data = logbundle /* hardware of type T */,
1497      en = isWriteFTQTable.orR && v && do_commit && isCfi,
1498      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1499      clock = clock,
1500      reset = reset
1501    )
1502  }
1503
1504  val enq = io.fromBpu.resp
1505  val perf_redirect = backendRedirect
1506
1507  XSPerfAccumulate("entry", validEntries)
1508  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1509  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1510  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1511  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1512
1513  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1514
1515  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1516  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1517  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1518  XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready)
1519
1520  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_))
1521  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
1522  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
1523
1524  val from_bpu = io.fromBpu.resp.bits
1525  val to_ifu = io.toIfu.req.bits
1526
1527
1528  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1)
1529
1530
1531
1532
1533  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1534  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1535  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1536  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1537
1538
1539  val mbpBRights = mbpRights & commit_br_mask
1540  val mbpJRights = mbpRights & commit_jal_mask
1541  val mbpIRights = mbpRights & commit_jalr_mask
1542  val mbpCRights = mbpRights & commit_call_mask
1543  val mbpRRights = mbpRights & commit_ret_mask
1544
1545  val mbpBWrongs = mbpWrongs & commit_br_mask
1546  val mbpJWrongs = mbpWrongs & commit_jal_mask
1547  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1548  val mbpCWrongs = mbpWrongs & commit_call_mask
1549  val mbpRWrongs = mbpWrongs & commit_ret_mask
1550
1551  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1552
1553  def pred_stage_map(src: UInt, name: String) = {
1554    (0 until numBpStages).map(i =>
1555      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1556    ).foldLeft(Map[String, UInt]())(_+_)
1557  }
1558
1559  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1560  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1561  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1562  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1563  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1564  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1565
1566  val update_valid = io.toBpu.update.valid
1567  def u(cond: Bool) = update_valid && cond
1568  val ftb_false_hit = u(update.false_hit)
1569  // assert(!ftb_false_hit)
1570  val ftb_hit = u(commit_hit === h_hit)
1571
1572  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1573  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1574  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1575  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1576
1577  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1578
1579  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1580  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1581  val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value))
1582  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1583  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1584  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1585
1586  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1587  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1588  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1)
1589  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1)
1590  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1591  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1)
1592
1593  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1)
1594
1595  val perfCountsMap = Map(
1596    "BpInstr" -> PopCount(mbpInstrs),
1597    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1598    "BpRight"  -> PopCount(mbpRights),
1599    "BpWrong"  -> PopCount(mbpWrongs),
1600    "BpBRight" -> PopCount(mbpBRights),
1601    "BpBWrong" -> PopCount(mbpBWrongs),
1602    "BpJRight" -> PopCount(mbpJRights),
1603    "BpJWrong" -> PopCount(mbpJWrongs),
1604    "BpIRight" -> PopCount(mbpIRights),
1605    "BpIWrong" -> PopCount(mbpIWrongs),
1606    "BpCRight" -> PopCount(mbpCRights),
1607    "BpCWrong" -> PopCount(mbpCWrongs),
1608    "BpRRight" -> PopCount(mbpRRights),
1609    "BpRWrong" -> PopCount(mbpRWrongs),
1610
1611    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1612    "ftb_hit"                      -> PopCount(ftb_hit),
1613    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1614    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1615    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1616    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1617    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1618    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1619    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1620    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1621    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1622    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1623  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1624       correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1625
1626  for((key, value) <- perfCountsMap) {
1627    XSPerfAccumulate(key, value)
1628  }
1629
1630  // --------------------------- Debug --------------------------------
1631  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1632  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1633  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1634  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1635  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1636    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1637  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1638
1639  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1640  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1641  //       case (((valid, pd), ans), taken) =>
1642  //       Mux(valid && pd.isBr,
1643  //         isWrong ^ Mux(ans.hit.asBool,
1644  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1645  //           !taken),
1646  //         !taken),
1647  //       false.B)
1648  //     }
1649  //   }
1650
1651  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1652  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1653  //       case (((valid, pd), ans), taken) =>
1654  //       Mux(valid && pd.isBr,
1655  //         isWrong ^ Mux(ans.hit.asBool,
1656  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1657  //           !taken),
1658  //         !taken),
1659  //       false.B)
1660  //     }
1661  //   }
1662
1663  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1664  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1665  //       case (((valid, pd), ans), taken) =>
1666  //       Mux(valid && pd.isBr,
1667  //         isWrong ^ (ans.taken.asBool === taken),
1668  //       false.B)
1669  //     }
1670  //   }
1671
1672  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1673  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1674  //       case (((valid, pd), ans), taken) =>
1675  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1676  //         isWrong ^ (!taken),
1677  //           false.B)
1678  //     }
1679  //   }
1680
1681  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1682  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1683  //       case (((valid, pd), ans), taken) =>
1684  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1685  //         isWrong ^ (ans.target === commitEntry.target),
1686  //           false.B)
1687  //     }
1688  //   }
1689
1690  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1691  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1692  //   // btb and ubtb pred jal and jalr as well
1693  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1694  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1695  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1696  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1697
1698  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1699  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1700
1701  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1702  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1703
1704  val perfEvents = Seq(
1705    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1706    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1707    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1708    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1709    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1710    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1711    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1712    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1713    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1714    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1715    ("BpRight                ", PopCount(mbpRights)                                                         ),
1716    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1717    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1718    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1719    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1720    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1721    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1722    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1723    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1724    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1725    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1726    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1727    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1728    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1729  )
1730  generatePerfEvent()
1731}
1732