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