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 chisel3._ 20import chisel3.util._ 21import org.chipsalliance.cde.config.Parameters 22import utility._ 23import utils._ 24import xiangshan._ 25import xiangshan.ExceptionNO._ 26 27class IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](p => p(XSCoreParamsKey).IBufSize) {} 28 29class IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](p => 30 p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank 31 ) {} 32 33class IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](p => p(XSCoreParamsKey).IBufNBank) {} 34 35class IBufferIO(implicit p: Parameters) extends XSBundle { 36 val flush = Input(Bool()) 37 val ControlRedirect = Input(Bool()) 38 val ControlBTBMissBubble = Input(Bool()) 39 val TAGEMissBubble = Input(Bool()) 40 val SCMissBubble = Input(Bool()) 41 val ITTAGEMissBubble = Input(Bool()) 42 val RASMissBubble = Input(Bool()) 43 val MemVioRedirect = Input(Bool()) 44 val in = Flipped(DecoupledIO(new FetchToIBuffer)) 45 val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow)) 46 val full = Output(Bool()) 47 val decodeCanAccept = Input(Bool()) 48 val stallReason = new StallReasonIO(DecodeWidth) 49} 50 51class IBufEntry(implicit p: Parameters) extends XSBundle { 52 val inst = UInt(32.W) 53 val pc = UInt(VAddrBits.W) 54 val foldpc = UInt(MemPredPCWidth.W) 55 val pd = new PreDecodeInfo 56 val pred_taken = Bool() 57 val ftqPtr = new FtqPtr 58 val ftqOffset = UInt(log2Ceil(PredictWidth).W) 59 val exceptionType = IBufferExceptionType() 60 val backendException = Bool() 61 val triggered = TriggerAction() 62 val isLastInFtqEntry = Bool() 63 val debug_seqNum = InstSeqNum() 64 65 def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = { 66 inst := fetch.instrs(i) 67 pc := fetch.pc(i) 68 foldpc := fetch.foldpc(i) 69 pd := fetch.pd(i) 70 pred_taken := fetch.ftqOffset(i).valid 71 ftqPtr := fetch.ftqPtr 72 ftqOffset := fetch.ftqOffset(i).bits 73 exceptionType := IBufferExceptionType.cvtFromFetchExcpAndCrossPageAndRVCII( 74 fetch.exceptionType(i), 75 fetch.crossPageIPFFix(i), 76 fetch.illegalInstr(i) 77 ) 78 backendException := fetch.backendException(i) 79 triggered := fetch.triggered(i) 80 isLastInFtqEntry := fetch.isLastInFtqEntry(i) 81 debug_seqNum := fetch.debug_seqNum(i) 82 this 83 } 84 85 def toCtrlFlow: CtrlFlow = { 86 val cf = Wire(new CtrlFlow) 87 cf.instr := inst 88 cf.pc := pc 89 cf.foldpc := foldpc 90 cf.exceptionVec := 0.U.asTypeOf(ExceptionVec()) 91 cf.exceptionVec(instrPageFault) := IBufferExceptionType.isPF(this.exceptionType) 92 cf.exceptionVec(instrGuestPageFault) := IBufferExceptionType.isGPF(this.exceptionType) 93 cf.exceptionVec(instrAccessFault) := IBufferExceptionType.isAF(this.exceptionType) 94 cf.exceptionVec(EX_II) := IBufferExceptionType.isRVCII(this.exceptionType) 95 cf.backendException := backendException 96 cf.trigger := triggered 97 cf.pd := pd 98 cf.pred_taken := pred_taken 99 cf.crossPageIPFFix := IBufferExceptionType.isCrossPage(this.exceptionType) 100 cf.storeSetHit := DontCare 101 cf.waitForRobIdx := DontCare 102 cf.loadWaitBit := DontCare 103 cf.loadWaitStrict := DontCare 104 cf.ssid := DontCare 105 cf.ftqPtr := ftqPtr 106 cf.ftqOffset := ftqOffset 107 cf.isLastInFtqEntry := isLastInFtqEntry 108 cf.debug_seqNum := debug_seqNum 109 cf 110 } 111 112 object IBufferExceptionType extends NamedUInt(3) { 113 def None = "b000".U 114 def NonCrossPF = "b001".U 115 def NonCrossGPF = "b010".U 116 def NonCrossAF = "b011".U 117 // illegal instruction 118 def rvcII = "b100".U 119 def CrossPF = "b101".U 120 def CrossGPF = "b110".U 121 def CrossAF = "b111".U 122 123 def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: UInt, crossPage: Bool, rvcIll: Bool): UInt = { 124 require( 125 fetchExcp.getWidth == ExceptionType.width, 126 s"The width(${fetchExcp.getWidth}) of fetchExcp should be equal to " + 127 s"the width(${ExceptionType.width}) of frontend.ExceptionType." 128 ) 129 MuxCase( 130 0.U, 131 Seq( 132 crossPage -> Cat(1.U(1.W), fetchExcp), 133 fetchExcp.orR -> fetchExcp, 134 rvcIll -> this.rvcII 135 ) 136 ) 137 } 138 139 def isRVCII(uint: UInt): Bool = { 140 this.checkInputWidth(uint) 141 uint(2) && uint(1, 0) === 0.U 142 } 143 144 def isCrossPage(uint: UInt): Bool = { 145 this.checkInputWidth(uint) 146 uint(2) && uint(1, 0) =/= 0.U 147 } 148 149 def isPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0) 150 def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0) 151 def isAF(uint: UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0) 152 } 153} 154 155class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents { 156 val io = IO(new IBufferIO) 157 158 // io alias 159 private val decodeCanAccept = io.decodeCanAccept 160 161 // Parameter Check 162 private val bankSize = IBufSize / IBufNBank 163 require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize") 164 require( 165 IBufNBank >= DecodeWidth, 166 s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth" 167 ) 168 169 // IBuffer is organized as raw registers 170 // This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled 171 // . + + E E E - . 172 // . + + E E E - . 173 // . . + E E E - . 174 // . . + E E E E - 175 // As shown above, + means enqueue, - means dequeue, E is current content 176 // When dequeue, read port is organized like a banked FIFO 177 // Dequeue reads no more than 1 entry from each bank sequentially, this can be exploit to reduce area 178 // Enqueue writes cannot benefit from this characteristic unless use a SRAM 179 // For detail see Enqueue and Dequeue below 180 private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry))) 181 private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(bankID => 182 VecInit.tabulate(bankSize)(inBankOffset => ibuf(bankID + inBankOffset * IBufNBank)) 183 ) 184 185 // Bypass wire 186 private val bypassEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 187 // Normal read wire 188 private val deqEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 189 // Output register 190 private val outputEntries = RegInit(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 191 private val outputEntriesValidNum = 192 PriorityMuxDefault(outputEntries.map(_.valid).zip(Seq.range(1, DecodeWidth).map(_.U)).reverse.toSeq, 0.U) 193 194 // Between Bank 195 private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr))) 196 private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0) 197 private val deqBankPtrVecNext = Wire(deqBankPtrVec.cloneType) 198 // Inside Bank 199 private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))) 200 private val deqInBankPtrNext = Wire(deqInBankPtr.cloneType) 201 202 val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr)) 203 val deqPtrNext = Wire(deqPtr.cloneType) 204 205 val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr))) 206 val enqPtr = enqPtrVec(0) 207 208 val numTryEnq = WireDefault(0.U) 209 val numEnq = Mux(io.in.fire, numTryEnq, 0.U) 210 211 // empty and decode can accept insts 212 val useBypass = enqPtr === deqPtr && decodeCanAccept 213 214 // The number of decode accepted insts. 215 // Since decode promises accepting insts in order, use priority encoder to simplify the accumulation. 216 private val numOut = Wire(UInt(log2Ceil(DecodeWidth).W)) 217 private val numDeq = numOut 218 219 // counter current number of valid 220 val numValid = distanceBetween(enqPtr, deqPtr) 221 val numValidAfterDeq = numValid - numDeq 222 // counter next number of valid 223 val numValidNext = numValid + numEnq - numDeq 224 val allowEnq = RegInit(true.B) 225 val numFromFetch = Mux(io.in.valid, PopCount(io.in.bits.enqEnable), 0.U) 226 227 allowEnq := (IBufSize - PredictWidth).U >= numValidNext // Disable when almost full 228 229 val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i))) 230 val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i)) 231 232 val outputEntriesIsNotFull = !outputEntries(DecodeWidth - 1).valid 233 when(decodeCanAccept) { 234 numOut := Mux(numValid >= DecodeWidth.U, DecodeWidth.U, numValid) 235 }.elsewhen(outputEntriesIsNotFull) { 236 numOut := Mux(numValid >= DecodeWidth.U - outputEntriesValidNum, DecodeWidth.U - outputEntriesValidNum, numValid) 237 }.otherwise { 238 numOut := 0.U 239 } 240 val numBypass = Wire(UInt(log2Ceil(DecodeWidth).W)) 241 // when using bypass, bypassed entries do not enqueue 242 when(useBypass) { 243 when(numFromFetch >= DecodeWidth.U) { 244 numTryEnq := numFromFetch - DecodeWidth.U 245 numBypass := DecodeWidth.U 246 }.otherwise { 247 numTryEnq := 0.U 248 numBypass := numFromFetch 249 } 250 }.otherwise { 251 numTryEnq := numFromFetch 252 numBypass := 0.U 253 } 254 255 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 256 // Bypass 257 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 258 bypassEntries.zipWithIndex.foreach { 259 case (entry, idx) => 260 // Select 261 val validOH = Range(0, PredictWidth).map { 262 i => 263 io.in.bits.valid(i) && 264 io.in.bits.enqEnable(i) && 265 enqOffset(i) === idx.asUInt 266 } // Should be OneHot 267 entry.valid := validOH.reduce(_ || _) && io.in.fire && !io.flush 268 entry.bits := Mux1H(validOH, enqData) 269 270 // Debug Assertion 271 XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot") 272 } 273 274 // => Decode Output 275 // clean register output 276 io.out zip outputEntries foreach { 277 case (io, reg) => 278 io.valid := reg.valid 279 io.bits := reg.bits.toCtrlFlow 280 } 281 (outputEntries zip bypassEntries).zipWithIndex.foreach { 282 case ((out, bypass), i) => 283 when(decodeCanAccept) { 284 when(useBypass && io.in.valid) { 285 out := bypass 286 }.otherwise { 287 out := deqEntries(i) 288 } 289 }.elsewhen(outputEntriesIsNotFull) { 290 out.valid := deqEntries(i).valid 291 out.bits := Mux( 292 i.U < outputEntriesValidNum, 293 out.bits, 294 VecInit(deqEntries.take(i + 1).map(_.bits))(i.U - outputEntriesValidNum) 295 ) 296 } 297 } 298 299 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 300 // Enqueue 301 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 302 io.in.ready := allowEnq 303 // Data 304 ibuf.zipWithIndex.foreach { 305 case (entry, idx) => { 306 // Select 307 val validOH = Range(0, PredictWidth).map { 308 i => 309 val useBypassMatch = enqOffset(i) >= DecodeWidth.U && 310 enqPtrVec(enqOffset(i) - DecodeWidth.U).value === idx.asUInt 311 val normalMatch = enqPtrVec(enqOffset(i)).value === idx.asUInt 312 val m = Mux(useBypass, useBypassMatch, normalMatch) // when using bypass, bypassed entries do not enqueue 313 314 io.in.bits.valid(i) && io.in.bits.enqEnable(i) && m 315 } // Should be OneHot 316 val wen = validOH.reduce(_ || _) && io.in.fire && !io.flush 317 318 // Write port 319 // Each IBuffer entry has a PredictWidth -> 1 Mux 320 val writeEntry = Mux1H(validOH, enqData) 321 entry := Mux(wen, writeEntry, entry) 322 323 // Debug Assertion 324 XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot") 325 } 326 } 327 // Pointer maintenance 328 when(io.in.fire && !io.flush) { 329 enqPtrVec := VecInit(enqPtrVec.map(_ + numTryEnq)) 330 } 331 332 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 333 // Dequeue 334 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 335 val outputEntriesValidNumNext = Wire(UInt(log2Ceil(DecodeWidth).W)) 336 XSError(outputEntriesValidNumNext > DecodeWidth.U, "Ibuffer: outputEntriesValidNumNext > DecodeWidth.U") 337 val validVec = UIntToMask(outputEntriesValidNumNext(log2Ceil(DecodeWidth) - 1, 0), DecodeWidth) 338 when(decodeCanAccept) { 339 outputEntriesValidNumNext := Mux(useBypass, numBypass, numDeq) 340 }.elsewhen(outputEntriesIsNotFull) { 341 outputEntriesValidNumNext := outputEntriesValidNum + numDeq 342 }.otherwise { 343 outputEntriesValidNumNext := outputEntriesValidNum 344 } 345 // Data 346 // Read port 347 // 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1 348 // Should be better than IBufSize -> 1 in area, with no significant latency increase 349 private val readStage1: Vec[IBufEntry] = 350 VecInit.tabulate(IBufNBank)(bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID))) 351 for (i <- 0 until DecodeWidth) { 352 deqEntries(i).valid := validVec(i) 353 deqEntries(i).bits := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1) 354 } 355 // Pointer maintenance 356 deqBankPtrVecNext := VecInit(deqBankPtrVec.map(_ + numDeq)) 357 deqPtrNext := deqPtr + numDeq 358 deqInBankPtrNext.zip(deqInBankPtr).zipWithIndex.foreach { 359 case ((ptrNext, ptr), idx) => { 360 // validVec[k] == bankValid[deqBankPtr + k] 361 // So bankValid[n] == validVec[n - deqBankPtr] 362 val validIdx = Mux( 363 idx.asUInt >= deqBankPtr.value, 364 idx.asUInt - deqBankPtr.value, 365 ((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0) 366 )(log2Ceil(DecodeWidth) - 1, 0) 367 val bankAdvance = numOut > validIdx 368 ptrNext := Mux(bankAdvance, ptr + 1.U, ptr) 369 } 370 } 371 372 // Flush 373 when(io.flush) { 374 allowEnq := true.B 375 enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr)) 376 deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr)) 377 deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)) 378 deqPtr := 0.U.asTypeOf(new IBufPtr()) 379 outputEntries.foreach(_.valid := false.B) 380 }.otherwise { 381 deqPtr := deqPtrNext 382 deqInBankPtr := deqInBankPtrNext 383 deqBankPtrVec := deqBankPtrVecNext 384 } 385 io.full := !allowEnq 386 387 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 388 // TopDown 389 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 390 val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 391 topdown_stage := io.in.bits.topdown_info 392 when(io.flush) { 393 when(io.ControlRedirect) { 394 when(io.ControlBTBMissBubble) { 395 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 396 }.elsewhen(io.TAGEMissBubble) { 397 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 398 }.elsewhen(io.SCMissBubble) { 399 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 400 }.elsewhen(io.ITTAGEMissBubble) { 401 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 402 }.elsewhen(io.RASMissBubble) { 403 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 404 } 405 }.elsewhen(io.MemVioRedirect) { 406 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 407 }.otherwise { 408 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 409 } 410 } 411 412 val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W)) 413 val deqValidCount = PopCount(validVec.asBools) 414 val deqWasteCount = DecodeWidth.U - deqValidCount 415 matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse) 416 417 io.stallReason.reason.map(_ := 0.U) 418 for (i <- 0 until DecodeWidth) { 419 when(i.U < deqWasteCount) { 420 io.stallReason.reason(DecodeWidth - i - 1) := matchBubble 421 } 422 } 423 424 when(!(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR)) { 425 // should set reason for FetchFragmentationStall 426 // topdown_stage.reasons(TopDownCounters.FetchFragmentationStall.id) := true.B 427 for (i <- 0 until DecodeWidth) { 428 when(i.U < deqWasteCount) { 429 io.stallReason.reason(DecodeWidth - i - 1) := TopDownCounters.FetchFragBubble.id.U 430 } 431 } 432 } 433 434 when(io.stallReason.backReason.valid) { 435 io.stallReason.reason.map(_ := io.stallReason.backReason.bits) 436 } 437 438 // Debug info 439 XSError( 440 deqPtr.value =/= deqBankPtr.value + deqInBankPtr(deqBankPtr.value).value * IBufNBank.asUInt, 441 "Dequeue PTR mismatch" 442 ) 443 XSError(isBefore(enqPtr, deqPtr) && !isFull(enqPtr, deqPtr), "\ndeqPtr is older than enqPtr!\n") 444 445 XSDebug(io.flush, "IBuffer Flushed\n") 446 447 XSDebug(io.in.fire, "Enque:\n") 448 XSDebug(io.in.fire, p"MASK=${Binary(io.in.bits.valid)}\n") 449 for (i <- 0 until PredictWidth) { 450 XSDebug(io.in.fire, p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n") 451 } 452 453 for (i <- 0 until DecodeWidth) { 454 XSDebug( 455 io.out(i).fire, 456 p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" + 457 p"v=${io.out(i).valid} r=${io.out(i).ready} " + 458 p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n" 459 ) 460 } 461 462 XSDebug(p"numValid: ${numValid}\n") 463 XSDebug(p"EnqNum: ${numEnq}\n") 464 XSDebug(p"DeqNum: ${numDeq}\n") 465 466 val afterInit = RegInit(false.B) 467 val headBubble = RegInit(false.B) 468 when(io.in.fire)(afterInit := true.B) 469 when(io.flush) { 470 headBubble := true.B 471 }.elsewhen(numValid =/= 0.U) { 472 headBubble := false.B 473 } 474 val instrHungry = afterInit && (numValid === 0.U) && !headBubble 475 476 QueuePerf(IBufSize, numValid, !allowEnq) 477 XSPerfAccumulate("flush", io.flush) 478 XSPerfAccumulate("hungry", instrHungry) 479 480 val ibuffer_IDWidth_hvButNotFull = afterInit && (numValid =/= 0.U) && (numValid < DecodeWidth.U) && !headBubble 481 XSPerfAccumulate("ibuffer_IDWidth_hvButNotFull", ibuffer_IDWidth_hvButNotFull) 482 483 val FrontBubble = Mux(decodeCanAccept && !headBubble, DecodeWidth.U - numOut, 0.U) 484 485 val fetchLatency = decodeCanAccept && !headBubble && numOut === 0.U 486 487 XSPerfAccumulate("if_fetch_bubble", FrontBubble) 488 XSPerfAccumulate("if_fetch_bubble_eq_max", fetchLatency) 489 490 val perfEvents = Seq( 491 ("IBuffer_Flushed ", io.flush), 492 ("IBuffer_hungry ", instrHungry), 493 ("IBuffer_1_4_valid", (numValid > (0 * (IBufSize / 4)).U) & (numValid < (1 * (IBufSize / 4)).U)), 494 ("IBuffer_2_4_valid", (numValid >= (1 * (IBufSize / 4)).U) & (numValid < (2 * (IBufSize / 4)).U)), 495 ("IBuffer_3_4_valid", (numValid >= (2 * (IBufSize / 4)).U) & (numValid < (3 * (IBufSize / 4)).U)), 496 ("IBuffer_4_4_valid", (numValid >= (3 * (IBufSize / 4)).U) & (numValid < (4 * (IBufSize / 4)).U)), 497 ("IBuffer_full ", numValid.andR), 498 ("Front_Bubble ", FrontBubble), 499 ("Fetch_Latency_Bound", fetchLatency) 500 ) 501 generatePerfEvent() 502} 503