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