xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision cd365d4ca1205723617d915c8588e09b1ecb1819)
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 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 getRobFlushPcRead = 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  init_entry.brValids(0) := cfi_is_br
294  init_entry.brOffset(0) := io.cfiIndex.bits
295  init_entry.setByBrTarget(0, io.start_addr, io.target)
296  init_entry.always_taken(0) := cfi_is_br // set to always taken on init
297  init_entry.always_taken(1) := false.B
298  init_entry.jmpOffset := pd.jmpOffset
299  init_entry.jmpValid := new_jmp_is_jal || new_jmp_is_jalr
300  init_entry.setByJmpTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget))
301  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
302  init_entry.pftAddr := Mux(entry_has_jmp, jmpPft, getLower(io.start_addr) + ((FetchWidth*4)>>instOffsetBits).U + Mux(last_br_rvi, 1.U, 0.U))
303  init_entry.carry   := Mux(entry_has_jmp, jmpPft(carryPos-instOffsetBits), io.start_addr(carryPos-1) || (io.start_addr(carryPos-2, instOffsetBits).andR && last_br_rvi))
304  init_entry.isJalr := new_jmp_is_jalr
305  init_entry.isCall := new_jmp_is_call
306  init_entry.isRet  := new_jmp_is_ret
307  init_entry.last_is_rvc := Mux(entry_has_jmp, pd.rvcMask(pd.jmpOffset), pd.rvcMask.last)
308
309  init_entry.oversize := last_br_rvi || last_jmp_rvi
310
311  // if hit, check whether a new cfi(only br is possible) is detected
312  val oe = io.old_entry
313  val br_recorded_vec = VecInit((oe.brValids zip oe.brOffset).map {
314    case (v, off) => v && (off === io.cfiIndex.bits)
315  })
316  val br_recorded = br_recorded_vec.asUInt.orR
317  val is_new_br = cfi_is_br && !br_recorded
318  val br_full = oe.brValids.asUInt.andR // all slots have brs
319  val new_br_offset = io.cfiIndex.bits
320  // vec(i) means new br will be inserted BEFORE old br(i)
321  val new_br_insert_onehot = VecInit((0 until numBr).map{
322    i => i match {
323      case 0 => !oe.brValids(0) || new_br_offset < oe.brOffset(0)
324      case idx => oe.brValids(idx-1) && new_br_offset > oe.brOffset(idx-1) &&
325        (!oe.brValids(idx) || new_br_offset < oe.brOffset(idx))
326    }
327  })
328
329  val old_entry_modified = WireInit(io.old_entry)
330  val (new_br_lower, new_br_tar_stat) = old_entry_modified.getBrLowerStatByTarget(io.start_addr, io.target)
331  for (i <- 0 until numBr) {
332    old_entry_modified.brOffset(i)  :=  Mux(new_br_insert_onehot(i), new_br_offset,
333                                          Mux(oe.brOffset(i) < new_br_offset, oe.brOffset(i),
334                                            (if (i != 0) oe.brOffset(i-1) else oe.brOffset(i))))
335    old_entry_modified.brLowers(i) :=  Mux(new_br_insert_onehot(i), new_br_lower,
336                                          Mux(oe.brOffset(i) < new_br_offset, oe.brLowers(i),
337                                            (if (i != 0) oe.brLowers(i-1) else oe.brLowers(i))))
338    old_entry_modified.brTarStats(i) := Mux(new_br_insert_onehot(i), new_br_tar_stat,
339                                          Mux(oe.brOffset(i) < new_br_offset, oe.brTarStats(i),
340                                            (if (i != 0) oe.brTarStats(i-1) else oe.brTarStats(i))))
341    old_entry_modified.always_taken(i) := Mux(new_br_insert_onehot(i), true.B,
342                                            Mux(oe.brOffset(i) < new_br_offset, false.B,
343                                              (if (i != 0) oe.always_taken(i-1) else oe.always_taken(i))))
344  }
345  old_entry_modified.brValids := VecInit((oe.brValids zip new_br_insert_onehot).map{case (v1, v2) => v1 || v2})
346
347  // in this case, pft_addr should be the addrs of the last br in packet
348  val pft_need_to_change = is_new_br && br_full
349  // it should either be the given last br or the new br
350  when (pft_need_to_change) {
351    val new_pft_offset = Mux(new_br_insert_onehot.asUInt.orR, oe.brOffset.last, new_br_offset)
352    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
353    old_entry_modified.last_is_rvc := pd.rvcMask(new_pft_offset - 1.U) // TODO: fix this
354    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
355    old_entry_modified.oversize := false.B
356    old_entry_modified.jmpValid := false.B
357    old_entry_modified.isCall := false.B
358    old_entry_modified.isRet := false.B
359  }
360
361  val old_entry_jmp_target_modified = WireInit(oe)
362  val old_target = oe.getJmpTarget(io.start_addr)
363  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) // TODO: pass full jalr target
364  when (jalr_target_modified) {
365    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
366    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
367  }
368
369  val old_entry_always_taken = WireInit(oe)
370  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
371  for (i <- 0 until numBr) {
372    old_entry_always_taken.always_taken(i) :=
373      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
374    always_taken_modified_vec(i) := oe.always_taken(i) && !(io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i))
375  }
376  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
377
378
379
380  val derived_from_old_entry =
381    Mux(is_new_br, old_entry_modified,
382      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
383
384
385  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
386
387  io.new_br_insert_pos := new_br_insert_onehot
388  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
389    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
390  })
391  for (i <- 0 until numBr) {
392    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
393  }
394  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
395
396  // for perf counters
397  io.is_init_entry := !hit
398  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
399  io.is_new_br := hit && is_new_br
400  io.is_jalr_target_modified := hit && jalr_target_modified
401  io.is_always_taken_modified := hit && always_taken_modified
402  io.is_br_full := hit && is_new_br && br_full
403}
404
405class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
406  with HasBackendRedirectInfo with BPUUtils with HasBPUConst {
407  val io = IO(new Bundle {
408    val fromBpu = Flipped(new BpuToFtqIO)
409    val fromIfu = Flipped(new IfuToFtqIO)
410    val fromBackend = Flipped(new CtrlToFtqIO)
411
412    val toBpu = new FtqToBpuIO
413    val toIfu = new FtqToIfuIO
414    val toBackend = new FtqToCtrlIO
415
416    val bpuInfo = new Bundle {
417      val bpRight = Output(UInt(XLEN.W))
418      val bpWrong = Output(UInt(XLEN.W))
419    }
420  })
421  io.bpuInfo := DontCare
422
423  val robFlush = io.fromBackend.robFlush
424  val stage2Redirect = io.fromBackend.stage2Redirect
425  val stage3Redirect = io.fromBackend.stage3Redirect
426
427  val stage2Flush = stage2Redirect.valid || robFlush.valid
428  val backendFlush = stage2Flush || RegNext(stage2Flush)
429  val ifuFlush = Wire(Bool())
430
431  val flush = stage2Flush || RegNext(stage2Flush)
432
433  val allowBpuIn, allowToIfu = WireInit(false.B)
434  val flushToIfu = !allowToIfu
435  allowBpuIn := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
436  allowToIfu := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid
437
438  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
439  val validEntries = distanceBetween(bpuPtr, commPtr)
440
441  // **********************************************************************
442  // **************************** enq from bpu ****************************
443  // **********************************************************************
444  val new_entry_ready = validEntries < FtqSize.U
445  io.fromBpu.resp.ready := new_entry_ready
446
447  val bpu_s2_resp = io.fromBpu.resp.bits.s2
448  val bpu_s3_resp = io.fromBpu.resp.bits.s3
449  val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
450  val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
451
452  io.toBpu.enq_ptr := bpuPtr
453  val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1
454  val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
455
456  val bpu_in_resp = WireInit(io.fromBpu.resp.bits.selectedResp)
457  val bpu_in_stage = WireInit(io.fromBpu.resp.bits.selectedRespIdx)
458  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
459  val bpu_in_resp_idx = bpu_in_resp_ptr.value
460
461  // read ports:                            jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate
462  val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1))
463  // resp from uBTB
464  ftq_pc_mem.io.wen(0) := bpu_in_fire
465  ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx
466  ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp)
467
468  //                                                            ifuRedirect + backendRedirect + commit
469  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1))
470  // these info is intended to enq at the last stage of bpu
471  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
472  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
473  ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage)
474
475  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
476  // these info is intended to enq at the last stage of bpu
477  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid
478  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
479  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta
480  //                                                            ifuRedirect + backendRedirect + commit
481  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1))
482  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid
483  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
484  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry
485
486
487  // multi-write
488  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W)))
489  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
490  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
491  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
492
493  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
494  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
495    VecInit(Seq.fill(PredictWidth)(c_invalid))
496  }))
497
498  val f_to_send :: f_sent :: Nil = Enum(2)
499  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
500
501  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
502  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
503
504
505  when (bpu_in_fire) {
506    entry_fetch_status(bpu_in_resp_idx) := f_to_send
507    commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid))
508    cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.genCfiIndex
509    mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
510    update_target(bpu_in_resp_idx) := bpu_in_resp.target
511    pred_stage(bpu_in_resp_idx) := bpu_in_stage
512  }
513
514  bpuPtr := bpuPtr + enq_fire
515  ifuPtr := ifuPtr + io.toIfu.req.fire
516
517  // only use ftb result to assign hit status
518  when (bpu_s2_resp.valid) {
519    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.preds.hit, h_hit, h_not_hit)
520  }
521
522
523  io.toIfu.flushFromBpu.s2.valid := bpu_s2_resp.valid && bpu_s2_resp.hasRedirect
524  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
525  when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) {
526    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
527    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
528    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
529      ifuPtr := bpu_s2_resp.ftq_idx
530    }
531  }
532
533  io.toIfu.flushFromBpu.s3.valid := bpu_s3_resp.valid && bpu_s3_resp.hasRedirect
534  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
535  when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) {
536    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
537    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
538    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
539      ifuPtr := bpu_s3_resp.ftq_idx
540    }
541    XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
542  }
543
544  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
545
546  // ****************************************************************
547  // **************************** to ifu ****************************
548  // ****************************************************************
549  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire)
550  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
551  val last_cycle_bpu_in = RegNext(bpu_in_fire)
552  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
553
554  // read pc and target
555  ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value
556  ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value
557
558  val toIfuReq = Wire(chiselTypeOf(io.toIfu.req))
559
560  toIfuReq.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr
561  toIfuReq.bits.ftqIdx := ifuPtr
562  toIfuReq.bits.target := update_target(ifuPtr.value)
563  toIfuReq.bits.ftqOffset := cfiIndex_vec(ifuPtr.value)
564  toIfuReq.bits.fallThruError  := false.B
565
566  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
567    toIfuReq.bits.fromFtqPcBundle(bpu_in_bypass_buf)
568  }.elsewhen (last_cycle_to_ifu_fire) {
569    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.last)
570  }.otherwise {
571    toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.init.last)
572  }
573
574  io.toIfu.req <> toIfuReq
575
576  // when fall through is smaller in value than start address, there must be a false hit
577  when (toIfuReq.bits.fallThroughError() && entry_hit_status(ifuPtr.value) === h_hit) {
578    when (io.toIfu.req.fire &&
579      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
580      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
581    ) {
582      entry_hit_status(ifuPtr.value) := h_false_hit
583      XSDebug(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
584    }
585    io.toIfu.req.bits.fallThruAddr   := toIfuReq.bits.startAddr + (FetchWidth*4).U
586    io.toIfu.req.bits.fallThruError  := true.B
587    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr)
588  }
589
590  val ifu_req_should_be_flushed =
591    io.toIfu.flushFromBpu.shouldFlushByStage2(toIfuReq.bits.ftqIdx) ||
592    io.toIfu.flushFromBpu.shouldFlushByStage3(toIfuReq.bits.ftqIdx)
593
594  when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
595    entry_fetch_status(ifuPtr.value) := f_sent
596  }
597
598
599  // *********************************************************************
600  // **************************** wb from ifu ****************************
601  // *********************************************************************
602  val pdWb = io.fromIfu.pdWb
603  val pds = pdWb.bits.pd
604  val ifu_wb_valid = pdWb.valid
605  val ifu_wb_idx = pdWb.bits.ftqIdx.value
606  // read ports:                                                         commit update
607  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
608  ftq_pd_mem.io.wen(0) := ifu_wb_valid
609  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
610  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
611
612  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
613  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
614  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
615  val pd_reg       = RegEnable(pds,             enable = pdWb.valid)
616  val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid)
617  val wb_idx_reg   = RegEnable(ifu_wb_idx,      enable = pdWb.valid)
618
619  when (ifu_wb_valid) {
620    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
621      case (v, inRange) => v && inRange
622    })
623    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
624      case (qe, v) => when (v) { qe := c_valid }
625    }
626  }
627
628  ifuWbPtr := ifuWbPtr + ifu_wb_valid
629
630  ftb_entry_mem.io.raddr.head := ifu_wb_idx
631  val has_false_hit = WireInit(false.B)
632  when (RegNext(hit_pd_valid)) {
633    // check for false hit
634    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
635    // we check cfis that bpu predicted
636    val br_false_hit = (pred_ftb_entry.brValids zip pred_ftb_entry.brOffset).map{
637      case (v, offset) => v && !(pd_reg(offset).valid && pd_reg(offset).isBr)
638    }.reduce(_||_)
639
640    val jmpOffset = pred_ftb_entry.jmpOffset
641    val jmp_pd = pd_reg(jmpOffset)
642    val jal_false_hit = pred_ftb_entry.jmpValid &&
643      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
644       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
645       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
646       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
647      )
648
649    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
650    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
651
652    // assert(!has_false_hit)
653  }
654
655  when (has_false_hit) {
656    entry_hit_status(wb_idx_reg) := h_false_hit
657  }
658
659
660  // **********************************************************************
661  // **************************** backend read ****************************
662  // **********************************************************************
663
664  // pc reads
665  for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) {
666    ftq_pc_mem.io.raddr(i) := req.ptr.value
667    req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset))
668  }
669  // target read
670  io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value))
671
672  // *******************************************************************************
673  // **************************** redirect from backend ****************************
674  // *******************************************************************************
675
676  // redirect read cfiInfo, couples to redirectGen s2
677  ftq_redirect_sram.io.ren.init.last := io.fromBackend.stage2Redirect.valid
678  ftq_redirect_sram.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
679
680  ftb_entry_mem.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value
681
682  val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last
683  val fromBackendRedirect = WireInit(io.fromBackend.stage3Redirect)
684  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
685  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
686
687  val r_ftb_entry = ftb_entry_mem.io.rdata.init.last
688  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
689
690  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
691    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
692      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
693      !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1)))
694
695    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
696        !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1)))
697  }.otherwise {
698    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
699    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
700  }
701
702
703  // ***************************************************************************
704  // **************************** redirect from ifu ****************************
705  // ***************************************************************************
706  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect)))
707  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
708  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
709  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
710  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
711
712  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
713  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
714  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
715  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
716  ifuRedirectCfiUpdate.target := pdWb.bits.target
717  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
718  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
719
720  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect)))
721  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
722  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
723
724  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
725  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
726
727  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
728
729  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
730  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
731  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) {
732    toBpuCfi.target := toBpuCfi.rasEntry.retAddr
733  }
734
735  // *********************************************************************
736  // **************************** wb from exu ****************************
737  // *********************************************************************
738
739  def extractRedirectInfo(wb: Valid[Redirect]) = {
740    val ftqIdx = wb.bits.ftqIdx.value
741    val ftqOffset = wb.bits.ftqOffset
742    val taken = wb.bits.cfiUpdate.taken
743    val mispred = wb.bits.cfiUpdate.isMisPred
744    (wb.valid, ftqIdx, ftqOffset, taken, mispred)
745  }
746
747  // fix mispredict entry
748  val lastIsMispredict = RegNext(
749    stage2Redirect.valid && stage2Redirect.bits.level === RedirectLevel.flushAfter, init = false.B
750  )
751
752  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
753    val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
754    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
755    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
756    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
757      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
758    }
759    when (cfiIndex_bits_wen) {
760      cfiIndex_vec(r_idx).bits := r_offset
761    }
762    update_target(r_idx) := redirect.bits.cfiUpdate.target
763    if (isBackend) {
764      mispredict_vec(r_idx)(r_offset) := r_mispred
765    }
766  }
767
768  when(stage3Redirect.valid && lastIsMispredict) {
769    updateCfiInfo(stage3Redirect)
770  }.elsewhen (ifuRedirectToBpu.valid) {
771    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
772  }
773
774  // ***********************************************************************************
775  // **************************** flush ptr and state queue ****************************
776  // ***********************************************************************************
777
778  class RedirectInfo extends Bundle {
779    val valid = Bool()
780    val ftqIdx = new FtqPtr
781    val ftqOffset = UInt(4.W)
782    val flushItSelf = Bool()
783    def apply(redirect: Valid[Redirect]) = {
784      this.valid := redirect.valid
785      this.ftqIdx := redirect.bits.ftqIdx
786      this.ftqOffset := redirect.bits.ftqOffset
787      this.flushItSelf := RedirectLevel.flushItself(redirect.bits.level)
788      this
789    }
790  }
791  val redirectVec = Wire(Vec(3, new RedirectInfo))
792  val robRedirect = robFlush
793
794  redirectVec.zip(Seq(robRedirect, stage2Redirect, fromIfuRedirect)).map {
795    case (ve, r) => ve(r)
796  }
797
798  // when redirect, we should reset ptrs and status queues
799  when(redirectVec.map(r => r.valid).reduce(_||_)){
800    val r = PriorityMux(redirectVec.map(r => (r.valid -> r)))
801    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
802    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, r.flushItSelf)
803    val next = idx + 1.U
804    bpuPtr := next
805    ifuPtr := next
806    ifuWbPtr := next
807    when (notIfu) {
808      commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) =>
809        when(i.U > offset || i.U === offset && flushItSelf){
810          s := c_invalid
811        }
812      })
813    }
814  }
815
816  // only the valid bit is actually needed
817  io.toIfu.redirect := DontCare
818  io.toIfu.redirect.valid := stage2Flush
819
820  // commit
821  for (c <- io.fromBackend.rob_commits) {
822    when(c.valid) {
823      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
824      // TODO: remove this
825      // For instruction fusions, we also update the next instruction
826      when (c.bits.commitType === 4.U) {
827        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
828      }.elsewhen(c.bits.commitType === 5.U) {
829        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
830      }.elsewhen(c.bits.commitType === 6.U) {
831        val index = (c.bits.ftqIdx + 1.U).value
832        commitStateQueue(index)(0) := c_commited
833      }.elsewhen(c.bits.commitType === 7.U) {
834        val index = (c.bits.ftqIdx + 1.U).value
835        commitStateQueue(index)(1) := c_commited
836      }
837    }
838  }
839
840  // ****************************************************************
841  // **************************** to bpu ****************************
842  // ****************************************************************
843
844  io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
845
846  val may_have_stall_from_bpu = RegInit(false.B)
847  val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
848    Cat(commitStateQueue(commPtr.value).map(s => {
849      s === c_invalid || s === c_commited
850    })).andR()
851
852  // commit reads
853  ftq_pc_mem.io.raddr.last := commPtr.value
854  val commit_pc_bundle = ftq_pc_mem.io.rdata.last
855  ftq_pd_mem.io.raddr.last := commPtr.value
856  val commit_pd = ftq_pd_mem.io.rdata.last
857  ftq_redirect_sram.io.ren.last := canCommit
858  ftq_redirect_sram.io.raddr.last := commPtr.value
859  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
860  ftq_meta_1r_sram.io.ren(0) := canCommit
861  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
862  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
863  ftb_entry_mem.io.raddr.last := commPtr.value
864  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
865
866  // need one cycle to read mem and srams
867  val do_commit_ptr = RegNext(commPtr)
868  val do_commit = RegNext(canCommit, init=false.B)
869  when (canCommit) { commPtr := commPtr + 1.U }
870  val commit_state = RegNext(commitStateQueue(commPtr.value))
871  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
872  when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
873    can_commit_cfi.valid := false.B
874  }
875  val commit_cfi = RegNext(can_commit_cfi)
876
877  val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
878    case (mis, state) => mis && state === c_commited
879  })
880  val can_commit_hit = entry_hit_status(commPtr.value)
881  val commit_hit = RegNext(can_commit_hit)
882  val commit_target = RegNext(update_target(commPtr.value))
883  val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken
884
885  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
886  may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu
887
888  io.toBpu.update := DontCare
889  io.toBpu.update.valid := commit_valid && do_commit
890  val update = io.toBpu.update.bits
891  update.false_hit   := commit_hit === h_false_hit
892  update.pc          := commit_pc_bundle.startAddr
893  update.preds.hit   := commit_hit === h_hit || commit_hit === h_false_hit
894  update.meta        := commit_meta.meta
895  update.full_target := commit_target
896  update.fromFtqRedirectSram(commit_spec_meta)
897
898  val commit_real_hit = commit_hit === h_hit
899  val update_ftb_entry = update.ftb_entry
900
901  val ftbEntryGen = Module(new FTBEntryGen).io
902  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
903  ftbEntryGen.old_entry      := commit_ftb_entry
904  ftbEntryGen.pd             := commit_pd
905  ftbEntryGen.cfiIndex       := commit_cfi
906  ftbEntryGen.target         := commit_target
907  ftbEntryGen.hit            := commit_real_hit
908  ftbEntryGen.mispredict_vec := commit_mispredict
909
910  update_ftb_entry         := ftbEntryGen.new_entry
911  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
912  update.mispred_mask      := ftbEntryGen.mispred_mask
913  update.old_entry         := ftbEntryGen.is_old_entry
914  update.preds.taken_mask  := ftbEntryGen.taken_mask
915
916  // ******************************************************************************
917  // **************************** commit perf counters ****************************
918  // ******************************************************************************
919
920  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
921  val commit_mispred_mask = commit_mispredict.asUInt
922  val commit_not_mispred_mask = ~commit_mispred_mask
923
924  val commit_br_mask = commit_pd.brMask.asUInt
925  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
926  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
927
928  val mbpInstrs = commit_inst_mask & commit_cfi_mask
929
930  val mbpRights = mbpInstrs & commit_not_mispred_mask
931  val mbpWrongs = mbpInstrs & commit_mispred_mask
932
933  io.bpuInfo.bpRight := PopCount(mbpRights)
934  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
935
936  // Cfi Info
937  for (i <- 0 until PredictWidth) {
938    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
939    val v = commit_state(i) === c_commited
940    val isBr = commit_pd.brMask(i)
941    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
942    val isCfi = isBr || isJmp
943    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
944    val misPred = commit_mispredict(i)
945    val ghist = commit_spec_meta.ghist.predHist
946    val predCycle = commit_meta.meta(63, 0)
947    val target = commit_target
948
949    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
950    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
951    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
952    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
953    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${Hexadecimal(ghist)}) " +
954    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
955    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
956  }
957
958  val enq = io.fromBpu.resp
959  val perf_redirect = io.fromBackend.stage2Redirect
960
961  XSPerfAccumulate("entry", validEntries)
962  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
963  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
964  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
965  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
966
967  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
968
969  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
970  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
971  XSPerfAccumulate("bpu_to_ftq_bubble", bpuPtr === ifuPtr)
972
973  val from_bpu = io.fromBpu.resp.bits
974  def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = {
975    val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits
976    val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U)
977    val entry_len_map = (1 to PredictWidth+1).map(i =>
978      f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid)
979    ).foldLeft(Map[String, UInt]())(_+_)
980    entry_len_map
981  }
982  val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1")
983  val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2")
984  val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3")
985
986  val to_ifu = io.toIfu.req.bits
987  val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits
988  val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U)
989  val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i =>
990    f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire)
991  ).foldLeft(Map[String, UInt]())(_+_)
992
993
994
995  val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U)
996  val commit_num_inst_map = (1 to PredictWidth).map(i =>
997    f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit)
998  ).foldLeft(Map[String, UInt]())(_+_)
999
1000
1001
1002  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
1003  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
1004  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
1005  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
1006
1007
1008  val mbpBRights = mbpRights & commit_br_mask
1009  val mbpJRights = mbpRights & commit_jal_mask
1010  val mbpIRights = mbpRights & commit_jalr_mask
1011  val mbpCRights = mbpRights & commit_call_mask
1012  val mbpRRights = mbpRights & commit_ret_mask
1013
1014  val mbpBWrongs = mbpWrongs & commit_br_mask
1015  val mbpJWrongs = mbpWrongs & commit_jal_mask
1016  val mbpIWrongs = mbpWrongs & commit_jalr_mask
1017  val mbpCWrongs = mbpWrongs & commit_call_mask
1018  val mbpRWrongs = mbpWrongs & commit_ret_mask
1019
1020  val update_valid = io.toBpu.update.valid
1021  def u(cond: Bool) = update_valid && cond
1022  val ftb_false_hit = u(update.false_hit)
1023  // assert(!ftb_false_hit)
1024  val ftb_hit = u(commit_hit === h_hit)
1025
1026  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1027  val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid
1028  val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0)
1029  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid
1030
1031  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
1032
1033  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
1034  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1035  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
1036  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
1037  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
1038
1039  val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits
1040  val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U)
1041  val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i =>
1042    f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry)
1043  ).foldLeft(Map[String, UInt]())(_+_)
1044  val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i =>
1045    f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry)
1046  ).foldLeft(Map[String, UInt]())(_+_)
1047
1048  val ftq_occupancy_map = (0 to FtqSize).map(i =>
1049    f"ftq_has_entry_$i" ->( validEntries === i.U)
1050  ).foldLeft(Map[String, UInt]())(_+_)
1051
1052  val perfCountsMap = Map(
1053    "BpInstr" -> PopCount(mbpInstrs),
1054    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
1055    "BpRight"  -> PopCount(mbpRights),
1056    "BpWrong"  -> PopCount(mbpWrongs),
1057    "BpBRight" -> PopCount(mbpBRights),
1058    "BpBWrong" -> PopCount(mbpBWrongs),
1059    "BpJRight" -> PopCount(mbpJRights),
1060    "BpJWrong" -> PopCount(mbpJWrongs),
1061    "BpIRight" -> PopCount(mbpIRights),
1062    "BpIWrong" -> PopCount(mbpIWrongs),
1063    "BpCRight" -> PopCount(mbpCRights),
1064    "BpCWrong" -> PopCount(mbpCWrongs),
1065    "BpRRight" -> PopCount(mbpRRights),
1066    "BpRWrong" -> PopCount(mbpRWrongs),
1067
1068    "ftb_false_hit"                -> PopCount(ftb_false_hit),
1069    "ftb_hit"                      -> PopCount(ftb_hit),
1070    "ftb_new_entry"                -> PopCount(ftb_new_entry),
1071    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
1072    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
1073    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
1074    "ftb_old_entry"                -> PopCount(ftb_old_entry),
1075    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
1076    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
1077    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
1078    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
1079    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1080  ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++
1081  s2_entry_len_map ++ s3_entry_len_map ++
1082  to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map
1083
1084  for((key, value) <- perfCountsMap) {
1085    XSPerfAccumulate(key, value)
1086  }
1087
1088  // --------------------------- Debug --------------------------------
1089  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
1090  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
1091  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
1092  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
1093  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
1094    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
1095  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
1096
1097  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1098  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1099  //       case (((valid, pd), ans), taken) =>
1100  //       Mux(valid && pd.isBr,
1101  //         isWrong ^ Mux(ans.hit.asBool,
1102  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1103  //           !taken),
1104  //         !taken),
1105  //       false.B)
1106  //     }
1107  //   }
1108
1109  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1110  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1111  //       case (((valid, pd), ans), taken) =>
1112  //       Mux(valid && pd.isBr,
1113  //         isWrong ^ Mux(ans.hit.asBool,
1114  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
1115  //           !taken),
1116  //         !taken),
1117  //       false.B)
1118  //     }
1119  //   }
1120
1121  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1122  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1123  //       case (((valid, pd), ans), taken) =>
1124  //       Mux(valid && pd.isBr,
1125  //         isWrong ^ (ans.taken.asBool === taken),
1126  //       false.B)
1127  //     }
1128  //   }
1129
1130  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1131  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1132  //       case (((valid, pd), ans), taken) =>
1133  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
1134  //         isWrong ^ (!taken),
1135  //           false.B)
1136  //     }
1137  //   }
1138
1139  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
1140  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
1141  //       case (((valid, pd), ans), taken) =>
1142  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
1143  //         isWrong ^ (ans.target === commitEntry.target),
1144  //           false.B)
1145  //     }
1146  //   }
1147
1148  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
1149  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
1150  //   // btb and ubtb pred jal and jalr as well
1151  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
1152  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
1153  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
1154  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
1155
1156  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
1157  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
1158
1159  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
1160  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
1161  val perfinfo = IO(new Bundle(){
1162    val perfEvents = Output(new PerfEventsBundle(22))
1163  })
1164  val perfEvents = Seq(
1165    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1166    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1167    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1168    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1169    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1170    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1171    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1172    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1173    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1174    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1175    ("BpRight                ", PopCount(mbpRights)                                                         ),
1176    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1177    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1178    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1179    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1180    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1181    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1182    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1183    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1184    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1185    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1186    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1187    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1188    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1189  )
1190
1191  for (((perf_out,(perf_name,perf)),i) <- perfinfo.perfEvents.perf_events.zip(perfEvents).zipWithIndex) {
1192    perf_out.incr_step := RegNext(perf)
1193  }
1194}
1195