xref: /XiangShan/src/main/scala/xiangshan/frontend/IBuffer.scala (revision 44c9c1de213b2844d737b2a34fcfabfdf4e74fa4)
1*44c9c1deSEaston Man/***************************************************************************************
2*44c9c1deSEaston Man* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*44c9c1deSEaston Man* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*44c9c1deSEaston Man*
5*44c9c1deSEaston Man* XiangShan is licensed under Mulan PSL v2.
6*44c9c1deSEaston Man* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*44c9c1deSEaston Man* You may obtain a copy of Mulan PSL v2 at:
8*44c9c1deSEaston Man*          http://license.coscl.org.cn/MulanPSL2
9*44c9c1deSEaston Man*
10*44c9c1deSEaston Man* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*44c9c1deSEaston Man* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*44c9c1deSEaston Man* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*44c9c1deSEaston Man*
14*44c9c1deSEaston Man* See the Mulan PSL v2 for more details.
15*44c9c1deSEaston Man***************************************************************************************/
16*44c9c1deSEaston Man
17*44c9c1deSEaston Manpackage xiangshan.frontend
18*44c9c1deSEaston Man
19*44c9c1deSEaston Manimport org.chipsalliance.cde.config.Parameters
20*44c9c1deSEaston Manimport chisel3._
21*44c9c1deSEaston Manimport chisel3.util._
22*44c9c1deSEaston Manimport xiangshan._
23*44c9c1deSEaston Manimport utils._
24*44c9c1deSEaston Manimport utility._
25*44c9c1deSEaston Manimport xiangshan.ExceptionNO._
26*44c9c1deSEaston Man
27*44c9c1deSEaston Manclass IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](
28*44c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufSize
29*44c9c1deSEaston Man) {
30*44c9c1deSEaston Man}
31*44c9c1deSEaston Man
32*44c9c1deSEaston Manclass IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](
33*44c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank
34*44c9c1deSEaston Man) {
35*44c9c1deSEaston Man}
36*44c9c1deSEaston Man
37*44c9c1deSEaston Manclass IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](
38*44c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufNBank
39*44c9c1deSEaston Man) {
40*44c9c1deSEaston Man}
41*44c9c1deSEaston Man
42*44c9c1deSEaston Manclass IBufferIO(implicit p: Parameters) extends XSBundle {
43*44c9c1deSEaston Man  val flush = Input(Bool())
44*44c9c1deSEaston Man  val ControlRedirect = Input(Bool())
45*44c9c1deSEaston Man  val ControlBTBMissBubble = Input(Bool())
46*44c9c1deSEaston Man  val TAGEMissBubble = Input(Bool())
47*44c9c1deSEaston Man  val SCMissBubble = Input(Bool())
48*44c9c1deSEaston Man  val ITTAGEMissBubble = Input(Bool())
49*44c9c1deSEaston Man  val RASMissBubble = Input(Bool())
50*44c9c1deSEaston Man  val MemVioRedirect = Input(Bool())
51*44c9c1deSEaston Man  val in = Flipped(DecoupledIO(new FetchToIBuffer))
52*44c9c1deSEaston Man  val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
53*44c9c1deSEaston Man  val full = Output(Bool())
54*44c9c1deSEaston Man  val stallReason = new StallReasonIO(DecodeWidth)
55*44c9c1deSEaston Man}
56*44c9c1deSEaston Man
57*44c9c1deSEaston Manclass IBufEntry(implicit p: Parameters) extends XSBundle {
58*44c9c1deSEaston Man  val inst = UInt(32.W)
59*44c9c1deSEaston Man  val pc = UInt(VAddrBits.W)
60*44c9c1deSEaston Man  val foldpc = UInt(MemPredPCWidth.W)
61*44c9c1deSEaston Man  val pd = new PreDecodeInfo
62*44c9c1deSEaston Man  val pred_taken = Bool()
63*44c9c1deSEaston Man  val ftqPtr = new FtqPtr
64*44c9c1deSEaston Man  val ftqOffset = UInt(log2Ceil(PredictWidth).W)
65*44c9c1deSEaston Man  val ipf = Bool()
66*44c9c1deSEaston Man  val acf = Bool()
67*44c9c1deSEaston Man  val crossPageIPFFix = Bool()
68*44c9c1deSEaston Man  val triggered = new TriggerCf
69*44c9c1deSEaston Man
70*44c9c1deSEaston Man  def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = {
71*44c9c1deSEaston Man    inst   := fetch.instrs(i)
72*44c9c1deSEaston Man    pc     := fetch.pc(i)
73*44c9c1deSEaston Man    foldpc := fetch.foldpc(i)
74*44c9c1deSEaston Man    pd     := fetch.pd(i)
75*44c9c1deSEaston Man    pred_taken := fetch.ftqOffset(i).valid
76*44c9c1deSEaston Man    ftqPtr := fetch.ftqPtr
77*44c9c1deSEaston Man    ftqOffset := fetch.ftqOffset(i).bits
78*44c9c1deSEaston Man    ipf := fetch.ipf(i)
79*44c9c1deSEaston Man    acf := fetch.acf(i)
80*44c9c1deSEaston Man    crossPageIPFFix := fetch.crossPageIPFFix(i)
81*44c9c1deSEaston Man    triggered := fetch.triggered(i)
82*44c9c1deSEaston Man    this
83*44c9c1deSEaston Man  }
84*44c9c1deSEaston Man
85*44c9c1deSEaston Man  def toCtrlFlow: CtrlFlow = {
86*44c9c1deSEaston Man    val cf = Wire(new CtrlFlow)
87*44c9c1deSEaston Man    cf.instr := inst
88*44c9c1deSEaston Man    cf.pc := pc
89*44c9c1deSEaston Man    cf.foldpc := foldpc
90*44c9c1deSEaston Man    cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
91*44c9c1deSEaston Man    cf.exceptionVec(instrPageFault) := ipf
92*44c9c1deSEaston Man    cf.exceptionVec(instrAccessFault) := acf
93*44c9c1deSEaston Man    cf.trigger := triggered
94*44c9c1deSEaston Man    cf.pd := pd
95*44c9c1deSEaston Man    cf.pred_taken := pred_taken
96*44c9c1deSEaston Man    cf.crossPageIPFFix := crossPageIPFFix
97*44c9c1deSEaston Man    cf.storeSetHit := DontCare
98*44c9c1deSEaston Man    cf.waitForRobIdx := DontCare
99*44c9c1deSEaston Man    cf.loadWaitBit := DontCare
100*44c9c1deSEaston Man    cf.loadWaitStrict := DontCare
101*44c9c1deSEaston Man    cf.ssid := DontCare
102*44c9c1deSEaston Man    cf.ftqPtr := ftqPtr
103*44c9c1deSEaston Man    cf.ftqOffset := ftqOffset
104*44c9c1deSEaston Man    cf
105*44c9c1deSEaston Man  }
106*44c9c1deSEaston Man}
107*44c9c1deSEaston Man
108*44c9c1deSEaston Manclass IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents {
109*44c9c1deSEaston Man  val io = IO(new IBufferIO)
110*44c9c1deSEaston Man
111*44c9c1deSEaston Man  // Parameter Check
112*44c9c1deSEaston Man  private val bankSize = IBufSize / IBufNBank
113*44c9c1deSEaston Man  require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize")
114*44c9c1deSEaston Man  require(IBufNBank >= DecodeWidth,
115*44c9c1deSEaston Man    s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth")
116*44c9c1deSEaston Man
117*44c9c1deSEaston Man  // IBuffer is organized as raw registers
118*44c9c1deSEaston Man  // This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled
119*44c9c1deSEaston Man  //                             . + + E E E - .
120*44c9c1deSEaston Man  //                             . + + E E E - .
121*44c9c1deSEaston Man  //                             . . + E E E - .
122*44c9c1deSEaston Man  //                             . . + E E E E -
123*44c9c1deSEaston Man  // As shown above, + means enqueue, - means dequeue, E is current content
124*44c9c1deSEaston Man  // When dequeue, read port is organized like a banked FIFO
125*44c9c1deSEaston Man  // Dequeue reads no more than 1 entry from each bank sequentially, this can be exploit to reduce area
126*44c9c1deSEaston Man  // Enqueue writes cannot benefit from this characteristic unless use a SRAM
127*44c9c1deSEaston Man  // For detail see Enqueue and Dequeue below
128*44c9c1deSEaston Man  private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry)))
129*44c9c1deSEaston Man  private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(
130*44c9c1deSEaston Man    bankID => VecInit.tabulate(bankSize)(
131*44c9c1deSEaston Man      inBankOffset => ibuf(bankID + inBankOffset * IBufNBank)
132*44c9c1deSEaston Man    )
133*44c9c1deSEaston Man  )
134*44c9c1deSEaston Man
135*44c9c1deSEaston Man  // Between Bank
136*44c9c1deSEaston Man  private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr)))
137*44c9c1deSEaston Man  private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0)
138*44c9c1deSEaston Man  // Inside Bank
139*44c9c1deSEaston Man  private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)))
140*44c9c1deSEaston Man
141*44c9c1deSEaston Man  val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr))
142*44c9c1deSEaston Man
143*44c9c1deSEaston Man  val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr)))
144*44c9c1deSEaston Man  val enqPtr = enqPtrVec(0)
145*44c9c1deSEaston Man
146*44c9c1deSEaston Man  val validEntries = distanceBetween(enqPtr, deqPtr)
147*44c9c1deSEaston Man  val allowEnq = RegInit(true.B)
148*44c9c1deSEaston Man
149*44c9c1deSEaston Man  val numEnq = Mux(io.in.fire, PopCount(io.in.bits.valid), 0.U)
150*44c9c1deSEaston Man  val numTryDeq = Mux(validEntries >= DecodeWidth.U, DecodeWidth.U, validEntries)
151*44c9c1deSEaston Man  val numDeq = Mux(io.out.head.ready, numTryDeq, 0.U)
152*44c9c1deSEaston Man
153*44c9c1deSEaston Man  val numAfterEnq = validEntries +& numEnq
154*44c9c1deSEaston Man  val nextValidEntries = Mux(io.out(0).ready, numAfterEnq - numTryDeq, numAfterEnq)
155*44c9c1deSEaston Man  allowEnq := (IBufSize - PredictWidth).U >= nextValidEntries // Disable when almost full
156*44c9c1deSEaston Man
157*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158*44c9c1deSEaston Man  // Enqueue
159*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160*44c9c1deSEaston Man  io.in.ready := allowEnq
161*44c9c1deSEaston Man  // Data
162*44c9c1deSEaston Man  val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i)))
163*44c9c1deSEaston Man  val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i))
164*44c9c1deSEaston Man  ibuf.zipWithIndex.foreach {
165*44c9c1deSEaston Man    case (entry, idx) => {
166*44c9c1deSEaston Man      // Select
167*44c9c1deSEaston Man      val validOH = Range(0, PredictWidth).map {
168*44c9c1deSEaston Man        i => io.in.bits.valid(i) &&
169*44c9c1deSEaston Man          io.in.bits.enqEnable(i) &&
170*44c9c1deSEaston Man          enqPtrVec(enqOffset(i)).value === idx.asUInt
171*44c9c1deSEaston Man      } // Should be OneHot
172*44c9c1deSEaston Man      val wen = validOH.reduce(_ || _) && io.in.fire && !io.flush
173*44c9c1deSEaston Man
174*44c9c1deSEaston Man      // Write port
175*44c9c1deSEaston Man      // Each IBuffer entry has a PredictWidth -> 1 Mux
176*44c9c1deSEaston Man      val writeEntry = Mux1H(validOH, enqData)
177*44c9c1deSEaston Man      entry := Mux(wen, writeEntry, entry)
178*44c9c1deSEaston Man
179*44c9c1deSEaston Man      // Debug Assertion
180*44c9c1deSEaston Man      XSError(PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
181*44c9c1deSEaston Man    }
182*44c9c1deSEaston Man  }
183*44c9c1deSEaston Man  // Pointer maintenance
184*44c9c1deSEaston Man  when (io.in.fire && !io.flush) {
185*44c9c1deSEaston Man    enqPtrVec := VecInit(enqPtrVec.map(_ + PopCount(io.in.bits.enqEnable)))
186*44c9c1deSEaston Man  }
187*44c9c1deSEaston Man
188*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
189*44c9c1deSEaston Man  // Dequeue
190*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
191*44c9c1deSEaston Man  val validVec = Mux(validEntries >= DecodeWidth.U,
192*44c9c1deSEaston Man    ((1 << DecodeWidth) - 1).U,
193*44c9c1deSEaston Man    UIntToMask(validEntries(log2Ceil(DecodeWidth) - 1, 0), DecodeWidth)
194*44c9c1deSEaston Man  )
195*44c9c1deSEaston Man  // Data
196*44c9c1deSEaston Man  // Read port
197*44c9c1deSEaston Man  // 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1
198*44c9c1deSEaston Man  // Should be better than IBufSize -> 1 in area, with no significant latency increase
199*44c9c1deSEaston Man  private val readStage1: Vec[IBufEntry] = VecInit.tabulate(IBufNBank)(
200*44c9c1deSEaston Man    bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID))
201*44c9c1deSEaston Man  )
202*44c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
203*44c9c1deSEaston Man    io.out(i).valid := validVec(i)
204*44c9c1deSEaston Man    io.out(i).bits := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1).toCtrlFlow
205*44c9c1deSEaston Man  }
206*44c9c1deSEaston Man  // Pointer maintenance
207*44c9c1deSEaston Man  deqBankPtrVec := Mux(io.out.head.ready, VecInit(deqBankPtrVec.map(_ + numTryDeq)), deqBankPtrVec)
208*44c9c1deSEaston Man  deqPtr := Mux(io.out.head.ready, deqPtr + numTryDeq, deqPtr)
209*44c9c1deSEaston Man  deqInBankPtr.zipWithIndex.foreach {
210*44c9c1deSEaston Man    case (ptr, idx) => {
211*44c9c1deSEaston Man      // validVec[k] == bankValid[deqBankPtr + k]
212*44c9c1deSEaston Man      // So bankValid[n] == validVec[n - deqBankPtr]
213*44c9c1deSEaston Man      val validIdx = Mux(idx.asUInt >= deqBankPtr.value,
214*44c9c1deSEaston Man        idx.asUInt - deqBankPtr.value,
215*44c9c1deSEaston Man        ((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0)
216*44c9c1deSEaston Man      )
217*44c9c1deSEaston Man      val bankAdvance = Mux(validIdx >= DecodeWidth.U,
218*44c9c1deSEaston Man        false.B,
219*44c9c1deSEaston Man        validVec(validIdx(log2Ceil(DecodeWidth) - 1, 0))
220*44c9c1deSEaston Man      ) && io.out.head.ready
221*44c9c1deSEaston Man      ptr := Mux(bankAdvance , ptr + 1.U, ptr)
222*44c9c1deSEaston Man    }
223*44c9c1deSEaston Man  }
224*44c9c1deSEaston Man
225*44c9c1deSEaston Man  // Flush
226*44c9c1deSEaston Man  when (io.flush) {
227*44c9c1deSEaston Man    allowEnq := true.B
228*44c9c1deSEaston Man    enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr))
229*44c9c1deSEaston Man    deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr))
230*44c9c1deSEaston Man    deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))
231*44c9c1deSEaston Man    deqPtr := 0.U.asTypeOf(new IBufPtr())
232*44c9c1deSEaston Man  }
233*44c9c1deSEaston Man  io.full := !allowEnq
234*44c9c1deSEaston Man
235*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
236*44c9c1deSEaston Man  // TopDown
237*44c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
238*44c9c1deSEaston Man  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
239*44c9c1deSEaston Man  topdown_stage := io.in.bits.topdown_info
240*44c9c1deSEaston Man  when(io.flush) {
241*44c9c1deSEaston Man    when(io.ControlRedirect) {
242*44c9c1deSEaston Man      when(io.ControlBTBMissBubble) {
243*44c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
244*44c9c1deSEaston Man      }.elsewhen(io.TAGEMissBubble) {
245*44c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
246*44c9c1deSEaston Man      }.elsewhen(io.SCMissBubble) {
247*44c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
248*44c9c1deSEaston Man      }.elsewhen(io.ITTAGEMissBubble) {
249*44c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
250*44c9c1deSEaston Man      }.elsewhen(io.RASMissBubble) {
251*44c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
252*44c9c1deSEaston Man      }
253*44c9c1deSEaston Man    }.elsewhen(io.MemVioRedirect) {
254*44c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
255*44c9c1deSEaston Man    }.otherwise {
256*44c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
257*44c9c1deSEaston Man    }
258*44c9c1deSEaston Man  }
259*44c9c1deSEaston Man
260*44c9c1deSEaston Man
261*44c9c1deSEaston Man  val dequeueInsufficient = Wire(Bool())
262*44c9c1deSEaston Man  val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W))
263*44c9c1deSEaston Man  val deqValidCount = PopCount(validVec.asBools)
264*44c9c1deSEaston Man  val deqWasteCount = DecodeWidth.U - deqValidCount
265*44c9c1deSEaston Man  dequeueInsufficient := deqValidCount < DecodeWidth.U
266*44c9c1deSEaston Man  matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse)
267*44c9c1deSEaston Man
268*44c9c1deSEaston Man  io.stallReason.reason.map(_ := 0.U)
269*44c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
270*44c9c1deSEaston Man    when(i.U < deqWasteCount) {
271*44c9c1deSEaston Man      io.stallReason.reason(DecodeWidth - i - 1) := matchBubble
272*44c9c1deSEaston Man    }
273*44c9c1deSEaston Man  }
274*44c9c1deSEaston Man
275*44c9c1deSEaston Man  when(!(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR)) {
276*44c9c1deSEaston Man    // should set reason for FetchFragmentationStall
277*44c9c1deSEaston Man    // topdown_stage.reasons(TopDownCounters.FetchFragmentationStall.id) := true.B
278*44c9c1deSEaston Man    for (i <- 0 until DecodeWidth) {
279*44c9c1deSEaston Man      when(i.U < deqWasteCount) {
280*44c9c1deSEaston Man        io.stallReason.reason(DecodeWidth - i - 1) := TopDownCounters.FetchFragBubble.id.U
281*44c9c1deSEaston Man      }
282*44c9c1deSEaston Man    }
283*44c9c1deSEaston Man  }
284*44c9c1deSEaston Man
285*44c9c1deSEaston Man  when(io.stallReason.backReason.valid) {
286*44c9c1deSEaston Man    io.stallReason.reason.map(_ := io.stallReason.backReason.bits)
287*44c9c1deSEaston Man  }
288*44c9c1deSEaston Man
289*44c9c1deSEaston Man  // Debug info
290*44c9c1deSEaston Man  XSError(
291*44c9c1deSEaston Man    deqPtr.value =/= deqBankPtr.value + deqInBankPtr(deqBankPtr.value).value * IBufNBank.asUInt,
292*44c9c1deSEaston Man    "Dequeue PTR mismatch"
293*44c9c1deSEaston Man  )
294*44c9c1deSEaston Man  XSDebug(io.flush, "IBuffer Flushed\n")
295*44c9c1deSEaston Man
296*44c9c1deSEaston Man  when(io.in.fire) {
297*44c9c1deSEaston Man    XSDebug("Enque:\n")
298*44c9c1deSEaston Man    XSDebug(p"MASK=${Binary(io.in.bits.valid)}\n")
299*44c9c1deSEaston Man    for(i <- 0 until PredictWidth){
300*44c9c1deSEaston Man      XSDebug(p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n")
301*44c9c1deSEaston Man    }
302*44c9c1deSEaston Man  }
303*44c9c1deSEaston Man
304*44c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
305*44c9c1deSEaston Man    XSDebug(io.out(i).fire,
306*44c9c1deSEaston Man      p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" +
307*44c9c1deSEaston Man      p"v=${io.out(i).valid} r=${io.out(i).ready} " +
308*44c9c1deSEaston Man      p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n")
309*44c9c1deSEaston Man  }
310*44c9c1deSEaston Man
311*44c9c1deSEaston Man  XSDebug(p"ValidEntries: ${validEntries}\n")
312*44c9c1deSEaston Man  XSDebug(p"EnqNum: ${numEnq}\n")
313*44c9c1deSEaston Man  XSDebug(p"DeqNum: ${numDeq}\n")
314*44c9c1deSEaston Man
315*44c9c1deSEaston Man  val afterInit = RegInit(false.B)
316*44c9c1deSEaston Man  val headBubble = RegInit(false.B)
317*44c9c1deSEaston Man  when (io.in.fire) { afterInit := true.B }
318*44c9c1deSEaston Man  when (io.flush) {
319*44c9c1deSEaston Man    headBubble := true.B
320*44c9c1deSEaston Man  } .elsewhen(validEntries =/= 0.U) {
321*44c9c1deSEaston Man    headBubble := false.B
322*44c9c1deSEaston Man  }
323*44c9c1deSEaston Man  val instrHungry = afterInit && (validEntries === 0.U) && !headBubble
324*44c9c1deSEaston Man
325*44c9c1deSEaston Man  QueuePerf(IBufSize, validEntries, !allowEnq)
326*44c9c1deSEaston Man  XSPerfAccumulate("flush", io.flush)
327*44c9c1deSEaston Man  XSPerfAccumulate("hungry", instrHungry)
328*44c9c1deSEaston Man
329*44c9c1deSEaston Man  val ibuffer_IDWidth_hvButNotFull = afterInit && (validEntries =/= 0.U) && (validEntries < DecodeWidth.U) && !headBubble
330*44c9c1deSEaston Man  XSPerfAccumulate("ibuffer_IDWidth_hvButNotFull", ibuffer_IDWidth_hvButNotFull)
331*44c9c1deSEaston Man  /*
332*44c9c1deSEaston Man  XSPerfAccumulate("ICacheMissBubble", Mux(matchBubbleVec(TopDownCounters.ICacheMissBubble.id), deqWasteCount, 0.U))
333*44c9c1deSEaston Man  XSPerfAccumulate("ITLBMissBubble", Mux(matchBubbleVec(TopDownCounters.ITLBMissBubble.id), deqWasteCount, 0.U))
334*44c9c1deSEaston Man  XSPerfAccumulate("ControlRedirectBubble", Mux(matchBubbleVec(TopDownCounters.ControlRedirectBubble.id), deqWasteCount, 0.U))
335*44c9c1deSEaston Man  XSPerfAccumulate("MemVioRedirectBubble", Mux(matchBubbleVec(TopDownCounters.MemVioRedirectBubble.id), deqWasteCount, 0.U))
336*44c9c1deSEaston Man  XSPerfAccumulate("OtherRedirectBubble", Mux(matchBubbleVec(TopDownCounters.OtherRedirectBubble.id), deqWasteCount, 0.U))
337*44c9c1deSEaston Man  XSPerfAccumulate("BTBMissBubble", Mux(matchBubbleVec(TopDownCounters.BTBMissBubble.id), deqWasteCount, 0.U))
338*44c9c1deSEaston Man  XSPerfAccumulate("OverrideBubble", Mux(matchBubbleVec(TopDownCounters.OverrideBubble.id), deqWasteCount, 0.U))
339*44c9c1deSEaston Man  XSPerfAccumulate("FtqUpdateBubble", Mux(matchBubbleVec(TopDownCounters.FtqUpdateBubble.id), deqWasteCount, 0.U))
340*44c9c1deSEaston Man  XSPerfAccumulate("FtqFullStall", Mux(matchBubbleVec(TopDownCounters.FtqFullStall.id), deqWasteCount, 0.U))
341*44c9c1deSEaston Man  XSPerfAccumulate("FetchFragmentBubble",
342*44c9c1deSEaston Man  Mux(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR, 0.U, deqWasteCount))
343*44c9c1deSEaston Man  XSPerfAccumulate("TAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.TAGEMissBubble.id), deqWasteCount, 0.U))
344*44c9c1deSEaston Man  XSPerfAccumulate("SCMissBubble", Mux(matchBubbleVec(TopDownCounters.SCMissBubble.id), deqWasteCount, 0.U))
345*44c9c1deSEaston Man  XSPerfAccumulate("ITTAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.ITTAGEMissBubble.id), deqWasteCount, 0.U))
346*44c9c1deSEaston Man  XSPerfAccumulate("RASMissBubble", Mux(matchBubbleVec(TopDownCounters.RASMissBubble.id), deqWasteCount, 0.U))
347*44c9c1deSEaston Man  */
348*44c9c1deSEaston Man
349*44c9c1deSEaston Man  val perfEvents = Seq(
350*44c9c1deSEaston Man    ("IBuffer_Flushed  ", io.flush                                                                     ),
351*44c9c1deSEaston Man    ("IBuffer_hungry   ", instrHungry                                                                  ),
352*44c9c1deSEaston Man    ("IBuffer_1_4_valid", (validEntries >  (0*(IBufSize/4)).U) & (validEntries < (1*(IBufSize/4)).U)   ),
353*44c9c1deSEaston Man    ("IBuffer_2_4_valid", (validEntries >= (1*(IBufSize/4)).U) & (validEntries < (2*(IBufSize/4)).U)   ),
354*44c9c1deSEaston Man    ("IBuffer_3_4_valid", (validEntries >= (2*(IBufSize/4)).U) & (validEntries < (3*(IBufSize/4)).U)   ),
355*44c9c1deSEaston Man    ("IBuffer_4_4_valid", (validEntries >= (3*(IBufSize/4)).U) & (validEntries < (4*(IBufSize/4)).U)   ),
356*44c9c1deSEaston Man    ("IBuffer_full     ",  validEntries.andR                                                           ),
357*44c9c1deSEaston Man    ("Front_Bubble     ", PopCount((0 until DecodeWidth).map(i => io.out(i).ready && !io.out(i).valid)))
358*44c9c1deSEaston Man  )
359*44c9c1deSEaston Man  generatePerfEvent()
360*44c9c1deSEaston Man}
361