xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision c5e28a9a871afdf94bb2dd0a343a6f58d9c0e8a5)
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  io.bpuInfo := DontCare
447
448  val backendRedirect = Wire(Valid(new Redirect))
449  val backendRedirectReg = RegNext(backendRedirect)
450
451  val stage2Flush = backendRedirect.valid
452  val backendFlush = stage2Flush || RegNext(stage2Flush)
453  val ifuFlush = Wire(Bool())
454
455  val flush = stage2Flush || RegNext(stage2Flush)
456
457  val allowBpuIn, allowToIfu = WireInit(false.B)
458  val flushToIfu = !allowToIfu
459  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
460  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
461
462  def copyNum = 5
463  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
464  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
465  val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U))
466  val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
467  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
468  val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
469  require(FtqSize >= 4)
470  val ifuPtr_write       = WireInit(ifuPtr)
471  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
472  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
473  val ifuWbPtr_write     = WireInit(ifuWbPtr)
474  val commPtr_write      = WireInit(commPtr)
475  val commPtrPlus1_write = WireInit(commPtrPlus1)
476  ifuPtr       := ifuPtr_write
477  ifuPtrPlus1  := ifuPtrPlus1_write
478  ifuPtrPlus2  := ifuPtrPlus2_write
479  ifuWbPtr     := ifuWbPtr_write
480  commPtr      := commPtr_write
481  commPtrPlus1 := commPtrPlus1_write
482  copied_ifu_ptr.map{ptr =>
483    ptr := ifuPtr_write
484    dontTouch(ptr)
485  }
486  val validEntries = distanceBetween(bpuPtr, commPtr)
487
488  // **********************************************************************
489  // **************************** enq from bpu ****************************
490  // **********************************************************************
491  val new_entry_ready = validEntries < FtqSize.U
492  io.fromBpu.resp.ready := new_entry_ready
493
494  val bpu_s2_resp = io.fromBpu.resp.bits.s2
495  val bpu_s3_resp = io.fromBpu.resp.bits.s3
496  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
497  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
498
499  io.toBpu.enq_ptr := bpuPtr
500  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
501  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
502
503  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
504  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx
505  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
506  val bpu_in_resp_idx = bpu_in_resp_ptr.value
507
508  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
509  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
510  // resp from uBTB
511  ftq_pc_mem.io.wen := bpu_in_fire
512  ftq_pc_mem.io.waddr := bpu_in_resp_idx
513  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
514
515  //                                                            ifuRedirect + backendRedirect + commit
516  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
517  // these info is intended to enq at the last stage of bpu
518  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
519  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
520  ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info
521  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
522  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
523
524  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
525  // these info is intended to enq at the last stage of bpu
526  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
527  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
528  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta
529  //                                                            ifuRedirect + backendRedirect + commit
530  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
531  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
532  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
533  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
534
535
536  // multi-write
537  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
538  val newest_entry_target = Reg(UInt(VAddrBits.W))
539  val newest_entry_ptr = Reg(new FtqPtr)
540  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
541  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
542  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
543
544  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
545  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
546    VecInit(Seq.fill(PredictWidth)(c_invalid))
547  }))
548
549  val f_to_send :: f_sent :: Nil = Enum(2)
550  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
551
552  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
553  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
554
555  // modify registers one cycle later to cut critical path
556  val last_cycle_bpu_in = RegNext(bpu_in_fire)
557  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
558  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
559  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget)
560  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex)
561  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
562
563  def extra_copyNum_for_commitStateQueue = 2
564  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
565  val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr)))
566
567  when (last_cycle_bpu_in) {
568    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
569    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
570    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
571
572    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
573    newest_entry_target := last_cycle_bpu_target
574    newest_entry_ptr := last_cycle_bpu_in_ptr
575  }
576
577  // reduce fanout by delay write for a cycle
578  when (RegNext(last_cycle_bpu_in)) {
579    mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
580  }
581
582  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
583  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
584  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
585    case ((in, ptr), i) =>
586      when (in) {
587        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
588        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
589        for (j <- 0 until perSetEntries) {
590          when (ptr.value === (i*perSetEntries+j).U) {
591            commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid))
592          }
593        }
594      }
595  }
596
597  // num cycle is fixed
598  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
599  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
600
601
602  bpuPtr := bpuPtr + enq_fire
603  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
604  when (io.toIfu.req.fire && allowToIfu) {
605    ifuPtr_write := ifuPtrPlus1
606    ifuPtrPlus1_write := ifuPtrPlus2
607    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
608  }
609
610  // only use ftb result to assign hit status
611  when (bpu_s2_resp.valid) {
612    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit)
613  }
614
615
616  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
617  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
618  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
619    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
620    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
621    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
622    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
623      ifuPtr_write := bpu_s2_resp.ftq_idx
624      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
625      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
626    }
627  }
628
629  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
630  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
631  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
632    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
633    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
634    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
635    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
636      ifuPtr_write := bpu_s3_resp.ftq_idx
637      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
638      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
639    }
640  }
641
642  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
643
644  (0 until copyNum).map{i =>
645    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
646  }
647
648  // ****************************************************************
649  // **************************** to ifu ****************************
650  // ****************************************************************
651  // 0  for ifu, and 1-4 for ICache
652  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, enable=bpu_in_fire)
653  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, enable=bpu_in_fire)))
654  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
655  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
656  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
657
658  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
659  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
660
661  // read pc and target
662  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
663  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
664  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
665  ftq_pc_mem.io.commPtr_w      := commPtr_write
666  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
667
668
669  io.toIfu.req.bits.ftqIdx := ifuPtr
670
671  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
672  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
673  val toIfuPcBundle = Wire(new Ftq_RF_Components)
674  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
675  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
676  val entry_next_addr  = Wire(UInt(VAddrBits.W))
677
678  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
679  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
680  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
681
682  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))))
683  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)))
684
685  for(i <- 0 until copyNum){
686    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
687      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
688      toICacheEntryToSend(i)   := true.B
689    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
690      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
691      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
692    }.otherwise{
693      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
694      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
695    }
696  }
697
698  // TODO: reconsider target address bypass logic
699  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
700    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
701    entry_is_to_send := true.B
702    entry_next_addr := last_cycle_bpu_target
703    entry_ftq_offset := last_cycle_cfiIndex
704    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
705  }.elsewhen (last_cycle_to_ifu_fire) {
706    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
707    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
708                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
709    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
710                          bpu_in_bypass_buf_for_ifu.startAddr,
711                          Mux(ifuPtr === newest_entry_ptr,
712                            newest_entry_target,
713                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
714  }.otherwise {
715    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
716    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
717                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
718    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
719                          bpu_in_bypass_buf_for_ifu.startAddr,
720                          Mux(ifuPtr === newest_entry_ptr,
721                            newest_entry_target,
722                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
723  }
724
725  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
726  io.toIfu.req.bits.nextStartAddr := entry_next_addr
727  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
728  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
729
730  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
731  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
732  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
733  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
734  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
735  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
736  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
737  // }
738
739  // TODO: remove this
740  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
741          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
742
743  // when fall through is smaller in value than start address, there must be a false hit
744  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
745    when (io.toIfu.req.fire &&
746      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
747      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
748    ) {
749      entry_hit_status(ifuPtr.value) := h_false_hit
750      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
751    }
752    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
753  }
754
755  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
756    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
757
758  val ifu_req_should_be_flushed =
759    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
760    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
761
762    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
763      entry_fetch_status(ifuPtr.value) := f_sent
764    }
765
766  // *********************************************************************
767  // **************************** wb from ifu ****************************
768  // *********************************************************************
769  val pdWb = io.fromIfu.pdWb
770  val pds = pdWb.bits.pd
771  val ifu_wb_valid = pdWb.valid
772  val ifu_wb_idx = pdWb.bits.ftqIdx.value
773  // read ports:                                                         commit update
774  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
775  ftq_pd_mem.io.wen(0) := ifu_wb_valid
776  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
777  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
778
779  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
780  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
781  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
782  val pd_reg       = RegEnable(pds,             pdWb.valid)
783  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
784  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
785
786  when (ifu_wb_valid) {
787    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
788      case (v, inRange) => v && inRange
789    })
790    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
791      case (qe, v) => when (v) { qe := c_valid }
792    }
793  }
794
795  when (ifu_wb_valid) {
796    ifuWbPtr_write := ifuWbPtr + 1.U
797  }
798
799  ftb_entry_mem.io.raddr.head := ifu_wb_idx
800  val has_false_hit = WireInit(false.B)
801  when (RegNext(hit_pd_valid)) {
802    // check for false hit
803    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
804    val brSlots = pred_ftb_entry.brSlots
805    val tailSlot = pred_ftb_entry.tailSlot
806    // we check cfis that bpu predicted
807
808    // bpu predicted branches but denied by predecode
809    val br_false_hit =
810      brSlots.map{
811        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
812      }.reduce(_||_) ||
813      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
814        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
815
816    val jmpOffset = tailSlot.offset
817    val jmp_pd = pd_reg(jmpOffset)
818    val jal_false_hit = pred_ftb_entry.jmpValid &&
819      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
820       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
821       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
822       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
823      )
824
825    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
826    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
827
828    // assert(!has_false_hit)
829  }
830
831  when (has_false_hit) {
832    entry_hit_status(wb_idx_reg) := h_false_hit
833  }
834
835
836  // **********************************************************************
837  // ***************************** to backend *****************************
838  // **********************************************************************
839  // to backend pc mem / target
840  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
841  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
842  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
843
844  // *******************************************************************************
845  // **************************** redirect from backend ****************************
846  // *******************************************************************************
847
848  // redirect read cfiInfo, couples to redirectGen s2
849  ftq_redirect_sram.io.ren.init.last := backendRedirect.valid
850  ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
851
852  ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value
853
854  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
855  val fromBackendRedirect = WireInit(backendRedirectReg)
856  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
857  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
858
859  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
860  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
861
862  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
863    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
864      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
865      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
866
867    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
868        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
869  }.otherwise {
870    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
871    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
872  }
873
874
875  // ***************************************************************************
876  // **************************** redirect from ifu ****************************
877  // ***************************************************************************
878  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
879  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
880  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
881  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
882  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
883
884  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
885  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
886  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
887  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
888  ifuRedirectCfiUpdate.target := pdWb.bits.target
889  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
890  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
891
892  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
893  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
894  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
895
896  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
897  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
898
899  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
900
901  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
902  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
903  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
904    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
905  }
906
907  // *********************************************************************
908  // **************************** wb from exu ****************************
909  // *********************************************************************
910
911  backendRedirect := io.fromBackend.redirect
912
913  def extractRedirectInfo(wb: Valid[Redirect]) = {
914    val ftqPtr = wb.bits.ftqIdx
915    val ftqOffset = wb.bits.ftqOffset
916    val taken = wb.bits.cfiUpdate.taken
917    val mispred = wb.bits.cfiUpdate.isMisPred
918    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
919  }
920
921  // fix mispredict entry
922  val lastIsMispredict = RegNext(
923    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
924  )
925
926  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
927    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
928    val r_idx = r_ptr.value
929    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
930    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
931    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
932      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
933    }
934    when (cfiIndex_bits_wen) {
935      cfiIndex_vec(r_idx).bits := r_offset
936    }
937    newest_entry_target := redirect.bits.cfiUpdate.target
938    newest_entry_ptr := r_ptr
939    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
940    if (isBackend) {
941      mispredict_vec(r_idx)(r_offset) := r_mispred
942    }
943  }
944
945  when(backendRedirectReg.valid) {
946    updateCfiInfo(backendRedirectReg)
947  }.elsewhen (ifuRedirectToBpu.valid) {
948    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
949  }
950
951  // ***********************************************************************************
952  // **************************** flush ptr and state queue ****************************
953  // ***********************************************************************************
954
955  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
956
957  // when redirect, we should reset ptrs and status queues
958  when(redirectVec.map(r => r.valid).reduce(_||_)){
959    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
960    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
961    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
962    val next = idx + 1.U
963    bpuPtr := next
964    copied_bpu_ptr.map(_ := next)
965    ifuPtr_write := next
966    ifuWbPtr_write := next
967    ifuPtrPlus1_write := idx + 2.U
968    ifuPtrPlus2_write := idx + 3.U
969    when (notIfu) {
970      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
971        when(i.U > offset || i.U === offset && flushItSelf){
972          s := c_invalid
973        }
974      })
975    }
976  }
977
978  // only the valid bit is actually needed
979  io.toIfu.redirect.bits    := backendRedirect.bits
980  io.toIfu.redirect.valid   := stage2Flush
981
982  // commit
983  for (c <- io.fromBackend.rob_commits) {
984    when(c.valid) {
985      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
986      // TODO: remove this
987      // For instruction fusions, we also update the next instruction
988      when (c.bits.commitType === 4.U) {
989        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
990      }.elsewhen(c.bits.commitType === 5.U) {
991        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
992      }.elsewhen(c.bits.commitType === 6.U) {
993        val index = (c.bits.ftqIdx + 1.U).value
994        commitStateQueue(index)(0) := c_commited
995      }.elsewhen(c.bits.commitType === 7.U) {
996        val index = (c.bits.ftqIdx + 1.U).value
997        commitStateQueue(index)(1) := c_commited
998      }
999    }
1000  }
1001
1002  // ****************************************************************
1003  // **************************** to bpu ****************************
1004  // ****************************************************************
1005
1006  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1007
1008  val may_have_stall_from_bpu = Wire(Bool())
1009  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
1010  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
1011  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
1012    Cat(commitStateQueue(commPtr.value).map(s => {
1013      s === c_invalid || s === c_commited
1014    })).andR()
1015
1016  // commit reads
1017  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
1018  val commit_target =
1019    Mux(RegNext(commPtr === newest_entry_ptr),
1020      RegNext(newest_entry_target),
1021      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
1022  ftq_pd_mem.io.raddr.last := commPtr.value
1023  val commit_pd = ftq_pd_mem.io.rdata.last
1024  ftq_redirect_sram.io.ren.last := canCommit
1025  ftq_redirect_sram.io.raddr.last := commPtr.value
1026  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
1027  ftq_meta_1r_sram.io.ren(0) := canCommit
1028  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
1029  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
1030  ftb_entry_mem.io.raddr.last := commPtr.value
1031  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
1032
1033  // need one cycle to read mem and srams
1034  val do_commit_ptr = RegNext(commPtr)
1035  val do_commit = RegNext(canCommit, init=false.B)
1036  when (canCommit) {
1037    commPtr_write := commPtrPlus1
1038    commPtrPlus1_write := commPtrPlus1 + 1.U
1039  }
1040  val commit_state = RegNext(commitStateQueue(commPtr.value))
1041  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1042  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
1043    can_commit_cfi.valid := false.B
1044  }
1045  val commit_cfi = RegNext(can_commit_cfi)
1046
1047  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
1048    case (mis, state) => mis && state === c_commited
1049  })
1050  val can_commit_hit = entry_hit_status(commPtr.value)
1051  val commit_hit = RegNext(can_commit_hit)
1052  val diff_commit_target = RegNext(update_target(commPtr.value)) // TODO: remove this
1053  val commit_stage = RegNext(pred_stage(commPtr.value))
1054  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
1055
1056  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
1057  switch (bpu_ftb_update_stall) {
1058    is (0.U) {
1059      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
1060        bpu_ftb_update_stall := 2.U // 2-cycle stall
1061      }
1062    }
1063    is (2.U) {
1064      bpu_ftb_update_stall := 1.U
1065    }
1066    is (1.U) {
1067      bpu_ftb_update_stall := 0.U
1068    }
1069    is (3.U) {
1070      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
1071    }
1072  }
1073
1074  // TODO: remove this
1075  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1076
1077  io.toBpu.update := DontCare
1078  io.toBpu.update.valid := commit_valid && do_commit
1079  val update = io.toBpu.update.bits
1080  update.false_hit   := commit_hit === h_false_hit
1081  update.pc          := commit_pc_bundle.startAddr
1082  update.meta        := commit_meta.meta
1083  update.cfi_idx     := commit_cfi
1084  update.full_target := commit_target
1085  update.from_stage  := commit_stage
1086  update.spec_info   := commit_spec_meta
1087
1088  val commit_real_hit = commit_hit === h_hit
1089  val update_ftb_entry = update.ftb_entry
1090
1091  val ftbEntryGen = Module(new FTBEntryGen).io
1092  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
1093  ftbEntryGen.old_entry      := commit_ftb_entry
1094  ftbEntryGen.pd             := commit_pd
1095  ftbEntryGen.cfiIndex       := commit_cfi
1096  ftbEntryGen.target         := commit_target
1097  ftbEntryGen.hit            := commit_real_hit
1098  ftbEntryGen.mispredict_vec := commit_mispredict
1099
1100  update_ftb_entry         := ftbEntryGen.new_entry
1101  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
1102  update.mispred_mask      := ftbEntryGen.mispred_mask
1103  update.old_entry         := ftbEntryGen.is_old_entry
1104  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1105  update.br_taken_mask     := ftbEntryGen.taken_mask
1106  update.jmp_taken         := ftbEntryGen.jmp_taken
1107
1108  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1109  // update.full_pred.jalr_target := commit_target
1110  // update.full_pred.hit := true.B
1111  // when (update.full_pred.is_jalr) {
1112  //   update.full_pred.targets.last := commit_target
1113  // }
1114
1115  // ****************************************************************
1116  // *********************** to prefetch ****************************
1117  // ****************************************************************
1118
1119  ftq_pc_mem.io.other_raddrs(0) := DontCare
1120  if(cacheParams.hasPrefetch){
1121    val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1122    val diff_prefetch_addr = WireInit(update_target(prefetchPtr.value)) //TODO: remove this
1123
1124    prefetchPtr := prefetchPtr + io.toPrefetch.req.fire()
1125
1126    ftq_pc_mem.io.other_raddrs(0) := prefetchPtr.value
1127
1128    when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) {
1129      prefetchPtr := bpu_s2_resp.ftq_idx
1130    }
1131
1132    when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) {
1133      prefetchPtr := bpu_s3_resp.ftq_idx
1134      // XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
1135    }
1136
1137
1138    val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send)
1139    val prefetch_addr = Wire(UInt(VAddrBits.W))
1140
1141    when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) {
1142      prefetch_is_to_send := true.B
1143      prefetch_addr := last_cycle_bpu_target
1144      diff_prefetch_addr := last_cycle_bpu_target // TODO: remove this
1145    }.otherwise{
1146      prefetch_addr := RegNext( ftq_pc_mem.io.other_rdatas(0).startAddr)
1147    }
1148    io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send
1149    io.toPrefetch.req.bits.target := prefetch_addr
1150
1151    when(redirectVec.map(r => r.valid).reduce(_||_)){
1152      val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1153      val next = r.ftqIdx + 1.U
1154      prefetchPtr := next
1155    }
1156
1157    // TODO: remove this
1158    // XSError(io.toPrefetch.req.valid && diff_prefetch_addr =/= prefetch_addr,
1159    //         f"\nprefetch_req_target wrong! prefetchPtr: ${prefetchPtr}, prefetch_addr: ${Hexadecimal(prefetch_addr)} diff_prefetch_addr: ${Hexadecimal(diff_prefetch_addr)}\n")
1160
1161
1162    XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n")
1163    XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n")
1164  }
1165  else {
1166    io.toPrefetch.req <> DontCare
1167  }
1168
1169  // ******************************************************************************
1170  // **************************** commit perf counters ****************************
1171  // ******************************************************************************
1172
1173  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
1174  val commit_mispred_mask = commit_mispredict.asUInt
1175  val commit_not_mispred_mask = ~commit_mispred_mask
1176
1177  val commit_br_mask = commit_pd.brMask.asUInt
1178  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
1179  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
1180
1181  val mbpInstrs = commit_inst_mask & commit_cfi_mask
1182
1183  val mbpRights = mbpInstrs & commit_not_mispred_mask
1184  val mbpWrongs = mbpInstrs & commit_mispred_mask
1185
1186  io.bpuInfo.bpRight := PopCount(mbpRights)
1187  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
1188
1189  // Cfi Info
1190  for (i <- 0 until PredictWidth) {
1191    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
1192    val v = commit_state(i) === c_commited
1193    val isBr = commit_pd.brMask(i)
1194    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
1195    val isCfi = isBr || isJmp
1196    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
1197    val misPred = commit_mispredict(i)
1198    // val ghist = commit_spec_meta.ghist.predHist
1199    val histPtr = commit_spec_meta.histPtr
1200    val predCycle = commit_meta.meta(63, 0)
1201    val target = commit_target
1202
1203    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
1204    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
1205    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
1206    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1207    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
1208    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
1209    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
1210  }
1211
1212  val enq = io.fromBpu.resp
1213  val perf_redirect = backendRedirect
1214
1215  XSPerfAccumulate("entry", validEntries)
1216  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
1217  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
1218  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
1219  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
1220
1221  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
1222
1223  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
1224  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
1225  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1226
1227  val from_bpu = io.fromBpu.resp.bits
1228  def in_entry_len_map_gen(resp: BpuToFtqBundle)(stage: String) = {
1229    val entry_len = (resp.last_stage_ftb_entry.getFallThrough(resp.s3.pc) - resp.s3.pc) >> instOffsetBits
1230    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
1231    val entry_len_map = (1 to PredictWidth+1).map(i =>
1232      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.s3.valid)
1233    ).foldLeft(Map[String, UInt]())(_+_)
1234    entry_len_map
1235  }
1236  val s3_entry_len_map = in_entry_len_map_gen(from_bpu)("s3")
1237
1238  val to_ifu = io.toIfu.req.bits
1239
1240
1241
1242  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
1243  val commit_num_inst_map = (1 to PredictWidth).map(i =>
1244    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
1245  ).foldLeft(Map[String, UInt]())(_+_)
1246
1247
1248
1249  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1250  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1251  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1252  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1253
1254
1255  val mbpBRights = mbpRights & commit_br_mask
1256  val mbpJRights = mbpRights & commit_jal_mask
1257  val mbpIRights = mbpRights & commit_jalr_mask
1258  val mbpCRights = mbpRights & commit_call_mask
1259  val mbpRRights = mbpRights & commit_ret_mask
1260
1261  val mbpBWrongs = mbpWrongs & commit_br_mask
1262  val mbpJWrongs = mbpWrongs & commit_jal_mask
1263  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1264  val mbpCWrongs = mbpWrongs & commit_call_mask
1265  val mbpRWrongs = mbpWrongs & commit_ret_mask
1266
1267  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
1268
1269  def pred_stage_map(src: UInt, name: String) = {
1270    (0 until numBpStages).map(i =>
1271      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
1272    ).foldLeft(Map[String, UInt]())(_+_)
1273  }
1274
1275  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
1276  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
1277  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
1278  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
1279  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
1280  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
1281
1282  val update_valid = io.toBpu.update.valid
1283  def u(cond: Bool) = update_valid && cond
1284  val ftb_false_hit = u(update.false_hit)
1285  // assert(!ftb_false_hit)
1286  val ftb_hit = u(commit_hit === h_hit)
1287
1288  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1289  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1290  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1291  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
1292
1293  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1294
1295  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1296  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1297  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1298  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1299  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1300
1301  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
1302  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
1303  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
1304    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
1305  ).foldLeft(Map[String, UInt]())(_+_)
1306  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
1307    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
1308  ).foldLeft(Map[String, UInt]())(_+_)
1309
1310  val ftq_occupancy_map = (0 to FtqSize).map(i =>
1311    f"ftq_has_entry_$i" ->( validEntries === i.U)
1312  ).foldLeft(Map[String, UInt]())(_+_)
1313
1314  val perfCountsMap = Map(
1315    "BpInstr" -> PopCount(mbpInstrs),
1316    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1317    "BpRight"  -> PopCount(mbpRights),
1318    "BpWrong"  -> PopCount(mbpWrongs),
1319    "BpBRight" -> PopCount(mbpBRights),
1320    "BpBWrong" -> PopCount(mbpBWrongs),
1321    "BpJRight" -> PopCount(mbpJRights),
1322    "BpJWrong" -> PopCount(mbpJWrongs),
1323    "BpIRight" -> PopCount(mbpIRights),
1324    "BpIWrong" -> PopCount(mbpIWrongs),
1325    "BpCRight" -> PopCount(mbpCRights),
1326    "BpCWrong" -> PopCount(mbpCWrongs),
1327    "BpRRight" -> PopCount(mbpRRights),
1328    "BpRWrong" -> PopCount(mbpRWrongs),
1329
1330    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1331    "ftb_hit"                      -> PopCount(ftb_hit),
1332    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1333    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1334    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1335    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1336    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1337    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1338    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1339    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1340    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1341    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1342  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++
1343  s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++
1344  mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
1345  correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
1346
1347  for((key, value) <- perfCountsMap) {
1348    XSPerfAccumulate(key, value)
1349  }
1350
1351  // --------------------------- Debug --------------------------------
1352  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1353  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1354  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1355  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1356  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1357    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1358  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1359
1360  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1361  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1362  //       case (((valid, pd), ans), taken) =>
1363  //       Mux(valid && pd.isBr,
1364  //         isWrong ^ Mux(ans.hit.asBool,
1365  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1366  //           !taken),
1367  //         !taken),
1368  //       false.B)
1369  //     }
1370  //   }
1371
1372  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1373  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1374  //       case (((valid, pd), ans), taken) =>
1375  //       Mux(valid && pd.isBr,
1376  //         isWrong ^ Mux(ans.hit.asBool,
1377  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1378  //           !taken),
1379  //         !taken),
1380  //       false.B)
1381  //     }
1382  //   }
1383
1384  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1385  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1386  //       case (((valid, pd), ans), taken) =>
1387  //       Mux(valid && pd.isBr,
1388  //         isWrong ^ (ans.taken.asBool === taken),
1389  //       false.B)
1390  //     }
1391  //   }
1392
1393  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1394  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1395  //       case (((valid, pd), ans), taken) =>
1396  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1397  //         isWrong ^ (!taken),
1398  //           false.B)
1399  //     }
1400  //   }
1401
1402  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1403  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1404  //       case (((valid, pd), ans), taken) =>
1405  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1406  //         isWrong ^ (ans.target === commitEntry.target),
1407  //           false.B)
1408  //     }
1409  //   }
1410
1411  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1412  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1413  //   // btb and ubtb pred jal and jalr as well
1414  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1415  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1416  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1417  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1418
1419  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1420  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1421
1422  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1423  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1424
1425  val perfEvents = Seq(
1426    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1427    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1428    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1429    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1430    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1431    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1432    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1433    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1434    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1435    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1436    ("BpRight                ", PopCount(mbpRights)                                                         ),
1437    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1438    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1439    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1440    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1441    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1442    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1443    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1444    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1445    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1446    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1447    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1448    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1449    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1450  )
1451  generatePerfEvent()
1452}