xref: /XiangShan/src/main/scala/xiangshan/frontend/IBuffer.scala (revision 9afa8a47d702c934807b77171a9e9545e21e6153)
144c9c1deSEaston Man/***************************************************************************************
244c9c1deSEaston Man* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
344c9c1deSEaston Man* Copyright (c) 2020-2021 Peng Cheng Laboratory
444c9c1deSEaston Man*
544c9c1deSEaston Man* XiangShan is licensed under Mulan PSL v2.
644c9c1deSEaston Man* You can use this software according to the terms and conditions of the Mulan PSL v2.
744c9c1deSEaston Man* You may obtain a copy of Mulan PSL v2 at:
844c9c1deSEaston Man*          http://license.coscl.org.cn/MulanPSL2
944c9c1deSEaston Man*
1044c9c1deSEaston Man* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1144c9c1deSEaston Man* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1244c9c1deSEaston Man* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1344c9c1deSEaston Man*
1444c9c1deSEaston Man* See the Mulan PSL v2 for more details.
1544c9c1deSEaston Man***************************************************************************************/
1644c9c1deSEaston Man
1744c9c1deSEaston Manpackage xiangshan.frontend
1844c9c1deSEaston Man
1944c9c1deSEaston Manimport org.chipsalliance.cde.config.Parameters
2044c9c1deSEaston Manimport chisel3._
2144c9c1deSEaston Manimport chisel3.util._
2244c9c1deSEaston Manimport xiangshan._
2344c9c1deSEaston Manimport utils._
2444c9c1deSEaston Manimport utility._
2544c9c1deSEaston Manimport xiangshan.ExceptionNO._
2644c9c1deSEaston Man
2744c9c1deSEaston Manclass IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](
2844c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufSize
2944c9c1deSEaston Man) {
3044c9c1deSEaston Man}
3144c9c1deSEaston Man
3244c9c1deSEaston Manclass IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](
3344c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank
3444c9c1deSEaston Man) {
3544c9c1deSEaston Man}
3644c9c1deSEaston Man
3744c9c1deSEaston Manclass IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](
3844c9c1deSEaston Man  p => p(XSCoreParamsKey).IBufNBank
3944c9c1deSEaston Man) {
4044c9c1deSEaston Man}
4144c9c1deSEaston Man
4244c9c1deSEaston Manclass IBufferIO(implicit p: Parameters) extends XSBundle {
4344c9c1deSEaston Man  val flush = Input(Bool())
4444c9c1deSEaston Man  val ControlRedirect = Input(Bool())
4544c9c1deSEaston Man  val ControlBTBMissBubble = Input(Bool())
4644c9c1deSEaston Man  val TAGEMissBubble = Input(Bool())
4744c9c1deSEaston Man  val SCMissBubble = Input(Bool())
4844c9c1deSEaston Man  val ITTAGEMissBubble = Input(Bool())
4944c9c1deSEaston Man  val RASMissBubble = Input(Bool())
5044c9c1deSEaston Man  val MemVioRedirect = Input(Bool())
5144c9c1deSEaston Man  val in = Flipped(DecoupledIO(new FetchToIBuffer))
5244c9c1deSEaston Man  val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
5344c9c1deSEaston Man  val full = Output(Bool())
5444c9c1deSEaston Man  val stallReason = new StallReasonIO(DecodeWidth)
5544c9c1deSEaston Man}
5644c9c1deSEaston Man
5744c9c1deSEaston Manclass IBufEntry(implicit p: Parameters) extends XSBundle {
5844c9c1deSEaston Man  val inst = UInt(32.W)
5944c9c1deSEaston Man  val pc = UInt(VAddrBits.W)
6044c9c1deSEaston Man  val foldpc = UInt(MemPredPCWidth.W)
6144c9c1deSEaston Man  val pd = new PreDecodeInfo
6244c9c1deSEaston Man  val pred_taken = Bool()
6344c9c1deSEaston Man  val ftqPtr = new FtqPtr
6444c9c1deSEaston Man  val ftqOffset = UInt(log2Ceil(PredictWidth).W)
6544c9c1deSEaston Man  val ipf = Bool()
66d0de7e4aSpeixiaokun  val igpf = Bool()
6744c9c1deSEaston Man  val acf = Bool()
6844c9c1deSEaston Man  val crossPageIPFFix = Bool()
6944c9c1deSEaston Man  val triggered = new TriggerCf
70d0de7e4aSpeixiaokun  val gpaddr = UInt(GPAddrBits.W)
7144c9c1deSEaston Man
7244c9c1deSEaston Man  def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = {
7344c9c1deSEaston Man    inst   := fetch.instrs(i)
7444c9c1deSEaston Man    pc     := fetch.pc(i)
7544c9c1deSEaston Man    foldpc := fetch.foldpc(i)
76d0de7e4aSpeixiaokun    gpaddr := fetch.gpaddr(i)
7744c9c1deSEaston Man    pd     := fetch.pd(i)
7844c9c1deSEaston Man    pred_taken := fetch.ftqOffset(i).valid
7944c9c1deSEaston Man    ftqPtr := fetch.ftqPtr
8044c9c1deSEaston Man    ftqOffset := fetch.ftqOffset(i).bits
8144c9c1deSEaston Man    ipf := fetch.ipf(i)
82d0de7e4aSpeixiaokun    igpf:= fetch.igpf(i)
8344c9c1deSEaston Man    acf := fetch.acf(i)
8444c9c1deSEaston Man    crossPageIPFFix := fetch.crossPageIPFFix(i)
8544c9c1deSEaston Man    triggered := fetch.triggered(i)
8644c9c1deSEaston Man    this
8744c9c1deSEaston Man  }
8844c9c1deSEaston Man
8944c9c1deSEaston Man  def toCtrlFlow: CtrlFlow = {
9044c9c1deSEaston Man    val cf = Wire(new CtrlFlow)
9144c9c1deSEaston Man    cf.instr := inst
9244c9c1deSEaston Man    cf.pc := pc
9344c9c1deSEaston Man    cf.foldpc := foldpc
9444c9c1deSEaston Man    cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
9544c9c1deSEaston Man    cf.exceptionVec(instrPageFault) := ipf
96d0de7e4aSpeixiaokun    cf.exceptionVec(instrGuestPageFault) := igpf
9744c9c1deSEaston Man    cf.exceptionVec(instrAccessFault) := acf
9844c9c1deSEaston Man    cf.trigger := triggered
9944c9c1deSEaston Man    cf.pd := pd
10044c9c1deSEaston Man    cf.pred_taken := pred_taken
10144c9c1deSEaston Man    cf.crossPageIPFFix := crossPageIPFFix
10244c9c1deSEaston Man    cf.storeSetHit := DontCare
10344c9c1deSEaston Man    cf.waitForRobIdx := DontCare
10444c9c1deSEaston Man    cf.loadWaitBit := DontCare
10544c9c1deSEaston Man    cf.loadWaitStrict := DontCare
10644c9c1deSEaston Man    cf.ssid := DontCare
10744c9c1deSEaston Man    cf.ftqPtr := ftqPtr
10844c9c1deSEaston Man    cf.ftqOffset := ftqOffset
109d0de7e4aSpeixiaokun    cf.gpaddr := gpaddr
11044c9c1deSEaston Man    cf
11144c9c1deSEaston Man  }
11244c9c1deSEaston Man}
11344c9c1deSEaston Man
11444c9c1deSEaston Manclass IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents {
11544c9c1deSEaston Man  val io = IO(new IBufferIO)
11644c9c1deSEaston Man
11744c9c1deSEaston Man  // Parameter Check
11844c9c1deSEaston Man  private val bankSize = IBufSize / IBufNBank
11944c9c1deSEaston Man  require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize")
12044c9c1deSEaston Man  require(IBufNBank >= DecodeWidth,
12144c9c1deSEaston Man    s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth")
12244c9c1deSEaston Man
12344c9c1deSEaston Man  // IBuffer is organized as raw registers
12444c9c1deSEaston Man  // This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled
12544c9c1deSEaston Man  //                             . + + E E E - .
12644c9c1deSEaston Man  //                             . + + E E E - .
12744c9c1deSEaston Man  //                             . . + E E E - .
12844c9c1deSEaston Man  //                             . . + E E E E -
12944c9c1deSEaston Man  // As shown above, + means enqueue, - means dequeue, E is current content
13044c9c1deSEaston Man  // When dequeue, read port is organized like a banked FIFO
13144c9c1deSEaston Man  // Dequeue reads no more than 1 entry from each bank sequentially, this can be exploit to reduce area
13244c9c1deSEaston Man  // Enqueue writes cannot benefit from this characteristic unless use a SRAM
13344c9c1deSEaston Man  // For detail see Enqueue and Dequeue below
13444c9c1deSEaston Man  private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry)))
13544c9c1deSEaston Man  private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(
13644c9c1deSEaston Man    bankID => VecInit.tabulate(bankSize)(
13744c9c1deSEaston Man      inBankOffset => ibuf(bankID + inBankOffset * IBufNBank)
13844c9c1deSEaston Man    )
13944c9c1deSEaston Man  )
14044c9c1deSEaston Man
1418fae59bbSEaston Man
1428fae59bbSEaston Man  // Bypass wire
1438fae59bbSEaston Man  private val bypassEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
1448fae59bbSEaston Man  // Normal read wire
1458fae59bbSEaston Man  private val deqEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
1468fae59bbSEaston Man  // Output register
1478fae59bbSEaston Man  private val outputEntries = RegInit(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
1488fae59bbSEaston Man
14944c9c1deSEaston Man  // Between Bank
15044c9c1deSEaston Man  private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr)))
15144c9c1deSEaston Man  private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0)
15244c9c1deSEaston Man  // Inside Bank
15344c9c1deSEaston Man  private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)))
15444c9c1deSEaston Man
15544c9c1deSEaston Man  val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr))
15644c9c1deSEaston Man
15744c9c1deSEaston Man  val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr)))
15844c9c1deSEaston Man  val enqPtr = enqPtrVec(0)
15944c9c1deSEaston Man
16044c9c1deSEaston Man  val validEntries = distanceBetween(enqPtr, deqPtr)
16144c9c1deSEaston Man  val allowEnq = RegInit(true.B)
1628fae59bbSEaston Man  val useBypass = enqPtr === deqPtr && io.out.head.ready // empty and last cycle fire
16344c9c1deSEaston Man
1648fae59bbSEaston Man  val numFromFetch = PopCount(io.in.bits.enqEnable)
1658fae59bbSEaston Man  val numTryEnq = WireDefault(0.U)
1668fae59bbSEaston Man  val numEnq = Mux(io.in.fire, numTryEnq, 0.U)
1678fae59bbSEaston Man  val numBypass = PopCount(bypassEntries.map(_.valid))
16844c9c1deSEaston Man  val numTryDeq = Mux(validEntries >= DecodeWidth.U, DecodeWidth.U, validEntries)
16944c9c1deSEaston Man  val numDeq = Mux(io.out.head.ready, numTryDeq, 0.U)
17044c9c1deSEaston Man  val numAfterEnq = validEntries +& numEnq
1718fae59bbSEaston Man
17244c9c1deSEaston Man  val nextValidEntries = Mux(io.out(0).ready, numAfterEnq - numTryDeq, numAfterEnq)
17344c9c1deSEaston Man  allowEnq := (IBufSize - PredictWidth).U >= nextValidEntries // Disable when almost full
17444c9c1deSEaston Man
1758fae59bbSEaston Man  val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i)))
1768fae59bbSEaston Man  val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i))
1778fae59bbSEaston Man
1788fae59bbSEaston Man  // when using bypass, bypassed entries do not enqueue
1798fae59bbSEaston Man  when(useBypass) {
1808fae59bbSEaston Man    when(numFromFetch >= DecodeWidth.U) {
1818fae59bbSEaston Man      numTryEnq := numFromFetch - DecodeWidth.U
1828fae59bbSEaston Man    } .otherwise {
1838fae59bbSEaston Man      numTryEnq := 0.U
1848fae59bbSEaston Man    }
1858fae59bbSEaston Man  } .otherwise {
1868fae59bbSEaston Man    numTryEnq := numFromFetch
1878fae59bbSEaston Man  }
1888fae59bbSEaston Man
1898fae59bbSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1908fae59bbSEaston Man  // Bypass
1918fae59bbSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1928fae59bbSEaston Man  bypassEntries.zipWithIndex.foreach {
1938fae59bbSEaston Man    case (entry, idx) =>
1948fae59bbSEaston Man      // Select
1958fae59bbSEaston Man      val validOH = Range(0, PredictWidth).map {
1968fae59bbSEaston Man        i =>
1978fae59bbSEaston Man          io.in.bits.valid(i) &&
1988fae59bbSEaston Man            io.in.bits.enqEnable(i) &&
1998fae59bbSEaston Man            enqOffset(i) === idx.asUInt
2008fae59bbSEaston Man      } // Should be OneHot
2018fae59bbSEaston Man      entry.valid := validOH.reduce(_ || _) && io.in.fire && !io.flush
2028fae59bbSEaston Man      entry.bits := Mux1H(validOH, enqData)
2038fae59bbSEaston Man
2048fae59bbSEaston Man      // Debug Assertion
205*9afa8a47STang Haojin      XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
2068fae59bbSEaston Man  }
2078fae59bbSEaston Man
2088fae59bbSEaston Man  // => Decode Output
2098fae59bbSEaston Man  // clean register output
2108fae59bbSEaston Man  io.out zip outputEntries foreach {
2118fae59bbSEaston Man    case (io, reg) =>
2128fae59bbSEaston Man      io.valid := reg.valid
2138fae59bbSEaston Man      io.bits := reg.bits.toCtrlFlow
2148fae59bbSEaston Man  }
2158fae59bbSEaston Man  outputEntries zip bypassEntries zip deqEntries foreach {
2168fae59bbSEaston Man    case ((out, bypass), deq) =>
2178fae59bbSEaston Man      when(io.out.head.ready) {
2188fae59bbSEaston Man        out := deq
2198fae59bbSEaston Man        when(useBypass) {
2208fae59bbSEaston Man          out := bypass
2218fae59bbSEaston Man        }
2228fae59bbSEaston Man      }
2238fae59bbSEaston Man  }
2248fae59bbSEaston Man
22544c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
22644c9c1deSEaston Man  // Enqueue
22744c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
22844c9c1deSEaston Man  io.in.ready := allowEnq
22944c9c1deSEaston Man  // Data
23044c9c1deSEaston Man  ibuf.zipWithIndex.foreach {
23144c9c1deSEaston Man    case (entry, idx) => {
23244c9c1deSEaston Man      // Select
23344c9c1deSEaston Man      val validOH = Range(0, PredictWidth).map {
2348fae59bbSEaston Man        i =>
2358fae59bbSEaston Man          val useBypassMatch = enqOffset(i) >= DecodeWidth.U &&
2368fae59bbSEaston Man            enqPtrVec(enqOffset(i) - DecodeWidth.U).value === idx.asUInt
2378fae59bbSEaston Man          val normalMatch = enqPtrVec(enqOffset(i)).value === idx.asUInt
2388fae59bbSEaston Man          val m = Mux(useBypass, useBypassMatch, normalMatch) // when using bypass, bypassed entries do not enqueue
2398fae59bbSEaston Man
2408fae59bbSEaston Man          io.in.bits.valid(i) && io.in.bits.enqEnable(i) && m
24144c9c1deSEaston Man      } // Should be OneHot
24244c9c1deSEaston Man      val wen = validOH.reduce(_ || _) && io.in.fire && !io.flush
24344c9c1deSEaston Man
24444c9c1deSEaston Man      // Write port
24544c9c1deSEaston Man      // Each IBuffer entry has a PredictWidth -> 1 Mux
24644c9c1deSEaston Man      val writeEntry = Mux1H(validOH, enqData)
24744c9c1deSEaston Man      entry := Mux(wen, writeEntry, entry)
24844c9c1deSEaston Man
24944c9c1deSEaston Man      // Debug Assertion
25044c9c1deSEaston Man      XSError(PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
25144c9c1deSEaston Man    }
25244c9c1deSEaston Man  }
25344c9c1deSEaston Man  // Pointer maintenance
25444c9c1deSEaston Man  when (io.in.fire && !io.flush) {
2558fae59bbSEaston Man    enqPtrVec := VecInit(enqPtrVec.map(_ + numTryEnq))
25644c9c1deSEaston Man  }
25744c9c1deSEaston Man
25844c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
25944c9c1deSEaston Man  // Dequeue
26044c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26144c9c1deSEaston Man  val validVec = Mux(validEntries >= DecodeWidth.U,
26244c9c1deSEaston Man    ((1 << DecodeWidth) - 1).U,
26344c9c1deSEaston Man    UIntToMask(validEntries(log2Ceil(DecodeWidth) - 1, 0), DecodeWidth)
26444c9c1deSEaston Man  )
26544c9c1deSEaston Man  // Data
26644c9c1deSEaston Man  // Read port
26744c9c1deSEaston Man  // 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1
26844c9c1deSEaston Man  // Should be better than IBufSize -> 1 in area, with no significant latency increase
26944c9c1deSEaston Man  private val readStage1: Vec[IBufEntry] = VecInit.tabulate(IBufNBank)(
27044c9c1deSEaston Man    bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID))
27144c9c1deSEaston Man  )
27244c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
2738fae59bbSEaston Man    deqEntries(i).valid := validVec(i)
2748fae59bbSEaston Man    deqEntries(i).bits := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1)
27544c9c1deSEaston Man  }
27644c9c1deSEaston Man  // Pointer maintenance
27744c9c1deSEaston Man  deqBankPtrVec := Mux(io.out.head.ready, VecInit(deqBankPtrVec.map(_ + numTryDeq)), deqBankPtrVec)
27844c9c1deSEaston Man  deqPtr := Mux(io.out.head.ready, deqPtr + numTryDeq, deqPtr)
27944c9c1deSEaston Man  deqInBankPtr.zipWithIndex.foreach {
28044c9c1deSEaston Man    case (ptr, idx) => {
28144c9c1deSEaston Man      // validVec[k] == bankValid[deqBankPtr + k]
28244c9c1deSEaston Man      // So bankValid[n] == validVec[n - deqBankPtr]
28344c9c1deSEaston Man      val validIdx = Mux(idx.asUInt >= deqBankPtr.value,
28444c9c1deSEaston Man        idx.asUInt - deqBankPtr.value,
28544c9c1deSEaston Man        ((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0)
28644c9c1deSEaston Man      )
28744c9c1deSEaston Man      val bankAdvance = Mux(validIdx >= DecodeWidth.U,
28844c9c1deSEaston Man        false.B,
28944c9c1deSEaston Man        validVec(validIdx(log2Ceil(DecodeWidth) - 1, 0))
29044c9c1deSEaston Man      ) && io.out.head.ready
29144c9c1deSEaston Man      ptr := Mux(bankAdvance , ptr + 1.U, ptr)
29244c9c1deSEaston Man    }
29344c9c1deSEaston Man  }
29444c9c1deSEaston Man
29544c9c1deSEaston Man  // Flush
29644c9c1deSEaston Man  when (io.flush) {
29744c9c1deSEaston Man    allowEnq := true.B
29844c9c1deSEaston Man    enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr))
29944c9c1deSEaston Man    deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr))
30044c9c1deSEaston Man    deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))
30144c9c1deSEaston Man    deqPtr := 0.U.asTypeOf(new IBufPtr())
3028fae59bbSEaston Man    outputEntries.foreach(_.valid := false.B)
30344c9c1deSEaston Man  }
30444c9c1deSEaston Man  io.full := !allowEnq
30544c9c1deSEaston Man
30644c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30744c9c1deSEaston Man  // TopDown
30844c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30944c9c1deSEaston Man  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
31044c9c1deSEaston Man  topdown_stage := io.in.bits.topdown_info
31144c9c1deSEaston Man  when(io.flush) {
31244c9c1deSEaston Man    when(io.ControlRedirect) {
31344c9c1deSEaston Man      when(io.ControlBTBMissBubble) {
31444c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
31544c9c1deSEaston Man      }.elsewhen(io.TAGEMissBubble) {
31644c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
31744c9c1deSEaston Man      }.elsewhen(io.SCMissBubble) {
31844c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
31944c9c1deSEaston Man      }.elsewhen(io.ITTAGEMissBubble) {
32044c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
32144c9c1deSEaston Man      }.elsewhen(io.RASMissBubble) {
32244c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
32344c9c1deSEaston Man      }
32444c9c1deSEaston Man    }.elsewhen(io.MemVioRedirect) {
32544c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
32644c9c1deSEaston Man    }.otherwise {
32744c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
32844c9c1deSEaston Man    }
32944c9c1deSEaston Man  }
33044c9c1deSEaston Man
33144c9c1deSEaston Man
33244c9c1deSEaston Man  val dequeueInsufficient = Wire(Bool())
33344c9c1deSEaston Man  val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W))
33444c9c1deSEaston Man  val deqValidCount = PopCount(validVec.asBools)
33544c9c1deSEaston Man  val deqWasteCount = DecodeWidth.U - deqValidCount
33644c9c1deSEaston Man  dequeueInsufficient := deqValidCount < DecodeWidth.U
33744c9c1deSEaston Man  matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse)
33844c9c1deSEaston Man
33944c9c1deSEaston Man  io.stallReason.reason.map(_ := 0.U)
34044c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
34144c9c1deSEaston Man    when(i.U < deqWasteCount) {
34244c9c1deSEaston Man      io.stallReason.reason(DecodeWidth - i - 1) := matchBubble
34344c9c1deSEaston Man    }
34444c9c1deSEaston Man  }
34544c9c1deSEaston Man
34644c9c1deSEaston Man  when(!(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR)) {
34744c9c1deSEaston Man    // should set reason for FetchFragmentationStall
34844c9c1deSEaston Man    // topdown_stage.reasons(TopDownCounters.FetchFragmentationStall.id) := true.B
34944c9c1deSEaston Man    for (i <- 0 until DecodeWidth) {
35044c9c1deSEaston Man      when(i.U < deqWasteCount) {
35144c9c1deSEaston Man        io.stallReason.reason(DecodeWidth - i - 1) := TopDownCounters.FetchFragBubble.id.U
35244c9c1deSEaston Man      }
35344c9c1deSEaston Man    }
35444c9c1deSEaston Man  }
35544c9c1deSEaston Man
35644c9c1deSEaston Man  when(io.stallReason.backReason.valid) {
35744c9c1deSEaston Man    io.stallReason.reason.map(_ := io.stallReason.backReason.bits)
35844c9c1deSEaston Man  }
35944c9c1deSEaston Man
36044c9c1deSEaston Man  // Debug info
36144c9c1deSEaston Man  XSError(
36244c9c1deSEaston Man    deqPtr.value =/= deqBankPtr.value + deqInBankPtr(deqBankPtr.value).value * IBufNBank.asUInt,
36344c9c1deSEaston Man    "Dequeue PTR mismatch"
36444c9c1deSEaston Man  )
36544c9c1deSEaston Man  XSDebug(io.flush, "IBuffer Flushed\n")
36644c9c1deSEaston Man
36744c9c1deSEaston Man  when(io.in.fire) {
36844c9c1deSEaston Man    XSDebug("Enque:\n")
36944c9c1deSEaston Man    XSDebug(p"MASK=${Binary(io.in.bits.valid)}\n")
37044c9c1deSEaston Man    for(i <- 0 until PredictWidth){
37144c9c1deSEaston Man      XSDebug(p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n")
37244c9c1deSEaston Man    }
37344c9c1deSEaston Man  }
37444c9c1deSEaston Man
37544c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
37644c9c1deSEaston Man    XSDebug(io.out(i).fire,
37744c9c1deSEaston Man      p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" +
37844c9c1deSEaston Man      p"v=${io.out(i).valid} r=${io.out(i).ready} " +
37944c9c1deSEaston Man      p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n")
38044c9c1deSEaston Man  }
38144c9c1deSEaston Man
38244c9c1deSEaston Man  XSDebug(p"ValidEntries: ${validEntries}\n")
38344c9c1deSEaston Man  XSDebug(p"EnqNum: ${numEnq}\n")
38444c9c1deSEaston Man  XSDebug(p"DeqNum: ${numDeq}\n")
38544c9c1deSEaston Man
38644c9c1deSEaston Man  val afterInit = RegInit(false.B)
38744c9c1deSEaston Man  val headBubble = RegInit(false.B)
38844c9c1deSEaston Man  when (io.in.fire) { afterInit := true.B }
38944c9c1deSEaston Man  when (io.flush) {
39044c9c1deSEaston Man    headBubble := true.B
39144c9c1deSEaston Man  } .elsewhen(validEntries =/= 0.U) {
39244c9c1deSEaston Man    headBubble := false.B
39344c9c1deSEaston Man  }
39444c9c1deSEaston Man  val instrHungry = afterInit && (validEntries === 0.U) && !headBubble
39544c9c1deSEaston Man
39644c9c1deSEaston Man  QueuePerf(IBufSize, validEntries, !allowEnq)
39744c9c1deSEaston Man  XSPerfAccumulate("flush", io.flush)
39844c9c1deSEaston Man  XSPerfAccumulate("hungry", instrHungry)
39944c9c1deSEaston Man
40044c9c1deSEaston Man  val ibuffer_IDWidth_hvButNotFull = afterInit && (validEntries =/= 0.U) && (validEntries < DecodeWidth.U) && !headBubble
40144c9c1deSEaston Man  XSPerfAccumulate("ibuffer_IDWidth_hvButNotFull", ibuffer_IDWidth_hvButNotFull)
40244c9c1deSEaston Man  /*
40344c9c1deSEaston Man  XSPerfAccumulate("ICacheMissBubble", Mux(matchBubbleVec(TopDownCounters.ICacheMissBubble.id), deqWasteCount, 0.U))
40444c9c1deSEaston Man  XSPerfAccumulate("ITLBMissBubble", Mux(matchBubbleVec(TopDownCounters.ITLBMissBubble.id), deqWasteCount, 0.U))
40544c9c1deSEaston Man  XSPerfAccumulate("ControlRedirectBubble", Mux(matchBubbleVec(TopDownCounters.ControlRedirectBubble.id), deqWasteCount, 0.U))
40644c9c1deSEaston Man  XSPerfAccumulate("MemVioRedirectBubble", Mux(matchBubbleVec(TopDownCounters.MemVioRedirectBubble.id), deqWasteCount, 0.U))
40744c9c1deSEaston Man  XSPerfAccumulate("OtherRedirectBubble", Mux(matchBubbleVec(TopDownCounters.OtherRedirectBubble.id), deqWasteCount, 0.U))
40844c9c1deSEaston Man  XSPerfAccumulate("BTBMissBubble", Mux(matchBubbleVec(TopDownCounters.BTBMissBubble.id), deqWasteCount, 0.U))
40944c9c1deSEaston Man  XSPerfAccumulate("OverrideBubble", Mux(matchBubbleVec(TopDownCounters.OverrideBubble.id), deqWasteCount, 0.U))
41044c9c1deSEaston Man  XSPerfAccumulate("FtqUpdateBubble", Mux(matchBubbleVec(TopDownCounters.FtqUpdateBubble.id), deqWasteCount, 0.U))
41144c9c1deSEaston Man  XSPerfAccumulate("FtqFullStall", Mux(matchBubbleVec(TopDownCounters.FtqFullStall.id), deqWasteCount, 0.U))
41244c9c1deSEaston Man  XSPerfAccumulate("FetchFragmentBubble",
41344c9c1deSEaston Man  Mux(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR, 0.U, deqWasteCount))
41444c9c1deSEaston Man  XSPerfAccumulate("TAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.TAGEMissBubble.id), deqWasteCount, 0.U))
41544c9c1deSEaston Man  XSPerfAccumulate("SCMissBubble", Mux(matchBubbleVec(TopDownCounters.SCMissBubble.id), deqWasteCount, 0.U))
41644c9c1deSEaston Man  XSPerfAccumulate("ITTAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.ITTAGEMissBubble.id), deqWasteCount, 0.U))
41744c9c1deSEaston Man  XSPerfAccumulate("RASMissBubble", Mux(matchBubbleVec(TopDownCounters.RASMissBubble.id), deqWasteCount, 0.U))
41844c9c1deSEaston Man  */
41944c9c1deSEaston Man
42044c9c1deSEaston Man  val perfEvents = Seq(
42144c9c1deSEaston Man    ("IBuffer_Flushed  ", io.flush                                                                     ),
42244c9c1deSEaston Man    ("IBuffer_hungry   ", instrHungry                                                                  ),
42344c9c1deSEaston Man    ("IBuffer_1_4_valid", (validEntries >  (0*(IBufSize/4)).U) & (validEntries < (1*(IBufSize/4)).U)   ),
42444c9c1deSEaston Man    ("IBuffer_2_4_valid", (validEntries >= (1*(IBufSize/4)).U) & (validEntries < (2*(IBufSize/4)).U)   ),
42544c9c1deSEaston Man    ("IBuffer_3_4_valid", (validEntries >= (2*(IBufSize/4)).U) & (validEntries < (3*(IBufSize/4)).U)   ),
42644c9c1deSEaston Man    ("IBuffer_4_4_valid", (validEntries >= (3*(IBufSize/4)).U) & (validEntries < (4*(IBufSize/4)).U)   ),
42744c9c1deSEaston Man    ("IBuffer_full     ",  validEntries.andR                                                           ),
42844c9c1deSEaston Man    ("Front_Bubble     ", PopCount((0 until DecodeWidth).map(i => io.out(i).ready && !io.out(i).valid)))
42944c9c1deSEaston Man  )
43044c9c1deSEaston Man  generatePerfEvent()
43144c9c1deSEaston Man}
432