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