xref: /XiangShan/src/main/scala/xiangshan/frontend/FrontendBundle.scala (revision c5c5edaea014f7e6e45a66616bc0b74d8d7e0b8d)
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***************************************************************************************/
16package xiangshan.frontend
17
18import chipsalliance.rocketchip.config.Parameters
19import chisel3._
20import chisel3.util._
21import chisel3.experimental.chiselName
22import xiangshan._
23import xiangshan.frontend.icache.HasICacheParameters
24import utils._
25import scala.math._
26
27@chiselName
28class FetchRequestBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters {
29
30  //fast path: Timing critical
31  val startAddr       = UInt(VAddrBits.W)
32  val nextlineStart   = UInt(VAddrBits.W)
33  val nextStartAddr   = UInt(VAddrBits.W)
34  //slow path
35  val ftqIdx          = new FtqPtr
36  val ftqOffset       = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
37
38  def crossCacheline =  startAddr(blockOffBits - 1) === 1.U
39
40  def fromFtqPcBundle(b: Ftq_RF_Components) = {
41    this.startAddr := b.startAddr
42    this.nextlineStart := b.nextLineAddr
43    when (b.fallThruError) {
44      val nextBlockHigherTemp = Mux(startAddr(log2Ceil(PredictWidth)+instOffsetBits), b.startAddr, b.nextLineAddr)
45      val nextBlockHigher = nextBlockHigherTemp(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
46      this.nextStartAddr :=
47        Cat(nextBlockHigher,
48          startAddr(log2Ceil(PredictWidth)+instOffsetBits) ^ 1.U(1.W),
49          startAddr(log2Ceil(PredictWidth)+instOffsetBits-1, instOffsetBits),
50          0.U(instOffsetBits.W)
51        )
52    }
53    this
54  }
55  override def toPrintable: Printable = {
56    p"[start] ${Hexadecimal(startAddr)} [next] ${Hexadecimal(nextlineStart)}" +
57      p"[tgt] ${Hexadecimal(nextStartAddr)} [ftqIdx] $ftqIdx [jmp] v:${ftqOffset.valid}" +
58      p" offset: ${ftqOffset.bits}\n"
59  }
60}
61
62class FtqToICacheRequestBundle(implicit p: Parameters)extends XSBundle with HasICacheParameters{
63  val startAddr       = UInt(VAddrBits.W)
64  val nextlineStart   = UInt(VAddrBits.W)
65  def crossCacheline =  startAddr(blockOffBits - 1) === 1.U
66  def fromFtqPcBundle(b: Ftq_RF_Components) = {
67    this.startAddr := b.startAddr
68    this.nextlineStart := b.nextLineAddr
69    this
70  }
71}
72
73
74class PredecodeWritebackBundle(implicit p:Parameters) extends XSBundle {
75  val pc           = Vec(PredictWidth, UInt(VAddrBits.W))
76  val pd           = Vec(PredictWidth, new PreDecodeInfo) // TODO: redefine Predecode
77  val ftqIdx       = new FtqPtr
78  val ftqOffset    = UInt(log2Ceil(PredictWidth).W)
79  val misOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
80  val cfiOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
81  val target       = UInt(VAddrBits.W)
82  val jalTarget    = UInt(VAddrBits.W)
83  val instrRange   = Vec(PredictWidth, Bool())
84}
85
86// Ftq send req to Prefetch
87class PrefetchRequest(implicit p:Parameters) extends XSBundle {
88  val target          = UInt(VAddrBits.W)
89}
90
91class FtqPrefechBundle(implicit p:Parameters) extends XSBundle {
92  val req = DecoupledIO(new PrefetchRequest)
93}
94
95class FetchToIBuffer(implicit p: Parameters) extends XSBundle {
96  val instrs    = Vec(PredictWidth, UInt(32.W))
97  val valid     = UInt(PredictWidth.W)
98  val enqEnable = UInt(PredictWidth.W)
99  val pd        = Vec(PredictWidth, new PreDecodeInfo)
100  val pc        = Vec(PredictWidth, UInt(VAddrBits.W))
101  val foldpc    = Vec(PredictWidth, UInt(MemPredPCWidth.W))
102  val ftqPtr       = new FtqPtr
103  val ftqOffset    = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
104  val ipf          = Vec(PredictWidth, Bool())
105  val acf          = Vec(PredictWidth, Bool())
106  val crossPageIPFFix = Vec(PredictWidth, Bool())
107  val triggered    = Vec(PredictWidth, new TriggerCf)
108}
109
110// class BitWiseUInt(val width: Int, val init: UInt) extends Module {
111//   val io = IO(new Bundle {
112//     val set
113//   })
114// }
115// Move from BPU
116abstract class GlobalHistory(implicit p: Parameters) extends XSBundle with HasBPUConst {
117  def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): GlobalHistory
118}
119
120class ShiftingGlobalHistory(implicit p: Parameters) extends GlobalHistory {
121  val predHist = UInt(HistoryLength.W)
122
123  def update(shift: UInt, taken: Bool, hist: UInt = this.predHist): ShiftingGlobalHistory = {
124    val g = Wire(new ShiftingGlobalHistory)
125    g.predHist := (hist << shift) | taken
126    g
127  }
128
129  def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): ShiftingGlobalHistory = {
130    require(br_valids.length == numBr)
131    require(real_taken_mask.length == numBr)
132    val last_valid_idx = PriorityMux(
133      br_valids.reverse :+ true.B,
134      (numBr to 0 by -1).map(_.U(log2Ceil(numBr+1).W))
135    )
136    val first_taken_idx = PriorityEncoder(false.B +: real_taken_mask)
137    val smaller = Mux(last_valid_idx < first_taken_idx,
138      last_valid_idx,
139      first_taken_idx
140    )
141    val shift = smaller
142    val taken = real_taken_mask.reduce(_||_)
143    update(shift, taken, this.predHist)
144  }
145
146  // static read
147  def read(n: Int): Bool = predHist.asBools()(n)
148
149  final def === (that: ShiftingGlobalHistory): Bool = {
150    predHist === that.predHist
151  }
152
153  final def =/= (that: ShiftingGlobalHistory): Bool = !(this === that)
154}
155
156// circular global history pointer
157class CGHPtr(implicit p: Parameters) extends CircularQueuePtr[CGHPtr](
158  p => p(XSCoreParamsKey).HistoryLength
159){
160}
161
162object CGHPtr {
163  def apply(f: Bool, v: UInt)(implicit p: Parameters): CGHPtr = {
164    val ptr = Wire(new CGHPtr)
165    ptr.flag := f
166    ptr.value := v
167    ptr
168  }
169  def inverse(ptr: CGHPtr)(implicit p: Parameters): CGHPtr = {
170    apply(!ptr.flag, ptr.value)
171  }
172}
173
174class CircularGlobalHistory(implicit p: Parameters) extends GlobalHistory {
175  val buffer = Vec(HistoryLength, Bool())
176  type HistPtr = UInt
177  def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): CircularGlobalHistory = {
178    this
179  }
180}
181
182class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(implicit p: Parameters)
183  extends XSBundle with HasBPUConst {
184  require(compLen >= 1)
185  require(len > 0)
186  // require(folded_len <= len)
187  require(compLen >= max_update_num)
188  val folded_hist = UInt(compLen.W)
189
190  def need_oldest_bits = len > compLen
191  def info = (len, compLen)
192  def oldest_bit_to_get_from_ghr = (0 until max_update_num).map(len - _ - 1)
193  def oldest_bit_pos_in_folded = oldest_bit_to_get_from_ghr map (_ % compLen)
194  def oldest_bit_wrap_around = oldest_bit_to_get_from_ghr map (_ / compLen > 0)
195  def oldest_bit_start = oldest_bit_pos_in_folded.head
196
197  def get_oldest_bits_from_ghr(ghr: Vec[Bool], histPtr: CGHPtr) = {
198    // TODO: wrap inc for histPtr value
199    oldest_bit_to_get_from_ghr.map(i => ghr((histPtr + (i+1).U).value))
200  }
201
202  def circular_shift_left(src: UInt, shamt: Int) = {
203    val srcLen = src.getWidth
204    val src_doubled = Cat(src, src)
205    val shifted = src_doubled(srcLen*2-1-shamt, srcLen-shamt)
206    shifted
207  }
208
209  // slow path, read bits from ghr
210  def update(ghr: Vec[Bool], histPtr: CGHPtr, num: Int, taken: Bool): FoldedHistory = {
211    val oldest_bits = VecInit(get_oldest_bits_from_ghr(ghr, histPtr))
212    update(oldest_bits, num, taken)
213  }
214
215
216  // fast path, use pre-read oldest bits
217  def update(ob: Vec[Bool], num: Int, taken: Bool): FoldedHistory = {
218    // do xors for several bitsets at specified bits
219    def bitsets_xor(len: Int, bitsets: Seq[Seq[Tuple2[Int, Bool]]]) = {
220      val res = Wire(Vec(len, Bool()))
221      // println(f"num bitsets: ${bitsets.length}")
222      // println(f"bitsets $bitsets")
223      val resArr = Array.fill(len)(List[Bool]())
224      for (bs <- bitsets) {
225        for ((n, b) <- bs) {
226          resArr(n) = b :: resArr(n)
227        }
228      }
229      // println(f"${resArr.mkString}")
230      // println(f"histLen: ${this.len}, foldedLen: $folded_len")
231      for (i <- 0 until len) {
232        // println(f"bit[$i], ${resArr(i).mkString}")
233        if (resArr(i).length > 2) {
234          println(f"[warning] update logic of foldest history has two or more levels of xor gates! " +
235            f"histlen:${this.len}, compLen:$compLen, at bit $i")
236        }
237        if (resArr(i).length == 0) {
238          println(f"[error] bits $i is not assigned in folded hist update logic! histlen:${this.len}, compLen:$compLen")
239        }
240        res(i) := resArr(i).foldLeft(false.B)(_^_)
241      }
242      res.asUInt
243    }
244
245    val new_folded_hist = if (need_oldest_bits) {
246      val oldest_bits = ob
247      require(oldest_bits.length == max_update_num)
248      // mask off bits that do not update
249      val oldest_bits_masked = oldest_bits.zipWithIndex.map{
250        case (ob, i) => ob && (i < num).B
251      }
252      // if a bit does not wrap around, it should not be xored when it exits
253      val oldest_bits_set = (0 until max_update_num).filter(oldest_bit_wrap_around).map(i => (oldest_bit_pos_in_folded(i), oldest_bits_masked(i)))
254
255      // println(f"old bits pos ${oldest_bits_set.map(_._1)}")
256
257      // only the last bit could be 1, as we have at most one taken branch at a time
258      val newest_bits_masked = VecInit((0 until max_update_num).map(i => taken && ((i+1) == num).B)).asUInt
259      // if a bit does not wrap around, newest bits should not be xored onto it either
260      val newest_bits_set = (0 until max_update_num).map(i => (compLen-1-i, newest_bits_masked(i)))
261
262      // println(f"new bits set ${newest_bits_set.map(_._1)}")
263      //
264      val original_bits_masked = VecInit(folded_hist.asBools.zipWithIndex.map{
265        case (fb, i) => fb && !(num >= (len-i)).B
266      })
267      val original_bits_set = (0 until compLen).map(i => (i, original_bits_masked(i)))
268
269      // do xor then shift
270      val xored = bitsets_xor(compLen, Seq(original_bits_set, oldest_bits_set, newest_bits_set))
271      circular_shift_left(xored, num)
272    } else {
273      // histLen too short to wrap around
274      ((folded_hist << num) | taken)(compLen-1,0)
275    }
276
277    val fh = WireInit(this)
278    fh.folded_hist := new_folded_hist
279    fh
280  }
281}
282
283class AheadFoldedHistoryOldestBits(val len: Int, val max_update_num: Int)(implicit p: Parameters) extends XSBundle {
284  val bits = Vec(max_update_num*2, Bool())
285  // def info = (len, compLen)
286  def getRealOb(brNumOH: UInt): Vec[Bool] = {
287    val ob = Wire(Vec(max_update_num, Bool()))
288    for (i <- 0 until max_update_num) {
289      ob(i) := Mux1H(brNumOH, bits.drop(i).take(numBr+1))
290    }
291    ob
292  }
293}
294
295class AllAheadFoldedHistoryOldestBits(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters) extends XSBundle with HasBPUConst {
296  val afhob = MixedVec(gen.filter(t => t._1 > t._2).map{_._1}
297    .toSet.toList.map(l => new AheadFoldedHistoryOldestBits(l, numBr))) // remove duplicates
298  require(gen.toSet.toList.equals(gen))
299  def getObWithInfo(info: Tuple2[Int, Int]) = {
300    val selected = afhob.filter(_.len == info._1)
301    require(selected.length == 1)
302    selected(0)
303  }
304  def read(ghv: Vec[Bool], ptr: CGHPtr) = {
305    val hisLens = afhob.map(_.len)
306    val bitsToRead = hisLens.flatMap(l => (0 until numBr*2).map(i => l-i-1)).toSet // remove duplicates
307    val bitsWithInfo = bitsToRead.map(pos => (pos, ghv((ptr+(pos+1).U).value)))
308    for (ob <- afhob) {
309      for (i <- 0 until numBr*2) {
310        val pos = ob.len - i - 1
311        val bit_found = bitsWithInfo.filter(_._1 == pos).toList
312        require(bit_found.length == 1)
313        ob.bits(i) := bit_found(0)._2
314      }
315    }
316  }
317}
318
319class AllFoldedHistories(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters) extends XSBundle with HasBPUConst {
320  val hist = MixedVec(gen.map{case (l, cl) => new FoldedHistory(l, cl, numBr)})
321  // println(gen.mkString)
322  require(gen.toSet.toList.equals(gen))
323  def getHistWithInfo(info: Tuple2[Int, Int]) = {
324    val selected = hist.filter(_.info.equals(info))
325    require(selected.length == 1)
326    selected(0)
327  }
328  def autoConnectFrom(that: AllFoldedHistories) = {
329    require(this.hist.length <= that.hist.length)
330    for (h <- this.hist) {
331      h := that.getHistWithInfo(h.info)
332    }
333  }
334  def update(ghv: Vec[Bool], ptr: CGHPtr, shift: Int, taken: Bool): AllFoldedHistories = {
335    val res = WireInit(this)
336    for (i <- 0 until this.hist.length) {
337      res.hist(i) := this.hist(i).update(ghv, ptr, shift, taken)
338    }
339    res
340  }
341  def update(afhob: AllAheadFoldedHistoryOldestBits, lastBrNumOH: UInt, shift: Int, taken: Bool): AllFoldedHistories = {
342    val res = WireInit(this)
343    for (i <- 0 until this.hist.length) {
344      val fh = this.hist(i)
345      if (fh.need_oldest_bits) {
346        val info = fh.info
347        val selectedAfhob = afhob.getObWithInfo(info)
348        val ob = selectedAfhob.getRealOb(lastBrNumOH)
349        res.hist(i) := this.hist(i).update(ob, shift, taken)
350      } else {
351        val dumb = Wire(Vec(numBr, Bool())) // not needed
352        dumb := DontCare
353        res.hist(i) := this.hist(i).update(dumb, shift, taken)
354      }
355    }
356    res
357  }
358
359  def display(cond: Bool) = {
360    for (h <- hist) {
361      XSDebug(cond, p"hist len ${h.len}, folded len ${h.compLen}, value ${Binary(h.folded_hist)}\n")
362    }
363  }
364}
365
366class TableAddr(val idxBits: Int, val banks: Int)(implicit p: Parameters) extends XSBundle{
367  def tagBits = VAddrBits - idxBits - instOffsetBits
368
369  val tag = UInt(tagBits.W)
370  val idx = UInt(idxBits.W)
371  val offset = UInt(instOffsetBits.W)
372
373  def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
374  def getTag(x: UInt) = fromUInt(x).tag
375  def getIdx(x: UInt) = fromUInt(x).idx
376  def getBank(x: UInt) = if (banks > 1) getIdx(x)(log2Up(banks) - 1, 0) else 0.U
377  def getBankIdx(x: UInt) = if (banks > 1) getIdx(x)(idxBits - 1, log2Up(banks)) else getIdx(x)
378}
379
380trait BasicPrediction extends HasXSParameter {
381  def cfiIndex: ValidUndirectioned[UInt]
382  def target(pc: UInt): UInt
383  def lastBrPosOH: Vec[Bool]
384  def brTaken: Bool
385  def shouldShiftVec: Vec[Bool]
386  def fallThruError: Bool
387}
388class MinimalBranchPrediction(implicit p: Parameters) extends NewMicroBTBEntry with BasicPrediction {
389  val valid = Bool()
390  def cfiIndex = {
391    val res = Wire(ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
392    res.valid := taken && valid
393    res.bits := cfiOffset | Fill(res.bits.getWidth, !valid)
394    res
395  }
396  def target(pc: UInt) = nextAddr
397  def lastBrPosOH: Vec[Bool] = VecInit(brNumOH.asBools())
398  def brTaken = takenOnBr
399  def shouldShiftVec: Vec[Bool] = VecInit((0 until numBr).map(i => lastBrPosOH.drop(i+1).reduce(_||_)))
400  def fallThruError: Bool = false.B // we do this check on the following stages
401
402  def fromMicroBTBEntry(valid: Bool, entry: NewMicroBTBEntry, pc: UInt) = {
403    this.valid := valid
404    this.nextAddr := Mux(valid, entry.nextAddr, pc + (FetchWidth*4).U)
405    this.cfiOffset := entry.cfiOffset | Fill(cfiOffset.getWidth, !valid)
406    this.taken := entry.taken && valid
407    this.takenOnBr := entry.takenOnBr && valid
408    this.brNumOH := Mux(valid, entry.brNumOH, 1.U((numBr+1).W))
409  }
410}
411@chiselName
412class FullBranchPrediction(implicit p: Parameters) extends XSBundle with HasBPUConst with BasicPrediction {
413  val br_taken_mask = Vec(numBr, Bool())
414
415  val slot_valids = Vec(totalSlot, Bool())
416
417  val targets = Vec(totalSlot, UInt(VAddrBits.W))
418  val jalr_target = UInt(VAddrBits.W) // special path for indirect predictors
419  val offsets = Vec(totalSlot, UInt(log2Ceil(PredictWidth).W))
420  val fallThroughAddr = UInt(VAddrBits.W)
421  val fallThroughErr = Bool()
422
423  val is_jal = Bool()
424  val is_jalr = Bool()
425  val is_call = Bool()
426  val is_ret = Bool()
427  val last_may_be_rvi_call = Bool()
428  val is_br_sharing = Bool()
429
430  // val call_is_rvc = Bool()
431  val hit = Bool()
432
433  def br_slot_valids = slot_valids.init
434  def tail_slot_valid = slot_valids.last
435
436  def br_valids = {
437    VecInit(br_slot_valids :+ (tail_slot_valid && is_br_sharing))
438  }
439
440  def taken_mask_on_slot = {
441    VecInit(
442      (br_slot_valids zip br_taken_mask.init).map{ case (t, v) => t && v } :+ (
443        tail_slot_valid && (
444          is_br_sharing && br_taken_mask.last || !is_br_sharing
445        )
446      )
447    )
448  }
449
450  def real_slot_taken_mask(): Vec[Bool] = {
451    VecInit(taken_mask_on_slot.map(_ && hit))
452  }
453
454  // len numBr
455  def real_br_taken_mask(): Vec[Bool] = {
456    VecInit(
457      taken_mask_on_slot.map(_ && hit).init :+
458      (br_taken_mask.last && tail_slot_valid && is_br_sharing && hit)
459    )
460  }
461
462  // the vec indicating if ghr should shift on each branch
463  def shouldShiftVec =
464    VecInit(br_valids.zipWithIndex.map{ case (v, i) =>
465      v && !real_br_taken_mask.take(i).reduceOption(_||_).getOrElse(false.B)})
466
467  def lastBrPosOH =
468    VecInit((!hit || !br_valids.reduce(_||_)) +: // not hit or no brs in entry
469      (0 until numBr).map(i =>
470        br_valids(i) &&
471        !real_br_taken_mask.take(i).reduceOption(_||_).getOrElse(false.B) && // no brs taken in front it
472        (real_br_taken_mask()(i) || !br_valids.drop(i+1).reduceOption(_||_).getOrElse(false.B)) && // no brs behind it
473        hit
474      )
475    )
476
477  def brTaken = (br_valids zip br_taken_mask).map{ case (a, b) => a && b && hit}.reduce(_||_)
478
479  def target(pc: UInt): UInt = {
480    val targetVec = targets :+ fallThroughAddr :+ (pc + (FetchWidth * 4).U)
481    val tm = taken_mask_on_slot
482    val selVecOH =
483      tm.zipWithIndex.map{ case (t, i) => !tm.take(i).fold(false.B)(_||_) && t && hit} :+
484      (!tm.asUInt.orR && hit) :+ !hit
485    Mux1H(selVecOH, targetVec)
486  }
487
488  def fallThruError: Bool = hit && fallThroughErr
489
490  def hit_taken_on_jmp =
491    !real_slot_taken_mask().init.reduce(_||_) &&
492    real_slot_taken_mask().last && !is_br_sharing
493  def hit_taken_on_call = hit_taken_on_jmp && is_call
494  def hit_taken_on_ret  = hit_taken_on_jmp && is_ret
495  def hit_taken_on_jalr = hit_taken_on_jmp && is_jalr
496
497  def cfiIndex = {
498    val cfiIndex = Wire(ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
499    cfiIndex.valid := real_slot_taken_mask().asUInt.orR
500    // when no takens, set cfiIndex to PredictWidth-1
501    cfiIndex.bits :=
502      ParallelPriorityMux(real_slot_taken_mask(), offsets) |
503      Fill(log2Ceil(PredictWidth), (!real_slot_taken_mask().asUInt.orR).asUInt)
504    cfiIndex
505  }
506
507  def taken = br_taken_mask.reduce(_||_) || slot_valids.last // || (is_jal || is_jalr)
508
509  def fromFtbEntry(entry: FTBEntry, pc: UInt, last_stage: Option[Tuple2[UInt, Bool]] = None) = {
510    slot_valids := entry.brSlots.map(_.valid) :+ entry.tailSlot.valid
511    targets := entry.getTargetVec(pc)
512    jalr_target := targets.last
513    offsets := entry.getOffsetVec
514    is_jal := entry.tailSlot.valid && entry.isJal
515    is_jalr := entry.tailSlot.valid && entry.isJalr
516    is_call := entry.tailSlot.valid && entry.isCall
517    is_ret := entry.tailSlot.valid && entry.isRet
518    last_may_be_rvi_call := entry.last_may_be_rvi_call
519    is_br_sharing := entry.tailSlot.valid && entry.tailSlot.sharing
520
521    val startLower        = Cat(0.U(1.W),    pc(instOffsetBits+log2Ceil(PredictWidth)-1, instOffsetBits))
522    val endLowerwithCarry = Cat(entry.carry, entry.pftAddr)
523    fallThroughErr := startLower >= endLowerwithCarry
524    fallThroughAddr := Mux(fallThroughErr, pc + (FetchWidth * 4).U, entry.getFallThrough(pc))
525  }
526
527  def display(cond: Bool): Unit = {
528    XSDebug(cond, p"[taken_mask] ${Binary(br_taken_mask.asUInt)} [hit] $hit\n")
529  }
530}
531
532@chiselName
533class BranchPredictionBundle(implicit p: Parameters) extends XSBundle
534  with HasBPUConst with BPUUtils {
535  // def full_pred_info[T <: Data](x: T) = if (is_minimal) None else Some(x)
536  val pc = UInt(VAddrBits.W)
537
538  val valid = Bool()
539
540  val hasRedirect = Bool()
541  val ftq_idx = new FtqPtr
542  // val hit = Bool()
543  val is_minimal = Bool()
544  val minimal_pred = new MinimalBranchPrediction
545  val full_pred = new FullBranchPrediction
546
547
548  val folded_hist = new AllFoldedHistories(foldedGHistInfos)
549  val afhob = new AllAheadFoldedHistoryOldestBits(foldedGHistInfos)
550  val lastBrNumOH = UInt((numBr+1).W)
551  val histPtr = new CGHPtr
552  val rasSp = UInt(log2Ceil(RasSize).W)
553  val rasTop = new RASEntry
554  // val specCnt = Vec(numBr, UInt(10.W))
555  // val meta = UInt(MaxMetaLength.W)
556
557  val ftb_entry = new FTBEntry()
558
559  def target(pc: UInt) = Mux(is_minimal, minimal_pred.target(pc),     full_pred.target(pc))
560  def cfiIndex         = Mux(is_minimal, minimal_pred.cfiIndex,       full_pred.cfiIndex)
561  def lastBrPosOH      = Mux(is_minimal, minimal_pred.lastBrPosOH,    full_pred.lastBrPosOH)
562  def brTaken          = Mux(is_minimal, minimal_pred.brTaken,        full_pred.brTaken)
563  def shouldShiftVec   = Mux(is_minimal, minimal_pred.shouldShiftVec, full_pred.shouldShiftVec)
564  def fallThruError    = Mux(is_minimal, minimal_pred.fallThruError,  full_pred.fallThruError)
565
566  def getTarget = target(pc)
567  def taken = cfiIndex.valid
568
569  def display(cond: Bool): Unit = {
570    XSDebug(cond, p"[pc] ${Hexadecimal(pc)}\n")
571    folded_hist.display(cond)
572    full_pred.display(cond)
573    ftb_entry.display(cond)
574  }
575}
576
577@chiselName
578class BranchPredictionResp(implicit p: Parameters) extends XSBundle with HasBPUConst {
579  // val valids = Vec(3, Bool())
580  val s1 = new BranchPredictionBundle
581  val s2 = new BranchPredictionBundle
582  val s3 = new BranchPredictionBundle
583
584  def selectedResp ={
585    val res =
586      PriorityMux(Seq(
587        ((s3.valid && s3.hasRedirect) -> s3),
588        ((s2.valid && s2.hasRedirect) -> s2),
589        (s1.valid -> s1)
590      ))
591    // println("is minimal: ", res.is_minimal)
592    res
593  }
594  def selectedRespIdx =
595    PriorityMux(Seq(
596      ((s3.valid && s3.hasRedirect) -> BP_S3),
597      ((s2.valid && s2.hasRedirect) -> BP_S2),
598      (s1.valid -> BP_S1)
599    ))
600  def lastStage = s3
601}
602
603class BpuToFtqBundle(implicit p: Parameters) extends BranchPredictionResp with HasBPUConst {
604  val meta = UInt(MaxMetaLength.W)
605}
606
607object BpuToFtqBundle {
608  def apply(resp: BranchPredictionResp)(implicit p: Parameters): BpuToFtqBundle = {
609    val e = Wire(new BpuToFtqBundle())
610    e.s1 := resp.s1
611    e.s2 := resp.s2
612    e.s3 := resp.s3
613
614    e.meta := DontCare
615    e
616  }
617}
618
619class BranchPredictionUpdate(implicit p: Parameters) extends BranchPredictionBundle with HasBPUConst {
620  val mispred_mask = Vec(numBr+1, Bool())
621  val pred_hit = Bool()
622  val false_hit = Bool()
623  val new_br_insert_pos = Vec(numBr, Bool())
624  val old_entry = Bool()
625  val meta = UInt(MaxMetaLength.W)
626  val full_target = UInt(VAddrBits.W)
627  val from_stage = UInt(2.W)
628  val ghist = UInt(HistoryLength.W)
629
630  def fromFtqRedirectSram(entry: Ftq_Redirect_SRAMEntry) = {
631    folded_hist := entry.folded_hist
632    afhob := entry.afhob
633    lastBrNumOH := entry.lastBrNumOH
634    histPtr := entry.histPtr
635    rasSp := entry.rasSp
636    rasTop := entry.rasEntry
637    this
638  }
639
640  override def display(cond: Bool) = {
641    XSDebug(cond, p"-----------BranchPredictionUpdate-----------\n")
642    XSDebug(cond, p"[mispred_mask] ${Binary(mispred_mask.asUInt)} [false_hit] $false_hit\n")
643    XSDebug(cond, p"[new_br_insert_pos] ${Binary(new_br_insert_pos.asUInt)}\n")
644    super.display(cond)
645    XSDebug(cond, p"--------------------------------------------\n")
646  }
647}
648
649class BranchPredictionRedirect(implicit p: Parameters) extends Redirect with HasBPUConst {
650  // override def toPrintable: Printable = {
651  //   p"-----------BranchPredictionRedirect----------- " +
652  //     p"-----------cfiUpdate----------- " +
653  //     p"[pc] ${Hexadecimal(cfiUpdate.pc)} " +
654  //     p"[predTaken] ${cfiUpdate.predTaken}, [taken] ${cfiUpdate.taken}, [isMisPred] ${cfiUpdate.isMisPred} " +
655  //     p"[target] ${Hexadecimal(cfiUpdate.target)} " +
656  //     p"------------------------------- " +
657  //     p"[robPtr] f=${robIdx.flag} v=${robIdx.value} " +
658  //     p"[ftqPtr] f=${ftqIdx.flag} v=${ftqIdx.value} " +
659  //     p"[ftqOffset] ${ftqOffset} " +
660  //     p"[level] ${level}, [interrupt] ${interrupt} " +
661  //     p"[stFtqIdx] f=${stFtqIdx.flag} v=${stFtqIdx.value} " +
662  //     p"[stFtqOffset] ${stFtqOffset} " +
663  //     p"\n"
664
665  // }
666
667  def display(cond: Bool): Unit = {
668    XSDebug(cond, p"-----------BranchPredictionRedirect----------- \n")
669    XSDebug(cond, p"-----------cfiUpdate----------- \n")
670    XSDebug(cond, p"[pc] ${Hexadecimal(cfiUpdate.pc)}\n")
671    // XSDebug(cond, p"[hist] ${Binary(cfiUpdate.hist.predHist)}\n")
672    XSDebug(cond, p"[br_hit] ${cfiUpdate.br_hit} [isMisPred] ${cfiUpdate.isMisPred}\n")
673    XSDebug(cond, p"[pred_taken] ${cfiUpdate.predTaken} [taken] ${cfiUpdate.taken} [isMisPred] ${cfiUpdate.isMisPred}\n")
674    XSDebug(cond, p"[target] ${Hexadecimal(cfiUpdate.target)} \n")
675    XSDebug(cond, p"[shift] ${cfiUpdate.shift}\n")
676    XSDebug(cond, p"------------------------------- \n")
677    XSDebug(cond, p"[robPtr] f=${robIdx.flag} v=${robIdx.value}\n")
678    XSDebug(cond, p"[ftqPtr] f=${ftqIdx.flag} v=${ftqIdx.value} \n")
679    XSDebug(cond, p"[ftqOffset] ${ftqOffset} \n")
680    XSDebug(cond, p"[stFtqIdx] f=${stFtqIdx.flag} v=${stFtqIdx.value}\n")
681    XSDebug(cond, p"[stFtqOffset] ${stFtqOffset}\n")
682    XSDebug(cond, p"---------------------------------------------- \n")
683  }
684}
685