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