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