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