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