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