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