xref: /XiangShan/src/main/scala/xiangshan/frontend/BPU.scala (revision f320e0f01bd645f0a3045a8a740e60dd770734a9)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.frontend
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import xiangshan._
24import chisel3.experimental.chiselName
25
26trait HasBPUParameter extends HasXSParameter {
27  val BPUDebug = true && !env.FPGAPlatform
28  val EnableCFICommitLog = true
29  val EnbaleCFIPredLog = true
30  val EnableBPUTimeRecord = (EnableCFICommitLog || EnbaleCFIPredLog) && !env.FPGAPlatform
31  val EnableCommit = false
32}
33
34class TableAddr(val idxBits: Int, val banks: Int)(implicit p: Parameters) extends XSBundle with HasIFUConst {
35  def tagBits = VAddrBits - idxBits - instOffsetBits
36
37  val tag = UInt(tagBits.W)
38  val idx = UInt(idxBits.W)
39  val offset = UInt(instOffsetBits.W)
40
41  def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
42  def getTag(x: UInt) = fromUInt(x).tag
43  def getIdx(x: UInt) = fromUInt(x).idx
44  def getBank(x: UInt) = getIdx(x)(log2Up(banks) - 1, 0)
45  def getBankIdx(x: UInt) = getIdx(x)(idxBits - 1, log2Up(banks))
46}
47
48class PredictorResponse(implicit p: Parameters) extends XSBundle {
49  class UbtbResp extends XSBundle {
50  // the valid bits indicates whether a target is hit
51    val targets = Vec(PredictWidth, UInt(VAddrBits.W))
52    val hits = Vec(PredictWidth, Bool())
53    val takens = Vec(PredictWidth, Bool())
54    val brMask = Vec(PredictWidth, Bool())
55    val is_RVC = Vec(PredictWidth, Bool())
56  }
57  class BtbResp extends XSBundle {
58  // the valid bits indicates whether a target is hit
59    val targets = Vec(PredictWidth, UInt(VAddrBits.W))
60    val hits = Vec(PredictWidth, Bool())
61    val isBrs = Vec(PredictWidth, Bool())
62    val isRVC = Vec(PredictWidth, Bool())
63  }
64  class BimResp extends XSBundle {
65    val ctrs = Vec(PredictWidth, UInt(2.W))
66  }
67  class TageResp extends XSBundle {
68  // the valid bits indicates whether a prediction is hit
69    val takens = Vec(PredictWidth, Bool())
70    val hits = Vec(PredictWidth, Bool())
71  }
72  class LoopResp extends XSBundle {
73    val exit = Vec(PredictWidth, Bool())
74  }
75
76  val ubtb = new UbtbResp
77  val btb = new BtbResp
78  val bim = new BimResp
79  val tage = new TageResp
80  val loop = new LoopResp
81}
82
83trait PredictorUtils {
84  // circular shifting
85  def circularShiftLeft(source: UInt, len: Int, shamt: UInt): UInt = {
86    val res = Wire(UInt(len.W))
87    val higher = source << shamt
88    val lower = source >> (len.U - shamt)
89    res := higher | lower
90    res
91  }
92
93  def circularShiftRight(source: UInt, len: Int, shamt: UInt): UInt = {
94    val res = Wire(UInt(len.W))
95    val higher = source << (len.U - shamt)
96    val lower = source >> shamt
97    res := higher | lower
98    res
99  }
100
101  // To be verified
102  def satUpdate(old: UInt, len: Int, taken: Bool): UInt = {
103    val oldSatTaken = old === ((1 << len)-1).U
104    val oldSatNotTaken = old === 0.U
105    Mux(oldSatTaken && taken, ((1 << len)-1).U,
106      Mux(oldSatNotTaken && !taken, 0.U,
107        Mux(taken, old + 1.U, old - 1.U)))
108  }
109
110  def signedSatUpdate(old: SInt, len: Int, taken: Bool): SInt = {
111    val oldSatTaken = old === ((1 << (len-1))-1).S
112    val oldSatNotTaken = old === (-(1 << (len-1))).S
113    Mux(oldSatTaken && taken, ((1 << (len-1))-1).S,
114      Mux(oldSatNotTaken && !taken, (-(1 << (len-1))).S,
115        Mux(taken, old + 1.S, old - 1.S)))
116  }
117}
118
119trait HasIFUFire { this: MultiIOModule =>
120  val fires = IO(Input(Vec(4, Bool())))
121  val s1_fire  = fires(0)
122  val s2_fire  = fires(1)
123  val s3_fire  = fires(2)
124  val out_fire = fires(3)
125}
126
127trait HasCtrl { this: BasePredictor =>
128  val ctrl = IO(Input(new BPUCtrl))
129}
130
131abstract class BasePredictor(implicit p: Parameters) extends XSModule
132  with HasBPUParameter with HasIFUConst with PredictorUtils
133  with HasIFUFire with HasCtrl {
134  val metaLen = 0
135
136  // An implementation MUST extend the IO bundle with a response
137  // and the special input from other predictors, as well as
138  // the metas to store in BRQ
139  abstract class Resp extends XSBundle {}
140  abstract class FromOthers extends XSBundle {}
141  abstract class Meta extends XSBundle {}
142
143  class DefaultBasePredictorIO extends XSBundle {
144    val pc = Flipped(ValidIO(UInt(VAddrBits.W)))
145    val hist = Input(UInt(HistoryLength.W))
146    val inMask = Input(UInt(PredictWidth.W))
147    val update = Flipped(ValidIO(new FtqEntry))
148  }
149  val io = new DefaultBasePredictorIO
150  val in_ready = IO(Output(Bool()))
151  in_ready := true.B
152  val debug = true
153}
154
155class BrInfo(implicit p: Parameters) extends XSBundle {
156  val metas = Vec(PredictWidth, new BpuMeta)
157  val rasSp = UInt(log2Ceil(RasSize).W)
158  val rasTop = new RASEntry
159  val specCnt = Vec(PredictWidth, UInt(10.W))
160}
161class BPUStageIO(implicit p: Parameters) extends XSBundle {
162  val pc = UInt(VAddrBits.W)
163  val mask = UInt(PredictWidth.W)
164  val resp = new PredictorResponse
165  val brInfo = new BrInfo
166}
167
168
169abstract class BPUStage(implicit p: Parameters) extends XSModule with HasBPUParameter
170  with HasIFUConst with HasIFUFire {
171  class DefaultIO extends XSBundle {
172    val in = Input(new BPUStageIO)
173    val inFire = Input(Bool())
174    val pred = Output(new BranchPrediction) // to ifu
175    val out = Output(new BPUStageIO)        // to the next stage
176    val outFire = Input(Bool())
177
178    val debug_hist = Input(UInt((if (BPUDebug) (HistoryLength) else 0).W))
179  }
180  val io = IO(new DefaultIO)
181
182  val inLatch = RegEnable(io.in, io.inFire)
183
184  // Each stage has its own logic to decide
185  // takens, brMask, jalMask, targets and hasHalfRVI
186  val takens = Wire(Vec(PredictWidth, Bool()))
187  val brMask = Wire(Vec(PredictWidth, Bool()))
188  val jalMask = Wire(Vec(PredictWidth, Bool()))
189  val targets = Wire(Vec(PredictWidth, UInt(VAddrBits.W)))
190  val hasHalfRVI = Wire(Bool())
191
192  io.pred <> DontCare
193  io.pred.takens := takens.asUInt
194  io.pred.brMask := brMask.asUInt
195  io.pred.jalMask := jalMask.asUInt
196  io.pred.targets := targets
197  io.pred.hasHalfRVI := hasHalfRVI
198
199  io.out <> DontCare
200  io.out.pc := inLatch.pc
201  io.out.mask := inLatch.mask
202  io.out.resp <> inLatch.resp
203  io.out.brInfo := inLatch.brInfo
204
205  if (BPUDebug) {
206    val jmpIdx = io.pred.jmpIdx
207    val taken  = io.pred.taken
208    val target = Mux(taken, io.pred.targets(jmpIdx), snpc(inLatch.pc))
209    XSDebug("in(%d): pc=%x, mask=%b\n", io.inFire, io.in.pc, io.in.mask)
210    XSDebug("inLatch: pc=%x, mask=%b\n", inLatch.pc, inLatch.mask)
211    XSDebug("out(%d): pc=%x, mask=%b, taken=%d, jmpIdx=%d, target=%x, hasHalfRVI=%d\n",
212      io.outFire, io.out.pc, io.out.mask, taken, jmpIdx, target, hasHalfRVI)
213    //val p = io.pred
214  }
215}
216
217@chiselName
218class BPUStage1(implicit p: Parameters) extends BPUStage {
219
220  // ubtb is accessed with inLatch pc in s1,
221  // so we use io.in instead of inLatch
222  val ubtbResp = io.in.resp.ubtb
223  // the read operation is already masked, so we do not need to mask here
224  takens    := VecInit((0 until PredictWidth).map(i => ubtbResp.takens(i)))
225  // notTakens := VecInit((0 until PredictWidth).map(i => ubtbResp.hits(i) && !ubtbResp.takens(i) && ubtbResp.brMask(i)))
226  brMask := ubtbResp.brMask
227  jalMask := DontCare
228  targets := ubtbResp.targets
229
230  hasHalfRVI := ubtbResp.hits(PredictWidth-1) && !ubtbResp.is_RVC(PredictWidth-1) && HasCExtension.B
231
232  // resp and brInfo are from the components,
233  // so it does not need to be latched
234  io.out.resp <> io.in.resp
235  io.out.brInfo := io.in.brInfo
236
237  // For perf counters
238  if (!env.FPGAPlatform && env.EnablePerfDebug) {
239    io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) =>
240      // record ubtb pred result
241      meta.ubtbAns.hit := ubtbResp.hits(i)
242      meta.ubtbAns.taken := ubtbResp.takens(i)
243      meta.ubtbAns.target := ubtbResp.targets(i)
244    }
245  }
246
247  if (BPUDebug) {
248    XSDebug(io.outFire, "outPred using ubtb resp: hits:%b, takens:%b, notTakens:%b, isRVC:%b\n",
249      ubtbResp.hits.asUInt, ubtbResp.takens.asUInt, ~ubtbResp.takens.asUInt & brMask.asUInt, ubtbResp.is_RVC.asUInt)
250  }
251  if (EnableBPUTimeRecord) {
252    io.out.brInfo.metas.map(_.debug_ubtb_cycle := GTimer())
253  }
254}
255@chiselName
256class BPUStage2(implicit p: Parameters) extends BPUStage {
257  // Use latched response from s1
258  val btbResp = inLatch.resp.btb
259  val bimResp = inLatch.resp.bim
260  takens    := VecInit((0 until PredictWidth).map(i => btbResp.hits(i) && (btbResp.isBrs(i) && bimResp.ctrs(i)(1) || !btbResp.isBrs(i))))
261  targets := btbResp.targets
262  brMask  := VecInit((0 until PredictWidth).map(i => btbResp.isBrs(i) && btbResp.hits(i)))
263  jalMask := DontCare
264
265  hasHalfRVI  := btbResp.hits(PredictWidth-1) && !btbResp.isRVC(PredictWidth-1) && HasCExtension.B
266
267  // For perf counters
268  if (!env.FPGAPlatform && env.EnablePerfDebug) {
269    io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) =>
270      // record btb pred result
271      meta.btbAns.hit := btbResp.hits(i)
272      meta.btbAns.taken := takens(i)
273      meta.btbAns.target := btbResp.targets(i)
274    }
275  }
276
277  if (BPUDebug) {
278    XSDebug(io.outFire, "outPred using btb&bim resp: hits:%b, ctrTakens:%b\n",
279      btbResp.hits.asUInt, VecInit(bimResp.ctrs.map(_(1))).asUInt)
280  }
281  if (EnableBPUTimeRecord) {
282    io.out.brInfo.metas.map(_.debug_btb_cycle := GTimer())
283  }
284}
285@chiselName
286class BPUStage3(implicit p: Parameters) extends BPUStage {
287  class S3IO extends XSBundle {
288    val predecode = Input(new Predecode)
289    val redirect =  Flipped(ValidIO(new Redirect))
290    val ctrl = Input(new BPUCtrl)
291  }
292  val s3IO = IO(new S3IO)
293  // TAGE has its own pipelines and the
294  // response comes directly from s3,
295  // so we do not use those from inLatch
296  val tageResp = io.in.resp.tage
297  val tageTakens = tageResp.takens
298
299  val loopResp = io.in.resp.loop.exit
300
301  val pdMask     = s3IO.predecode.mask
302  val pdLastHalf = s3IO.predecode.lastHalf
303  val pds        = s3IO.predecode.pd
304
305  val btbResp   = WireInit(inLatch.resp.btb)
306  val btbHits   = WireInit(btbResp.hits.asUInt)
307  val bimTakens = VecInit(inLatch.resp.bim.ctrs.map(_(1)))
308
309  val brs   = pdMask & Reverse(Cat(pds.map(_.isBr)))
310  val jals  = pdMask & Reverse(Cat(pds.map(_.isJal)))
311  val jalrs = pdMask & Reverse(Cat(pds.map(_.isJalr)))
312  val calls = pdMask & Reverse(Cat(pds.map(_.isCall)))
313  val rets  = pdMask & Reverse(Cat(pds.map(_.isRet)))
314  val RVCs  = pdMask & Reverse(Cat(pds.map(_.isRVC)))
315
316  val callIdx = PriorityEncoder(calls)
317  val retIdx  = PriorityEncoder(rets)
318
319  val brPred = (if(EnableBPD) tageTakens else bimTakens).asUInt
320  val loopRes = (if (EnableLoop) loopResp else VecInit(Fill(PredictWidth, 0.U(1.W)))).asUInt
321  val brTakens = ((brs & brPred) & ~loopRes)
322  // we should provide btb resp as well
323  btbHits := btbResp.hits.asUInt
324
325  // predict taken only if btb has a target, jal and br targets will be provided by IFU
326  takens := VecInit((0 until PredictWidth).map(i => jalrs(i) && btbHits(i) || (jals(i) || brTakens(i))))
327
328
329  targets := inLatch.resp.btb.targets
330
331  brMask  := WireInit(brs.asTypeOf(Vec(PredictWidth, Bool())))
332  jalMask := WireInit(jals.asTypeOf(Vec(PredictWidth, Bool())))
333
334  hasHalfRVI  := pdLastHalf && HasCExtension.B
335
336  //RAS
337  if(EnableRAS){
338    val ras = Module(new RAS)
339    ras.io <> DontCare
340    ras.io.pc.bits := packetAligned(inLatch.pc)
341    ras.io.pc.valid := io.outFire//predValid
342    ras.io.is_ret := rets.orR  && (retIdx === io.pred.jmpIdx)
343    ras.io.callIdx.valid := calls.orR && (callIdx === io.pred.jmpIdx)
344    ras.io.callIdx.bits := callIdx
345    ras.io.isRVC := (calls & RVCs).orR   //TODO: this is ugly
346    ras.io.isLastHalfRVI := s3IO.predecode.hasLastHalfRVI
347    ras.io.redirect := s3IO.redirect
348    ras.fires <> fires
349    ras.ctrl := s3IO.ctrl
350
351    for(i <- 0 until PredictWidth){
352      io.out.brInfo.rasSp :=  ras.io.meta.rasSp
353      io.out.brInfo.rasTop :=  ras.io.meta.rasTop
354    }
355    val rasEn = s3IO.ctrl.ras_enable
356    takens := VecInit((0 until PredictWidth).map(i => {
357      (jalrs(i) && btbHits(i)) ||
358          jals(i) || brTakens(i) ||
359          (rasEn && rets(i)) ||
360          (!rasEn && rets(i) && btbHits(i))
361      }
362    ))
363
364    for (i <- 0 until PredictWidth) {
365      when(rets(i)){
366        targets(i) := ras.io.out.target
367      }
368    }
369
370    // For perf counters
371    if (!env.FPGAPlatform && env.EnablePerfDebug) {
372      io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) =>
373        // record tage pred result
374        meta.tageAns.hit := tageResp.hits(i)
375        meta.tageAns.taken := tageResp.takens(i)
376        meta.tageAns.target := DontCare
377
378        // record ras pred result
379        meta.rasAns.hit := true.B
380        meta.rasAns.taken := true.B
381        meta.rasAns.target := ras.io.out.target
382
383        // record loop pred result
384        meta.loopAns.hit := loopRes(i)
385        meta.loopAns.taken := false.B
386        meta.loopAns.target := DontCare
387      }
388    }
389  }
390
391
392  // Wrap tage resp and tage meta in
393  // This is ugly
394  io.out.resp.tage <> io.in.resp.tage
395  io.out.resp.loop <> io.in.resp.loop
396  for (i <- 0 until PredictWidth) {
397    io.out.brInfo.metas(i).tageMeta := io.in.brInfo.metas(i).tageMeta
398    io.out.brInfo.specCnt(i) := io.in.brInfo.specCnt(i)
399  }
400
401  if (BPUDebug) {
402    XSDebug(io.inFire, "predecode: pc:%x, mask:%b\n", inLatch.pc, s3IO.predecode.mask)
403    for (i <- 0 until PredictWidth) {
404      val pd = s3IO.predecode.pd(i)
405      XSDebug(io.inFire && s3IO.predecode.mask(i), "predecode(%d): brType:%d, br:%d, jal:%d, jalr:%d, call:%d, ret:%d, RVC:%d, excType:%d\n",
406        i.U, pd.brType, pd.isBr, pd.isJal, pd.isJalr, pd.isCall, pd.isRet, pd.isRVC, pd.excType)
407    }
408    XSDebug(p"brs:${Binary(brs)} jals:${Binary(jals)} jalrs:${Binary(jalrs)} calls:${Binary(calls)} rets:${Binary(rets)} rvcs:${Binary(RVCs)}\n")
409    XSDebug(p"callIdx:${callIdx} retIdx:${retIdx}\n")
410    XSDebug(p"brPred:${Binary(brPred)} loopRes:${Binary(loopRes)} brTakens:${Binary(brTakens)}\n")
411  }
412
413  if (EnbaleCFIPredLog) {
414    val out = io.out
415    XSDebug(io.outFire, p"cfi_pred: fetchpc(${Hexadecimal(out.pc)}) mask(${out.mask}) brmask(${brMask.asUInt}) hist(${Hexadecimal(io.debug_hist)})\n")
416  }
417
418  if (EnableBPUTimeRecord) {
419    io.out.brInfo.metas.map(_.debug_tage_cycle := GTimer())
420  }
421}
422
423trait BranchPredictorComponents extends HasXSParameter {
424  val ubtb = Module(new MicroBTB)
425  val btb = Module(new BTB)
426  val bim = Module(new BIM)
427  val tage = (if(EnableBPD) { if (EnableSC) Module(new Tage_SC)
428                              else          Module(new Tage) }
429              else          { Module(new FakeTage) })
430  val loop = Module(new LoopPredictor)
431  val preds = Seq(ubtb, btb, bim, tage, loop)
432  preds.map(_.io := DontCare)
433}
434
435class BPUReq(implicit p: Parameters) extends XSBundle {
436  val pc = UInt(VAddrBits.W)
437  val hist = UInt(HistoryLength.W)
438  val inMask = UInt(PredictWidth.W)
439}
440
441class BPUCtrl(implicit p: Parameters) extends XSBundle {
442  val ubtb_enable = Bool()
443  val btb_enable  = Bool()
444  val bim_enable  = Bool()
445  val tage_enable = Bool()
446  val sc_enable   = Bool()
447  val ras_enable  = Bool()
448  val loop_enable = Bool()
449}
450
451abstract class BaseBPU(implicit p: Parameters) extends XSModule with BranchPredictorComponents
452  with HasBPUParameter with HasIFUConst {
453  val io = IO(new Bundle() {
454    // from backend
455    val redirect = Flipped(ValidIO(new Redirect))
456    val ctrl     = Input(new BPUCtrl)
457    val commit   = Flipped(ValidIO(new FtqEntry))
458    // from if1
459    val in = Input(new BPUReq)
460    val inFire = Input(Vec(4, Bool()))
461    // to if1
462    val in_ready = Output(Bool())
463    // to if2/if3/if4
464    val out = Vec(3, Output(new BranchPrediction))
465    // from if4
466    val predecode = Input(new Predecode)
467    // to if4, some bpu info used for updating
468    val brInfo = Output(new BrInfo)
469  })
470
471  preds.map(p => {
472    p.io.update <> io.commit
473    p.fires <> io.inFire
474    p.ctrl <> io.ctrl
475  })
476
477  io.in_ready := preds.map(p => p.in_ready).reduce(_&&_)
478
479  val s1 = Module(new BPUStage1)
480  val s2 = Module(new BPUStage2)
481  val s3 = Module(new BPUStage3)
482
483  Seq(s1, s2, s3).foreach(s => s.fires <> io.inFire)
484
485  val s1_fire = io.inFire(0)
486  val s2_fire = io.inFire(1)
487  val s3_fire = io.inFire(2)
488  val s4_fire = io.inFire(3)
489
490  s1.io.in <> DontCare
491  s2.io.in <> s1.io.out
492  s3.io.in <> s2.io.out
493
494  s1.io.inFire := s1_fire
495  s2.io.inFire := s2_fire
496  s3.io.inFire := s3_fire
497
498  s1.io.outFire := s2_fire
499  s2.io.outFire := s3_fire
500  s3.io.outFire := s4_fire
501
502  io.out(0) <> s1.io.pred
503  io.out(1) <> s2.io.pred
504  io.out(2) <> s3.io.pred
505
506  io.brInfo := s3.io.out.brInfo
507
508  if (BPUDebug) {
509    XSDebug(io.inFire(3), "bpuMeta sent!\n")
510    for (i <- 0 until PredictWidth) {
511      val b = io.brInfo.metas(i)
512      XSDebug(io.inFire(3), "brInfo(%d): btbWrWay:%d, bimCtr:%d\n",
513        i.U, b.btbWriteWay, b.bimCtr)
514      val t = b.tageMeta
515      XSDebug(io.inFire(3), "  tageMeta: pvder(%d):%d, altDiffers:%d, pvderU:%d, pvderCtr:%d, allocate(%d):%d\n",
516        t.provider.valid, t.provider.bits, t.altDiffers, t.providerU, t.providerCtr, t.allocate.valid, t.allocate.bits)
517    }
518  }
519  val debug_verbose = false
520}
521
522
523class FakeBPU(implicit p: Parameters) extends BaseBPU {
524  io.out.foreach(i => {
525    // Provide not takens
526    i <> DontCare
527    i.takens := 0.U
528  })
529  io.brInfo <> DontCare
530}
531@chiselName
532class BPU(implicit p: Parameters) extends BaseBPU {
533
534  //**********************Stage 1****************************//
535
536  val s1_resp_in = Wire(new PredictorResponse)
537  val s1_brInfo_in = Wire(new BrInfo)
538
539  s1_resp_in.tage := DontCare
540  s1_resp_in.loop := DontCare
541  s1_brInfo_in    := DontCare
542
543  val s1_inLatch = RegEnable(io.in, s1_fire)
544  ubtb.io.pc.valid := s2_fire
545  ubtb.io.pc.bits := s1_inLatch.pc
546  ubtb.io.inMask := s1_inLatch.inMask
547
548
549
550  // Wrap ubtb response into resp_in and brInfo_in
551  s1_resp_in.ubtb <> ubtb.io.out
552  for (i <- 0 until PredictWidth) {
553    s1_brInfo_in.metas(i).ubtbHit := ubtb.io.out.hits(i)
554  }
555
556  btb.io.pc.valid := s1_fire
557  btb.io.pc.bits := io.in.pc
558  btb.io.inMask := io.in.inMask
559
560
561
562  // Wrap btb response into resp_in and brInfo_in
563  s1_resp_in.btb <> btb.io.resp
564  for (i <- 0 until PredictWidth) {
565    s1_brInfo_in.metas(i).btbWriteWay := btb.io.meta.writeWay(i)
566    s1_brInfo_in.metas(i).btbHit := btb.io.meta.hits(i)
567  }
568
569  bim.io.pc.valid := s1_fire
570  bim.io.pc.bits := io.in.pc
571  bim.io.inMask := io.in.inMask
572
573
574  // Wrap bim response into resp_in and brInfo_in
575  s1_resp_in.bim <> bim.io.resp
576  for (i <- 0 until PredictWidth) {
577    s1_brInfo_in.metas(i).bimCtr := bim.io.meta.ctrs(i)
578  }
579
580
581  s1.io.inFire := s1_fire
582  s1.io.in.pc := io.in.pc
583  s1.io.in.mask := io.in.inMask
584  s1.io.in.resp <> s1_resp_in
585  s1.io.in.brInfo <> s1_brInfo_in
586
587  val s1_hist = RegEnable(io.in.hist, enable=s1_fire)
588  val s2_hist = RegEnable(s1_hist, enable=s2_fire)
589  val s3_hist = RegEnable(s2_hist, enable=s3_fire)
590
591  s1.io.debug_hist := s1_hist
592  s2.io.debug_hist := s2_hist
593  s3.io.debug_hist := s3_hist
594
595  //**********************Stage 2****************************//
596  tage.io.pc.valid := s2_fire
597  tage.io.pc.bits := s2.io.in.pc // PC from s1
598  tage.io.hist := s1_hist // The inst is from s1
599  tage.io.inMask := s2.io.in.mask
600  tage.io.bim <> s1.io.out.resp.bim // Use bim results from s1
601
602  //**********************Stage 3****************************//
603  // Wrap tage response and meta into s3.io.in.bits
604  // This is ugly
605
606  loop.io.pc.valid := s2_fire
607  loop.io.if3_fire := s3_fire
608  loop.io.pc.bits := s2.io.in.pc
609  loop.io.inMask := io.predecode.mask
610  loop.io.respIn.taken := s3.io.pred.taken
611  loop.io.respIn.jmpIdx := s3.io.pred.jmpIdx
612  loop.io.redirect := s3.s3IO.redirect
613
614
615  s3.io.in.resp.tage <> tage.io.resp
616  s3.io.in.resp.loop <> loop.io.resp
617  for (i <- 0 until PredictWidth) {
618    s3.io.in.brInfo.metas(i).tageMeta := tage.io.meta(i)
619    s3.io.in.brInfo.specCnt(i) := loop.io.meta.specCnts(i)
620  }
621
622  s3.s3IO.predecode <> io.predecode
623  s3.s3IO.redirect <> io.redirect
624  s3.s3IO.ctrl <> io.ctrl
625
626
627  if (BPUDebug) {
628    if (debug_verbose) {
629      val uo = ubtb.io.out
630      XSDebug("debug: ubtb hits:%b, takens:%b, notTakens:%b\n", uo.hits.asUInt, uo.takens.asUInt, ~uo.takens.asUInt & uo.brMask.asUInt)
631      val bio = bim.io.resp
632      XSDebug("debug: bim takens:%b\n", VecInit(bio.ctrs.map(_(1))).asUInt)
633      val bo = btb.io.resp
634      XSDebug("debug: btb hits:%b\n", bo.hits.asUInt)
635    }
636  }
637
638
639
640  if (EnableCFICommitLog) {
641    val buValid = io.commit.valid
642    val buinfo  = io.commit.bits
643    for (i <- 0 until PredictWidth) {
644      val cfi_idx = buinfo.cfiIndex
645      val isTaken = cfi_idx.valid && cfi_idx.bits === i.U
646      val isCfi = buinfo.valids(i) && (buinfo.br_mask(i) || cfi_idx.valid && cfi_idx.bits === i.U)
647      val isBr = buinfo.br_mask(i)
648      val pc = packetAligned(buinfo.ftqPC) + (i * instBytes).U - Mux((i==0).B && buinfo.hasLastPrev, 2.U, 0.U)
649      val tage_cycle = buinfo.metas(i).debug_tage_cycle
650      XSDebug(buValid && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) taken(${isTaken}) mispred(${buinfo.mispred(i)}) cycle($tage_cycle) hist(${Hexadecimal(buinfo.predHist.asUInt)})\n")
651    }
652  }
653
654}
655
656object BPU{
657  def apply(enableBPU: Boolean = true)(implicit p: Parameters) = {
658      if(enableBPU) {
659        val BPU = Module(new BPU)
660        BPU
661      }
662      else {
663        val FakeBPU = Module(new FakeBPU)
664        FakeBPU
665      }
666  }
667}
668