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