xref: /XiangShan/src/main/scala/xiangshan/frontend/BPU.scala (revision 7f8b9ff75601a7b72b62d7ebae7462491186158b)
1package xiangshan.frontend
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import xiangshan.utils._
7import xiangshan.backend.ALUOpType
8import xiangshan.backend.BRUOpType
9import utils._
10import chisel3.util.experimental.BoringUtils
11import xiangshan.backend.decode.XSTrap
12
13class TableAddr(val idxBits: Int, val banks: Int) extends XSBundle {
14  def tagBits = VAddrBits - idxBits - 1
15
16  val tag = UInt(tagBits.W)
17  val idx = UInt(idxBits.W)
18  val offset = UInt(1.W)
19
20  def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
21  def getTag(x: UInt) = fromUInt(x).tag
22  def getIdx(x: UInt) = fromUInt(x).idx
23  def getBank(x: UInt) = getIdx(x)(log2Up(banks) - 1, 0)
24  def getBankIdx(x: UInt) = getIdx(x)(idxBits - 1, log2Up(banks))
25}
26
27class Stage1To2IO extends XSBundle {
28  val pc = Output(UInt(VAddrBits.W))
29  val btb = new Bundle {
30    val hits = Output(UInt(FetchWidth.W))
31    val targets = Output(Vec(FetchWidth, UInt(VAddrBits.W)))
32  }
33  val jbtac = new Bundle {
34    val hitIdx = Output(UInt(FetchWidth.W))
35    val target = Output(UInt(VAddrBits.W))
36  }
37  val tage = new Bundle {
38    val hits = Output(UInt(FetchWidth.W))
39    val takens = Output(Vec(FetchWidth, Bool()))
40  }
41  val hist = Output(Vec(FetchWidth, UInt(HistoryLength.W)))
42  val btbPred = ValidIO(new BranchPrediction)
43}
44
45class BPUStage1 extends XSModule {
46  val io = IO(new Bundle() {
47    val in = new Bundle { val pc = Flipped(Decoupled(UInt(VAddrBits.W))) }
48    // from backend
49    val redirectInfo = Input(new RedirectInfo)
50    // from Stage3
51    val flush = Input(Bool())
52    val s3RollBackHist = Input(UInt(HistoryLength.W))
53    val s3Taken = Input(Bool())
54    // to ifu, quick prediction result
55    val s1OutPred = ValidIO(new BranchPrediction)
56    // to Stage2
57    val out = Decoupled(new Stage1To2IO)
58  })
59
60  io.in.pc.ready := true.B
61
62  // flush Stage1 when io.flush
63  val flushS1 = BoolStopWatch(io.flush, io.in.pc.fire(), startHighPriority = true)
64
65  // global history register
66  val ghr = RegInit(0.U(HistoryLength.W))
67  // modify updateGhr and newGhr when updating ghr
68  val updateGhr = WireInit(false.B)
69  val newGhr = WireInit(0.U(HistoryLength.W))
70  when (updateGhr) { ghr := newGhr }
71  // use hist as global history!!!
72  val hist = Mux(updateGhr, newGhr, ghr)
73
74  // Tage predictor
75  val tage = Module(new FakeTAGE)
76  // val tage = if(EnableBPD) Module(new Tage) else Module(new FakeTAGE)
77  tage.io.req.valid := io.in.pc.fire()
78  tage.io.req.bits.pc := io.in.pc.bits
79  tage.io.req.bits.hist := hist
80  tage.io.redirectInfo <> io.redirectInfo
81  io.out.bits.tage <> tage.io.out
82  io.s1OutPred.bits.tageMeta := tage.io.meta
83
84  // latch pc for 1 cycle latency when reading SRAM
85  val pcLatch = RegEnable(io.in.pc.bits, io.in.pc.fire())
86
87  val r = io.redirectInfo.redirect
88  val updateFetchpc = r.pc - (r.fetchIdx << 2.U)
89  // BTB
90  val btb = Module(new BTB)
91  btb.io.in.pc <> io.in.pc
92  btb.io.in.pcLatch := pcLatch
93  // TODO: pass real mask in
94  btb.io.in.mask := "b1111111111111111".asUInt
95  btb.io.redirectValid := io.redirectInfo.valid
96  btb.io.flush := io.flush
97
98  // btb.io.update.fetchPC := updateFetchpc
99  // btb.io.update.fetchIdx := r.fetchIdx
100  btb.io.update.pc := r.pc
101  btb.io.update.hit := r.btbHitWay
102  btb.io.update.misPred := io.redirectInfo.misPred
103  // btb.io.update.writeWay := r.btbVictimWay
104  btb.io.update.oldCtr := r.btbPredCtr
105  btb.io.update.taken := r.taken
106  btb.io.update.target := r.brTarget
107  btb.io.update._type := r._type
108  // TODO: add RVC logic
109  btb.io.update.isRVC := DontCare
110
111  val btbHit = btb.io.out.hit
112  val btbTaken = btb.io.out.taken
113  val btbTakenIdx = btb.io.out.takenIdx
114  val btbTakenTarget = btb.io.out.target
115  // val btbWriteWay = btb.io.out.writeWay
116  val btbNotTakens = btb.io.out.notTakens
117  val btbCtrs = VecInit(btb.io.out.dEntries.map(_.pred))
118  val btbValids = btb.io.out.hits
119  val btbTargets = VecInit(btb.io.out.dEntries.map(_.target))
120  val btbTypes = VecInit(btb.io.out.dEntries.map(_._type))
121
122
123  val jbtac = Module(new JBTAC)
124  jbtac.io.in.pc <> io.in.pc
125  jbtac.io.in.pcLatch := pcLatch
126  jbtac.io.in.hist := hist
127  jbtac.io.redirectValid := io.redirectInfo.valid
128  jbtac.io.flush := io.flush
129
130  jbtac.io.update.fetchPC := updateFetchpc
131  jbtac.io.update.fetchIdx := r.fetchIdx << 1
132  jbtac.io.update.misPred := io.redirectInfo.misPred
133  jbtac.io.update._type := r._type
134  jbtac.io.update.target := r.target
135  jbtac.io.update.hist := r.hist
136
137  val jbtacHit = jbtac.io.out.hit
138  val jbtacTarget = jbtac.io.out.target
139  val jbtacHitIdx = jbtac.io.out.hitIdx
140
141  // calculate global history of each instr
142  val firstHist = RegNext(hist)
143  val histShift = Wire(Vec(FetchWidth, UInt(log2Up(FetchWidth).W)))
144  val shift = Wire(Vec(FetchWidth, Vec(FetchWidth, UInt(1.W))))
145  (0 until FetchWidth).map(i => shift(i) := Mux(!btbNotTakens(i), 0.U, ~LowerMask(UIntToOH(i.U), FetchWidth)).asTypeOf(Vec(FetchWidth, UInt(1.W))))
146  for (j <- 0 until FetchWidth) {
147    var tmp = 0.U
148    for (i <- 0 until FetchWidth) {
149      tmp = tmp + shift(i)(j)
150    }
151    histShift(j) := tmp
152  }
153  (0 until FetchWidth).map(i => io.s1OutPred.bits.hist(i) := firstHist << histShift(i))
154
155  // update ghr
156  updateGhr := io.s1OutPred.bits.redirect || io.flush
157  val brJumpIdx = Mux(!(btbHit && btbTaken), 0.U, UIntToOH(btbTakenIdx))
158  val indirectIdx = Mux(!jbtacHit, 0.U, UIntToOH(jbtacHitIdx))
159  //val newTaken = Mux(io.redirectInfo.flush(), !(r._type === BTBtype.B && !r.taken), )
160  newGhr := Mux(io.redirectInfo.flush(),    (r.hist << 1.U) | !(r._type === BTBtype.B && !r.taken),
161            Mux(io.flush,                   Mux(io.s3Taken, (io.s3RollBackHist << 1.U) | 1.U, io.s3RollBackHist),
162            Mux(io.s1OutPred.bits.redirect, (PriorityMux(brJumpIdx | indirectIdx, io.s1OutPred.bits.hist) << 1.U | 1.U),
163                                            io.s1OutPred.bits.hist(0) << PopCount(btbNotTakens))))
164
165  // redirect based on BTB and JBTAC
166  // io.out.valid := RegNext(io.in.pc.fire()) && !flushS1u
167  io.out.valid := RegNext(io.in.pc.fire()) && !io.flush
168
169  io.s1OutPred.valid := io.out.valid
170  io.s1OutPred.bits.redirect := btbHit && btbTaken || jbtacHit
171  // io.s1OutPred.bits.instrValid := LowerMask(UIntToOH(btbTakenIdx), FetchWidth) & LowerMask(UIntToOH(jbtacHitIdx), FetchWidth)
172  io.s1OutPred.bits.instrValid := Mux(io.s1OutPred.bits.redirect, LowerMask(LowestBit(brJumpIdx | indirectIdx, FetchWidth), FetchWidth), Fill(FetchWidth, 1.U(1.W))).asTypeOf(Vec(FetchWidth, Bool()))
173  io.s1OutPred.bits.target := Mux(brJumpIdx === LowestBit(brJumpIdx | indirectIdx, FetchWidth), btbTakenTarget, jbtacTarget)
174  // io.s1OutPred.bits.btbVictimWay := btbWriteWay
175  io.s1OutPred.bits.predCtr := btbCtrs
176  io.s1OutPred.bits.btbHitWay := btbHit
177  io.s1OutPred.bits.rasSp := DontCare
178  io.s1OutPred.bits.rasTopCtr := DontCare
179
180  io.out.bits.pc := pcLatch
181  io.out.bits.btb.hits := btbValids.asUInt
182  (0 until FetchWidth).map(i => io.out.bits.btb.targets(i) := btbTargets(i))
183  io.out.bits.jbtac.hitIdx := UIntToOH(jbtacHitIdx)
184  io.out.bits.jbtac.target := jbtacTarget
185  // TODO: we don't need this repeatedly!
186  io.out.bits.hist := io.s1OutPred.bits.hist
187  io.out.bits.btbPred := io.s1OutPred
188
189
190
191  // debug info
192  XSDebug(true.B, "[BPUS1]in:(%d %d)   pc=%x ghr=%b\n", io.in.pc.valid, io.in.pc.ready, io.in.pc.bits, hist)
193  XSDebug(true.B, "[BPUS1]outPred:(%d) pc=0x%x, redirect=%d instrValid=%b tgt=%x\n",
194    io.s1OutPred.valid, pcLatch, io.s1OutPred.bits.redirect, io.s1OutPred.bits.instrValid.asUInt, io.s1OutPred.bits.target)
195  XSDebug(io.flush && io.redirectInfo.flush(),
196    "[BPUS1]flush from backend: pc=%x tgt=%x brTgt=%x _type=%b taken=%d oldHist=%b fetchIdx=%d isExcpt=%d\n",
197    r.pc, r.target, r.brTarget, r._type, r.taken, r.hist, r.fetchIdx, r.isException)
198  XSDebug(io.flush && !io.redirectInfo.flush(),
199    "[BPUS1]flush from Stage3:  s3Taken=%d s3RollBackHist=%b\n", io.s3Taken, io.s3RollBackHist)
200
201}
202
203class Stage2To3IO extends Stage1To2IO {
204}
205
206class BPUStage2 extends XSModule {
207  val io = IO(new Bundle() {
208    // flush from Stage3
209    val flush = Input(Bool())
210    val in = Flipped(Decoupled(new Stage1To2IO))
211    val out = Decoupled(new Stage2To3IO)
212  })
213
214  // flush Stage2 when Stage3 or banckend redirects
215  val flushS2 = BoolStopWatch(io.flush, io.in.fire(), startHighPriority = true)
216  val inLatch = RegInit(0.U.asTypeOf(io.in.bits))
217  when (io.in.fire()) { inLatch := io.in.bits }
218  val validLatch = RegInit(false.B)
219  when (io.flush) {
220    validLatch := false.B
221  }.elsewhen (io.in.fire()) {
222    validLatch := true.B
223  }.elsewhen (io.out.fire()) {
224    validLatch := false.B
225  }
226
227  io.out.valid := !io.flush && !flushS2 && validLatch
228  io.in.ready := !validLatch || io.out.fire()
229
230  // do nothing
231  io.out.bits := inLatch
232
233  // debug info
234  XSDebug(true.B, "[BPUS2]in:(%d %d) pc=%x out:(%d %d) pc=%x\n",
235    io.in.valid, io.in.ready, io.in.bits.pc, io.out.valid, io.out.ready, io.out.bits.pc)
236  XSDebug(true.B, "[BPUS2]validLatch=%d pc=%x\n", validLatch, inLatch.pc)
237  XSDebug(io.flush, "[BPUS2]flush!!!\n")
238}
239
240class BPUStage3 extends XSModule {
241  val io = IO(new Bundle() {
242    val flush = Input(Bool())
243    val in = Flipped(Decoupled(new Stage2To3IO))
244    val out = ValidIO(new BranchPrediction)
245    // from icache
246    val predecode = Flipped(ValidIO(new Predecode))
247    // from backend
248    val redirectInfo = Input(new RedirectInfo)
249    // to Stage1 and Stage2
250    val flushBPU = Output(Bool())
251    // to Stage1, restore ghr in stage1 when flushBPU is valid
252    val s1RollBackHist = Output(UInt(HistoryLength.W))
253    val s3Taken = Output(Bool())
254  })
255
256  val flushS3 = BoolStopWatch(io.flush, io.in.fire(), startHighPriority = true)
257  val inLatch = RegInit(0.U.asTypeOf(io.in.bits))
258  val validLatch = RegInit(false.B)
259  when (io.in.fire()) { inLatch := io.in.bits }
260  when (io.flush) {
261    validLatch := false.B
262  }.elsewhen (io.in.fire()) {
263    validLatch := true.B
264  }.elsewhen (io.out.valid) {
265    validLatch := false.B
266  }
267  io.out.valid := validLatch && io.predecode.valid && !flushS3 && !io.flush
268  io.in.ready := !validLatch || io.out.valid
269
270  // RAS
271  // TODO: split retAddr and ctr
272  def rasEntry() = new Bundle {
273    val retAddr = UInt(VAddrBits.W)
274    val ctr = UInt(8.W) // layer of nested call functions
275  }
276  val ras = RegInit(VecInit(Seq.fill(RasSize)(0.U.asTypeOf(rasEntry()))))
277  val sp = Counter(RasSize)
278  val rasTop = ras(sp.value)
279  val rasTopAddr = rasTop.retAddr
280
281  // get the first taken branch/jal/call/jalr/ret in a fetch line
282  // brTakenIdx/jalIdx/callIdx/jalrIdx/retIdx/jmpIdx is one-hot encoded.
283  // brNotTakenIdx indicates all the not-taken branches before the first jump instruction.
284  val brIdx = inLatch.btb.hits & Reverse(Cat(io.predecode.bits.fuOpTypes.map { t => ALUOpType.isBranch(t) }).asUInt) & io.predecode.bits.mask
285  val brTakenIdx = LowestBit(brIdx & inLatch.tage.takens.asUInt, FetchWidth)
286  val jalIdx = LowestBit(inLatch.btb.hits & Reverse(Cat(io.predecode.bits.fuOpTypes.map { t => t === BRUOpType.jal }).asUInt) & io.predecode.bits.mask, FetchWidth)
287  val callIdx = LowestBit(inLatch.btb.hits & io.predecode.bits.mask & Reverse(Cat(io.predecode.bits.fuOpTypes.map { t => t === BRUOpType.call }).asUInt), FetchWidth)
288  val jalrIdx = LowestBit(inLatch.jbtac.hitIdx & io.predecode.bits.mask & Reverse(Cat(io.predecode.bits.fuOpTypes.map { t => t === BRUOpType.jalr }).asUInt), FetchWidth)
289  val retIdx = LowestBit(io.predecode.bits.mask & Reverse(Cat(io.predecode.bits.fuOpTypes.map { t => t === BRUOpType.ret }).asUInt), FetchWidth)
290
291  val jmpIdx = LowestBit(brTakenIdx | jalIdx | callIdx | jalrIdx | retIdx, FetchWidth)
292  val brNotTakenIdx = brIdx & ~inLatch.tage.takens.asUInt & LowerMask(jmpIdx, FetchWidth) & io.predecode.bits.mask
293
294  io.out.bits.redirect := jmpIdx.orR.asBool
295  io.out.bits.target := Mux(jmpIdx === retIdx, rasTopAddr,
296    Mux(jmpIdx === jalrIdx, inLatch.jbtac.target,
297    Mux(jmpIdx === 0.U, inLatch.pc + 32.U, // TODO: RVC
298    PriorityMux(jmpIdx, inLatch.btb.targets))))
299  io.out.bits.instrValid := Mux(jmpIdx.orR, LowerMask(jmpIdx, FetchWidth), Fill(FetchWidth, 1.U(1.W))).asTypeOf(Vec(FetchWidth, Bool()))
300  // io.out.bits.btbVictimWay := inLatch.btbPred.bits.btbVictimWay
301  io.out.bits.predCtr := inLatch.btbPred.bits.predCtr
302  io.out.bits.btbHitWay := inLatch.btbPred.bits.btbHitWay
303  io.out.bits.tageMeta := inLatch.btbPred.bits.tageMeta
304  //io.out.bits._type := Mux(jmpIdx === retIdx, BTBtype.R,
305  //  Mux(jmpIdx === jalrIdx, BTBtype.I,
306  //  Mux(jmpIdx === brTakenIdx, BTBtype.B, BTBtype.J)))
307  val firstHist = inLatch.btbPred.bits.hist(0)
308  // there may be several notTaken branches before the first jump instruction,
309  // so we need to calculate how many zeroes should each instruction shift in its global history.
310  // each history is exclusive of instruction's own jump direction.
311  val histShift = Wire(Vec(FetchWidth, UInt(log2Up(FetchWidth).W)))
312  val shift = Wire(Vec(FetchWidth, Vec(FetchWidth, UInt(1.W))))
313  (0 until FetchWidth).map(i => shift(i) := Mux(!brNotTakenIdx(i), 0.U, ~LowerMask(UIntToOH(i.U), FetchWidth)).asTypeOf(Vec(FetchWidth, UInt(1.W))))
314  for (j <- 0 until FetchWidth) {
315    var tmp = 0.U
316    for (i <- 0 until FetchWidth) {
317      tmp = tmp + shift(i)(j)
318    }
319    histShift(j) := tmp
320  }
321  (0 until FetchWidth).map(i => io.out.bits.hist(i) := firstHist << histShift(i))
322  // save ras checkpoint info
323  io.out.bits.rasSp := sp.value
324  io.out.bits.rasTopCtr := rasTop.ctr
325
326  // flush BPU and redirect when target differs from the target predicted in Stage1
327  io.out.bits.redirect := (if(EnableBPD) (inLatch.btbPred.bits.redirect ^ jmpIdx.orR.asBool ||
328    inLatch.btbPred.bits.redirect && jmpIdx.orR.asBool && io.out.bits.target =/= inLatch.btbPred.bits.target)
329    else false.B)
330  io.flushBPU := io.out.bits.redirect && io.out.valid
331
332  // speculative update RAS
333  val rasWrite = WireInit(0.U.asTypeOf(rasEntry()))
334  rasWrite.retAddr := inLatch.pc + (OHToUInt(callIdx) << 2.U) + 4.U
335  val allocNewEntry = rasWrite.retAddr =/= rasTopAddr
336  rasWrite.ctr := Mux(allocNewEntry, 1.U, rasTop.ctr + 1.U)
337  when (io.out.valid) {
338    when (jmpIdx === callIdx) {
339      ras(Mux(allocNewEntry, sp.value + 1.U, sp.value)) := rasWrite
340      when (allocNewEntry) { sp.value := sp.value + 1.U }
341    }.elsewhen (jmpIdx === retIdx) {
342      when (rasTop.ctr === 1.U) {
343        sp.value := Mux(sp.value === 0.U, 0.U, sp.value - 1.U)
344      }.otherwise {
345        ras(sp.value) := Cat(rasTop.ctr - 1.U, rasTopAddr).asTypeOf(rasEntry())
346      }
347    }
348  }
349  // use checkpoint to recover RAS
350  val recoverSp = io.redirectInfo.redirect.rasSp
351  val recoverCtr = io.redirectInfo.redirect.rasTopCtr
352  when (io.redirectInfo.valid && io.redirectInfo.misPred) {
353    sp.value := recoverSp
354    ras(recoverSp) := Cat(recoverCtr, ras(recoverSp).retAddr).asTypeOf(rasEntry())
355  }
356
357  // roll back global history in S1 if S3 redirects
358  io.s1RollBackHist := Mux(io.s3Taken, PriorityMux(jmpIdx, io.out.bits.hist), io.out.bits.hist(0) << PopCount(brIdx & ~inLatch.tage.takens.asUInt))
359  // whether Stage3 has a taken jump
360  io.s3Taken := jmpIdx.orR.asBool
361
362  // debug info
363  XSDebug(io.in.fire(), "[BPUS3]in:(%d %d) pc=%x\n", io.in.valid, io.in.ready, io.in.bits.pc)
364  XSDebug(io.out.valid, "[BPUS3]out:%d pc=%x redirect=%d predcdMask=%b instrValid=%b tgt=%x\n",
365    io.out.valid, inLatch.pc, io.out.bits.redirect, io.predecode.bits.mask, io.out.bits.instrValid.asUInt, io.out.bits.target)
366  XSDebug(true.B, "[BPUS3]flushS3=%d\n", flushS3)
367  XSDebug(true.B, "[BPUS3]validLatch=%d predecode.valid=%d\n", validLatch, io.predecode.valid)
368  XSDebug(true.B, "[BPUS3]brIdx=%b brTakenIdx=%b brNTakenIdx=%b jalIdx=%b jalrIdx=%b callIdx=%b retIdx=%b\n",
369    brIdx, brTakenIdx, brNotTakenIdx, jalIdx, jalrIdx, callIdx, retIdx)
370
371  // BPU's TEMP Perf Cnt
372  BoringUtils.addSource(io.out.valid, "MbpS3Cnt")
373  BoringUtils.addSource(io.out.valid && io.out.bits.redirect, "MbpS3TageRed")
374  BoringUtils.addSource(io.out.valid && (inLatch.btbPred.bits.redirect ^ jmpIdx.orR.asBool), "MbpS3TageRedDir")
375  BoringUtils.addSource(io.out.valid && (inLatch.btbPred.bits.redirect
376              && jmpIdx.orR.asBool && (io.out.bits.target =/= inLatch.btbPred.bits.target)), "MbpS3TageRedTar")
377}
378
379class BPU extends XSModule {
380  val io = IO(new Bundle() {
381    // from backend
382    // flush pipeline if misPred and update bpu based on redirect signals from brq
383    val redirectInfo = Input(new RedirectInfo)
384
385    val in = new Bundle { val pc = Flipped(Valid(UInt(VAddrBits.W))) }
386
387    val btbOut = ValidIO(new BranchPrediction)
388    val tageOut = ValidIO(new BranchPrediction)
389
390    // predecode info from icache
391    // TODO: simplify this after implement predecode unit
392    val predecode = Flipped(ValidIO(new Predecode))
393  })
394
395  val s1 = Module(new BPUStage1)
396  val s2 = Module(new BPUStage2)
397  val s3 = Module(new BPUStage3)
398
399  s1.io.redirectInfo <> io.redirectInfo
400  s1.io.flush := s3.io.flushBPU || io.redirectInfo.flush()
401  s1.io.in.pc.valid := io.in.pc.valid
402  s1.io.in.pc.bits <> io.in.pc.bits
403  io.btbOut <> s1.io.s1OutPred
404  s1.io.s3RollBackHist := s3.io.s1RollBackHist
405  s1.io.s3Taken := s3.io.s3Taken
406
407  s1.io.out <> s2.io.in
408  s2.io.flush := s3.io.flushBPU || io.redirectInfo.flush()
409
410  s2.io.out <> s3.io.in
411  s3.io.flush := io.redirectInfo.flush()
412  s3.io.predecode <> io.predecode
413  io.tageOut <> s3.io.out
414  s3.io.redirectInfo <> io.redirectInfo
415
416  // TODO: temp and ugly code, when perf counters is added( may after adding CSR), please mv the below counter
417  val bpuPerfCntList = List(
418    ("MbpInstr","         "),
419    ("MbpRight","         "),
420    ("MbpWrong","         "),
421    ("MbpBRight","        "),
422    ("MbpBWrong","        "),
423    ("MbpJRight","        "),
424    ("MbpJWrong","        "),
425    ("MbpIRight","        "),
426    ("MbpIWrong","        "),
427    ("MbpRRight","        "),
428    ("MbpRWrong","        "),
429    ("MbpS3Cnt","         "),
430    ("MbpS3TageRed","     "),
431    ("MbpS3TageRedDir","  "),
432    ("MbpS3TageRedTar","  ")
433  )
434
435  val bpuPerfCnts = List.fill(bpuPerfCntList.length)(RegInit(0.U(XLEN.W)))
436  val bpuPerfCntConds = List.fill(bpuPerfCntList.length)(WireInit(false.B))
437  (bpuPerfCnts zip bpuPerfCntConds) map { case (cnt, cond) => { when (cond) { cnt := cnt + 1.U }}}
438
439  for(i <- bpuPerfCntList.indices) {
440    BoringUtils.addSink(bpuPerfCntConds(i), bpuPerfCntList(i)._1)
441  }
442
443  val xsTrap = WireInit(false.B)
444  BoringUtils.addSink(xsTrap, "XSTRAP_BPU")
445
446  // if (!p.FPGAPlatform) {
447    when (xsTrap) {
448      printf("=================BPU's PerfCnt================\n")
449      for(i <- bpuPerfCntList.indices) {
450        printf(bpuPerfCntList(i)._1 + bpuPerfCntList(i)._2 + " <- " + "%d\n", bpuPerfCnts(i))
451      }
452    }
453  // }
454}