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