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