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