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