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