xref: /XiangShan/src/main/scala/xiangshan/frontend/IBuffer.scala (revision 1592abd11eecf7bec0f1453ffe4a7617167f8ba9)
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 chisel3._
2044c9c1deSEaston Manimport chisel3.util._
21cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
2244c9c1deSEaston Manimport utility._
23cf7d6b7aSMuziimport utils._
24cf7d6b7aSMuziimport xiangshan._
2544c9c1deSEaston Manimport xiangshan.ExceptionNO._
2644c9c1deSEaston Man
27cf7d6b7aSMuziclass IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](p => p(XSCoreParamsKey).IBufSize) {}
2844c9c1deSEaston Man
29cf7d6b7aSMuziclass IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](p =>
30cf7d6b7aSMuzi      p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank
31cf7d6b7aSMuzi    ) {}
3244c9c1deSEaston Man
33cf7d6b7aSMuziclass IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](p => p(XSCoreParamsKey).IBufNBank) {}
3444c9c1deSEaston Man
3544c9c1deSEaston Manclass IBufferIO(implicit p: Parameters) extends XSBundle {
3644c9c1deSEaston Man  val flush                = Input(Bool())
3744c9c1deSEaston Man  val ControlRedirect      = Input(Bool())
3844c9c1deSEaston Man  val ControlBTBMissBubble = Input(Bool())
3944c9c1deSEaston Man  val TAGEMissBubble       = Input(Bool())
4044c9c1deSEaston Man  val SCMissBubble         = Input(Bool())
4144c9c1deSEaston Man  val ITTAGEMissBubble     = Input(Bool())
4244c9c1deSEaston Man  val RASMissBubble        = Input(Bool())
4344c9c1deSEaston Man  val MemVioRedirect       = Input(Bool())
4444c9c1deSEaston Man  val in                   = Flipped(DecoupledIO(new FetchToIBuffer))
4544c9c1deSEaston Man  val out                  = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
4644c9c1deSEaston Man  val full                 = Output(Bool())
4705cc2a4eSXuan Hu  val decodeCanAccept      = Input(Bool())
4844c9c1deSEaston Man  val stallReason          = new StallReasonIO(DecodeWidth)
4944c9c1deSEaston Man}
5044c9c1deSEaston Man
5144c9c1deSEaston Manclass IBufEntry(implicit p: Parameters) extends XSBundle {
5244c9c1deSEaston Man  val inst             = UInt(32.W)
5344c9c1deSEaston Man  val pc               = UInt(VAddrBits.W)
5444c9c1deSEaston Man  val foldpc           = UInt(MemPredPCWidth.W)
5544c9c1deSEaston Man  val pd               = new PreDecodeInfo
5644c9c1deSEaston Man  val pred_taken       = Bool()
5744c9c1deSEaston Man  val ftqPtr           = new FtqPtr
5844c9c1deSEaston Man  val ftqOffset        = UInt(log2Ceil(PredictWidth).W)
5992c61038SXuan Hu  val exceptionType    = IBufferExceptionType()
60fbdb359dSMuzi  val backendException = Bool()
617e0f64b0SGuanghui Cheng  val triggered        = TriggerAction()
62948e8159SEaston Man  val isLastInFtqEntry = Bool()
63*1592abd1SYan Xu  val debug_seqNum     = InstSeqNum()
6444c9c1deSEaston Man
6544c9c1deSEaston Man  def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = {
6644c9c1deSEaston Man    inst       := fetch.instrs(i)
6744c9c1deSEaston Man    pc         := fetch.pc(i)
6844c9c1deSEaston Man    foldpc     := fetch.foldpc(i)
6944c9c1deSEaston Man    pd         := fetch.pd(i)
7044c9c1deSEaston Man    pred_taken := fetch.ftqOffset(i).valid
7144c9c1deSEaston Man    ftqPtr     := fetch.ftqPtr
7244c9c1deSEaston Man    ftqOffset  := fetch.ftqOffset(i).bits
7392c61038SXuan Hu    exceptionType := IBufferExceptionType.cvtFromFetchExcpAndCrossPageAndRVCII(
7492c61038SXuan Hu      fetch.exceptionType(i),
7592c61038SXuan Hu      fetch.crossPageIPFFix(i),
76cf7d6b7aSMuzi      fetch.illegalInstr(i)
7792c61038SXuan Hu    )
78fbdb359dSMuzi    backendException := fetch.backendException(i)
7944c9c1deSEaston Man    triggered        := fetch.triggered(i)
80948e8159SEaston Man    isLastInFtqEntry := fetch.isLastInFtqEntry(i)
81*1592abd1SYan Xu    debug_seqNum     := fetch.debug_seqNum(i)
8244c9c1deSEaston Man    this
8344c9c1deSEaston Man  }
8444c9c1deSEaston Man
8544c9c1deSEaston Man  def toCtrlFlow: CtrlFlow = {
8644c9c1deSEaston Man    val cf = Wire(new CtrlFlow)
8744c9c1deSEaston Man    cf.instr                             := inst
8844c9c1deSEaston Man    cf.pc                                := pc
8944c9c1deSEaston Man    cf.foldpc                            := foldpc
9044c9c1deSEaston Man    cf.exceptionVec                      := 0.U.asTypeOf(ExceptionVec())
9192c61038SXuan Hu    cf.exceptionVec(instrPageFault)      := IBufferExceptionType.isPF(this.exceptionType)
9292c61038SXuan Hu    cf.exceptionVec(instrGuestPageFault) := IBufferExceptionType.isGPF(this.exceptionType)
9392c61038SXuan Hu    cf.exceptionVec(instrAccessFault)    := IBufferExceptionType.isAF(this.exceptionType)
9492c61038SXuan Hu    cf.exceptionVec(EX_II)               := IBufferExceptionType.isRVCII(this.exceptionType)
95fbdb359dSMuzi    cf.backendException                  := backendException
9644c9c1deSEaston Man    cf.trigger                           := triggered
9744c9c1deSEaston Man    cf.pd                                := pd
9844c9c1deSEaston Man    cf.pred_taken                        := pred_taken
9992c61038SXuan Hu    cf.crossPageIPFFix                   := IBufferExceptionType.isCrossPage(this.exceptionType)
10044c9c1deSEaston Man    cf.storeSetHit                       := DontCare
10144c9c1deSEaston Man    cf.waitForRobIdx                     := DontCare
10244c9c1deSEaston Man    cf.loadWaitBit                       := DontCare
10344c9c1deSEaston Man    cf.loadWaitStrict                    := DontCare
10444c9c1deSEaston Man    cf.ssid                              := DontCare
10544c9c1deSEaston Man    cf.ftqPtr                            := ftqPtr
10644c9c1deSEaston Man    cf.ftqOffset                         := ftqOffset
107948e8159SEaston Man    cf.isLastInFtqEntry                  := isLastInFtqEntry
108*1592abd1SYan Xu    cf.debug_seqNum                      := debug_seqNum
10944c9c1deSEaston Man    cf
11044c9c1deSEaston Man  }
11192c61038SXuan Hu
11292c61038SXuan Hu  object IBufferExceptionType extends NamedUInt(3) {
11392c61038SXuan Hu    def None        = "b000".U
11492c61038SXuan Hu    def NonCrossPF  = "b001".U
11592c61038SXuan Hu    def NonCrossGPF = "b010".U
11692c61038SXuan Hu    def NonCrossAF  = "b011".U
11792c61038SXuan Hu    // illegal instruction
11892c61038SXuan Hu    def rvcII    = "b100".U
11992c61038SXuan Hu    def CrossPF  = "b101".U
12092c61038SXuan Hu    def CrossGPF = "b110".U
12192c61038SXuan Hu    def CrossAF  = "b111".U
12292c61038SXuan Hu
12392c61038SXuan Hu    def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: UInt, crossPage: Bool, rvcIll: Bool): UInt = {
12492c61038SXuan Hu      require(
12592c61038SXuan Hu        fetchExcp.getWidth == ExceptionType.width,
12692c61038SXuan Hu        s"The width(${fetchExcp.getWidth}) of fetchExcp should be equal to " +
12792c61038SXuan Hu          s"the width(${ExceptionType.width}) of frontend.ExceptionType."
12892c61038SXuan Hu      )
129cf7d6b7aSMuzi      MuxCase(
130cf7d6b7aSMuzi        0.U,
131cf7d6b7aSMuzi        Seq(
13292c61038SXuan Hu          crossPage     -> Cat(1.U(1.W), fetchExcp),
133f5b900a2SXuan Hu          fetchExcp.orR -> fetchExcp,
134cf7d6b7aSMuzi          rvcIll        -> this.rvcII
135cf7d6b7aSMuzi        )
136cf7d6b7aSMuzi      )
13792c61038SXuan Hu    }
13892c61038SXuan Hu
13992c61038SXuan Hu    def isRVCII(uint: UInt): Bool = {
14092c61038SXuan Hu      this.checkInputWidth(uint)
14192c61038SXuan Hu      uint(2) && uint(1, 0) === 0.U
14292c61038SXuan Hu    }
14392c61038SXuan Hu
14492c61038SXuan Hu    def isCrossPage(uint: UInt): Bool = {
14592c61038SXuan Hu      this.checkInputWidth(uint)
14692c61038SXuan Hu      uint(2) && uint(1, 0) =/= 0.U
14792c61038SXuan Hu    }
14892c61038SXuan Hu
14992c61038SXuan Hu    def isPF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0)
15092c61038SXuan Hu    def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0)
15192c61038SXuan Hu    def isAF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0)
15292c61038SXuan Hu  }
15344c9c1deSEaston Man}
15444c9c1deSEaston Man
15544c9c1deSEaston Manclass IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents {
15644c9c1deSEaston Man  val io = IO(new IBufferIO)
15744c9c1deSEaston Man
15805cc2a4eSXuan Hu  // io alias
15905cc2a4eSXuan Hu  private val decodeCanAccept = io.decodeCanAccept
16005cc2a4eSXuan Hu
16144c9c1deSEaston Man  // Parameter Check
16244c9c1deSEaston Man  private val bankSize = IBufSize / IBufNBank
16344c9c1deSEaston Man  require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize")
164cf7d6b7aSMuzi  require(
165cf7d6b7aSMuzi    IBufNBank >= DecodeWidth,
166cf7d6b7aSMuzi    s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth"
167cf7d6b7aSMuzi  )
16844c9c1deSEaston Man
16944c9c1deSEaston Man  // IBuffer is organized as raw registers
17044c9c1deSEaston Man  // This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled
17144c9c1deSEaston Man  //                             . + + E E E - .
17244c9c1deSEaston Man  //                             . + + E E E - .
17344c9c1deSEaston Man  //                             . . + E E E - .
17444c9c1deSEaston Man  //                             . . + E E E E -
17544c9c1deSEaston Man  // As shown above, + means enqueue, - means dequeue, E is current content
17644c9c1deSEaston Man  // When dequeue, read port is organized like a banked FIFO
17744c9c1deSEaston Man  // Dequeue reads no more than 1 entry from each bank sequentially, this can be exploit to reduce area
17844c9c1deSEaston Man  // Enqueue writes cannot benefit from this characteristic unless use a SRAM
17944c9c1deSEaston Man  // For detail see Enqueue and Dequeue below
18044c9c1deSEaston Man  private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry)))
181cf7d6b7aSMuzi  private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(bankID =>
182cf7d6b7aSMuzi    VecInit.tabulate(bankSize)(inBankOffset => ibuf(bankID + inBankOffset * IBufNBank))
18344c9c1deSEaston Man  )
1848fae59bbSEaston Man
1858fae59bbSEaston Man  // Bypass wire
1868fae59bbSEaston Man  private val bypassEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
1878fae59bbSEaston Man  // Normal read wire
1888fae59bbSEaston Man  private val deqEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
1898fae59bbSEaston Man  // Output register
1908fae59bbSEaston Man  private val outputEntries = RegInit(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
191cf7d6b7aSMuzi  private val outputEntriesValidNum =
192cf7d6b7aSMuzi    PriorityMuxDefault(outputEntries.map(_.valid).zip(Seq.range(1, DecodeWidth).map(_.U)).reverse.toSeq, 0.U)
1938fae59bbSEaston Man
19444c9c1deSEaston Man  // Between Bank
19544c9c1deSEaston Man  private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr)))
19644c9c1deSEaston Man  private val deqBankPtr:    IBufBankPtr      = deqBankPtrVec(0)
19705cc2a4eSXuan Hu  private val deqBankPtrVecNext = Wire(deqBankPtrVec.cloneType)
19844c9c1deSEaston Man  // Inside Bank
19944c9c1deSEaston Man  private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)))
20005cc2a4eSXuan Hu  private val deqInBankPtrNext = Wire(deqInBankPtr.cloneType)
20144c9c1deSEaston Man
20244c9c1deSEaston Man  val deqPtr     = RegInit(0.U.asTypeOf(new IBufPtr))
20305cc2a4eSXuan Hu  val deqPtrNext = Wire(deqPtr.cloneType)
20444c9c1deSEaston Man
20544c9c1deSEaston Man  val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr)))
20644c9c1deSEaston Man  val enqPtr    = enqPtrVec(0)
20744c9c1deSEaston Man
2088fae59bbSEaston Man  val numTryEnq = WireDefault(0.U)
2098fae59bbSEaston Man  val numEnq    = Mux(io.in.fire, numTryEnq, 0.U)
2108fae59bbSEaston Man
2118506cfc0Sxiaofeibao  // empty and decode can accept insts
2128506cfc0Sxiaofeibao  val useBypass = enqPtr === deqPtr && decodeCanAccept
21305cc2a4eSXuan Hu
21405cc2a4eSXuan Hu  // The number of decode accepted insts.
21505cc2a4eSXuan Hu  // Since decode promises accepting insts in order, use priority encoder to simplify the accumulation.
216a5546049Sxiaofeibao  private val numOut = Wire(UInt(log2Ceil(DecodeWidth).W))
217a5546049Sxiaofeibao  private val numDeq = numOut
21805cc2a4eSXuan Hu
21905cc2a4eSXuan Hu  // counter current number of valid
22005cc2a4eSXuan Hu  val numValid         = distanceBetween(enqPtr, deqPtr)
22105cc2a4eSXuan Hu  val numValidAfterDeq = numValid - numDeq
22205cc2a4eSXuan Hu  // counter next number of valid
22305cc2a4eSXuan Hu  val numValidNext = numValid + numEnq - numDeq
22405cc2a4eSXuan Hu  val allowEnq     = RegInit(true.B)
22505cc2a4eSXuan Hu  val numFromFetch = Mux(io.in.valid, PopCount(io.in.bits.enqEnable), 0.U)
22605cc2a4eSXuan Hu
22705cc2a4eSXuan Hu  allowEnq := (IBufSize - PredictWidth).U >= numValidNext // Disable when almost full
22844c9c1deSEaston Man
2298fae59bbSEaston Man  val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i)))
2308fae59bbSEaston Man  val enqData   = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i))
2318fae59bbSEaston Man
232a5546049Sxiaofeibao  val outputEntriesIsNotFull = !outputEntries(DecodeWidth - 1).valid
233a5546049Sxiaofeibao  when(decodeCanAccept) {
234a5546049Sxiaofeibao    numOut := Mux(numValid >= DecodeWidth.U, DecodeWidth.U, numValid)
235a5546049Sxiaofeibao  }.elsewhen(outputEntriesIsNotFull) {
236a5546049Sxiaofeibao    numOut := Mux(numValid >= DecodeWidth.U - outputEntriesValidNum, DecodeWidth.U - outputEntriesValidNum, numValid)
237a5546049Sxiaofeibao  }.otherwise {
238a5546049Sxiaofeibao    numOut := 0.U
239a5546049Sxiaofeibao  }
240a5546049Sxiaofeibao  val numBypass = Wire(UInt(log2Ceil(DecodeWidth).W))
2418fae59bbSEaston Man  // when using bypass, bypassed entries do not enqueue
2428fae59bbSEaston Man  when(useBypass) {
2438fae59bbSEaston Man    when(numFromFetch >= DecodeWidth.U) {
2448fae59bbSEaston Man      numTryEnq := numFromFetch - DecodeWidth.U
245a5546049Sxiaofeibao      numBypass := DecodeWidth.U
2468fae59bbSEaston Man    }.otherwise {
2478fae59bbSEaston Man      numTryEnq := 0.U
248a5546049Sxiaofeibao      numBypass := numFromFetch
2498fae59bbSEaston Man    }
2508fae59bbSEaston Man  }.otherwise {
2518fae59bbSEaston Man    numTryEnq := numFromFetch
252a5546049Sxiaofeibao    numBypass := 0.U
2538fae59bbSEaston Man  }
2548fae59bbSEaston Man
2558fae59bbSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2568fae59bbSEaston Man  // Bypass
2578fae59bbSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2588fae59bbSEaston Man  bypassEntries.zipWithIndex.foreach {
2598fae59bbSEaston Man    case (entry, idx) =>
2608fae59bbSEaston Man      // Select
2618fae59bbSEaston Man      val validOH = Range(0, PredictWidth).map {
2628fae59bbSEaston Man        i =>
2638fae59bbSEaston Man          io.in.bits.valid(i) &&
2648fae59bbSEaston Man          io.in.bits.enqEnable(i) &&
2658fae59bbSEaston Man          enqOffset(i) === idx.asUInt
2668fae59bbSEaston Man      } // Should be OneHot
2678fae59bbSEaston Man      entry.valid := validOH.reduce(_ || _) && io.in.fire && !io.flush
2688fae59bbSEaston Man      entry.bits  := Mux1H(validOH, enqData)
2698fae59bbSEaston Man
2708fae59bbSEaston Man      // Debug Assertion
2719afa8a47STang Haojin      XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
2728fae59bbSEaston Man  }
2738fae59bbSEaston Man
2748fae59bbSEaston Man  // => Decode Output
2758fae59bbSEaston Man  // clean register output
2768fae59bbSEaston Man  io.out zip outputEntries foreach {
2778fae59bbSEaston Man    case (io, reg) =>
2788fae59bbSEaston Man      io.valid := reg.valid
2798fae59bbSEaston Man      io.bits  := reg.bits.toCtrlFlow
2808fae59bbSEaston Man  }
281a5546049Sxiaofeibao  (outputEntries zip bypassEntries).zipWithIndex.foreach {
282a5546049Sxiaofeibao    case ((out, bypass), i) =>
28305cc2a4eSXuan Hu      when(decodeCanAccept) {
28405cc2a4eSXuan Hu        when(useBypass && io.in.valid) {
2858fae59bbSEaston Man          out := bypass
286e778bb8aSxiaofeibao-xjtu        }.otherwise {
287a5546049Sxiaofeibao          out := deqEntries(i)
2888fae59bbSEaston Man        }
289a5546049Sxiaofeibao      }.elsewhen(outputEntriesIsNotFull) {
290a5546049Sxiaofeibao        out.valid := deqEntries(i).valid
291cf7d6b7aSMuzi        out.bits := Mux(
292cf7d6b7aSMuzi          i.U < outputEntriesValidNum,
293cf7d6b7aSMuzi          out.bits,
294cf7d6b7aSMuzi          VecInit(deqEntries.take(i + 1).map(_.bits))(i.U - outputEntriesValidNum)
295cf7d6b7aSMuzi        )
2968fae59bbSEaston Man      }
2978fae59bbSEaston Man  }
2988fae59bbSEaston Man
29944c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30044c9c1deSEaston Man  // Enqueue
30144c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30244c9c1deSEaston Man  io.in.ready := allowEnq
30344c9c1deSEaston Man  // Data
30444c9c1deSEaston Man  ibuf.zipWithIndex.foreach {
30544c9c1deSEaston Man    case (entry, idx) => {
30644c9c1deSEaston Man      // Select
30744c9c1deSEaston Man      val validOH = Range(0, PredictWidth).map {
3088fae59bbSEaston Man        i =>
3098fae59bbSEaston Man          val useBypassMatch = enqOffset(i) >= DecodeWidth.U &&
3108fae59bbSEaston Man            enqPtrVec(enqOffset(i) - DecodeWidth.U).value === idx.asUInt
3118fae59bbSEaston Man          val normalMatch = enqPtrVec(enqOffset(i)).value === idx.asUInt
3128fae59bbSEaston Man          val m = Mux(useBypass, useBypassMatch, normalMatch) // when using bypass, bypassed entries do not enqueue
3138fae59bbSEaston Man
3148fae59bbSEaston Man          io.in.bits.valid(i) && io.in.bits.enqEnable(i) && m
31544c9c1deSEaston Man      } // Should be OneHot
31644c9c1deSEaston Man      val wen = validOH.reduce(_ || _) && io.in.fire && !io.flush
31744c9c1deSEaston Man
31844c9c1deSEaston Man      // Write port
31944c9c1deSEaston Man      // Each IBuffer entry has a PredictWidth -> 1 Mux
32044c9c1deSEaston Man      val writeEntry = Mux1H(validOH, enqData)
32144c9c1deSEaston Man      entry := Mux(wen, writeEntry, entry)
32244c9c1deSEaston Man
32344c9c1deSEaston Man      // Debug Assertion
32478c76c74STang Haojin      XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
32544c9c1deSEaston Man    }
32644c9c1deSEaston Man  }
32744c9c1deSEaston Man  // Pointer maintenance
32844c9c1deSEaston Man  when(io.in.fire && !io.flush) {
3298fae59bbSEaston Man    enqPtrVec := VecInit(enqPtrVec.map(_ + numTryEnq))
33044c9c1deSEaston Man  }
33144c9c1deSEaston Man
33244c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33344c9c1deSEaston Man  // Dequeue
33444c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335a5546049Sxiaofeibao  val outputEntriesValidNumNext = Wire(UInt(log2Ceil(DecodeWidth).W))
336a5546049Sxiaofeibao  XSError(outputEntriesValidNumNext > DecodeWidth.U, "Ibuffer: outputEntriesValidNumNext > DecodeWidth.U")
337a5546049Sxiaofeibao  val validVec = UIntToMask(outputEntriesValidNumNext(log2Ceil(DecodeWidth) - 1, 0), DecodeWidth)
338a5546049Sxiaofeibao  when(decodeCanAccept) {
339a5546049Sxiaofeibao    outputEntriesValidNumNext := Mux(useBypass, numBypass, numDeq)
340a5546049Sxiaofeibao  }.elsewhen(outputEntriesIsNotFull) {
341a5546049Sxiaofeibao    outputEntriesValidNumNext := outputEntriesValidNum + numDeq
342a5546049Sxiaofeibao  }.otherwise {
343a5546049Sxiaofeibao    outputEntriesValidNumNext := outputEntriesValidNum
344a5546049Sxiaofeibao  }
34544c9c1deSEaston Man  // Data
34644c9c1deSEaston Man  // Read port
34744c9c1deSEaston Man  // 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1
34844c9c1deSEaston Man  // Should be better than IBufSize -> 1 in area, with no significant latency increase
349cf7d6b7aSMuzi  private val readStage1: Vec[IBufEntry] =
350cf7d6b7aSMuzi    VecInit.tabulate(IBufNBank)(bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID)))
35144c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
3528fae59bbSEaston Man    deqEntries(i).valid := validVec(i)
353a5546049Sxiaofeibao    deqEntries(i).bits  := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1)
35444c9c1deSEaston Man  }
35544c9c1deSEaston Man  // Pointer maintenance
356ac3c9508SXuan Hu  deqBankPtrVecNext := VecInit(deqBankPtrVec.map(_ + numDeq))
357ac3c9508SXuan Hu  deqPtrNext        := deqPtr + numDeq
35805cc2a4eSXuan Hu  deqInBankPtrNext.zip(deqInBankPtr).zipWithIndex.foreach {
35905cc2a4eSXuan Hu    case ((ptrNext, ptr), idx) => {
36044c9c1deSEaston Man      // validVec[k] == bankValid[deqBankPtr + k]
36144c9c1deSEaston Man      // So bankValid[n] == validVec[n - deqBankPtr]
362cf7d6b7aSMuzi      val validIdx = Mux(
363cf7d6b7aSMuzi        idx.asUInt >= deqBankPtr.value,
36444c9c1deSEaston Man        idx.asUInt - deqBankPtr.value,
36544c9c1deSEaston Man        ((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0)
36645b8fd86SEaston Man      )(log2Ceil(DecodeWidth) - 1, 0)
367a5546049Sxiaofeibao      val bankAdvance = numOut > validIdx
36805cc2a4eSXuan Hu      ptrNext := Mux(bankAdvance, ptr + 1.U, ptr)
36944c9c1deSEaston Man    }
37044c9c1deSEaston Man  }
37144c9c1deSEaston Man
37244c9c1deSEaston Man  // Flush
37344c9c1deSEaston Man  when(io.flush) {
37444c9c1deSEaston Man    allowEnq      := true.B
37544c9c1deSEaston Man    enqPtrVec     := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr))
37644c9c1deSEaston Man    deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr))
37744c9c1deSEaston Man    deqInBankPtr  := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))
37844c9c1deSEaston Man    deqPtr        := 0.U.asTypeOf(new IBufPtr())
3798fae59bbSEaston Man    outputEntries.foreach(_.valid := false.B)
38005cc2a4eSXuan Hu  }.otherwise {
38105cc2a4eSXuan Hu    deqPtr        := deqPtrNext
38205cc2a4eSXuan Hu    deqInBankPtr  := deqInBankPtrNext
38305cc2a4eSXuan Hu    deqBankPtrVec := deqBankPtrVecNext
38444c9c1deSEaston Man  }
38544c9c1deSEaston Man  io.full := !allowEnq
38644c9c1deSEaston Man
38744c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
38844c9c1deSEaston Man  // TopDown
38944c9c1deSEaston Man  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
39044c9c1deSEaston Man  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
39144c9c1deSEaston Man  topdown_stage := io.in.bits.topdown_info
39244c9c1deSEaston Man  when(io.flush) {
39344c9c1deSEaston Man    when(io.ControlRedirect) {
39444c9c1deSEaston Man      when(io.ControlBTBMissBubble) {
39544c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
39644c9c1deSEaston Man      }.elsewhen(io.TAGEMissBubble) {
39744c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
39844c9c1deSEaston Man      }.elsewhen(io.SCMissBubble) {
39944c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
40044c9c1deSEaston Man      }.elsewhen(io.ITTAGEMissBubble) {
40144c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
40244c9c1deSEaston Man      }.elsewhen(io.RASMissBubble) {
40344c9c1deSEaston Man        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
40444c9c1deSEaston Man      }
40544c9c1deSEaston Man    }.elsewhen(io.MemVioRedirect) {
40644c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
40744c9c1deSEaston Man    }.otherwise {
40844c9c1deSEaston Man      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
40944c9c1deSEaston Man    }
41044c9c1deSEaston Man  }
41144c9c1deSEaston Man
41244c9c1deSEaston Man  val matchBubble   = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W))
41344c9c1deSEaston Man  val deqValidCount = PopCount(validVec.asBools)
41444c9c1deSEaston Man  val deqWasteCount = DecodeWidth.U - deqValidCount
41544c9c1deSEaston Man  matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse)
41644c9c1deSEaston Man
41744c9c1deSEaston Man  io.stallReason.reason.map(_ := 0.U)
41844c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
41944c9c1deSEaston Man    when(i.U < deqWasteCount) {
42044c9c1deSEaston Man      io.stallReason.reason(DecodeWidth - i - 1) := matchBubble
42144c9c1deSEaston Man    }
42244c9c1deSEaston Man  }
42344c9c1deSEaston Man
42444c9c1deSEaston Man  when(!(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR)) {
42544c9c1deSEaston Man    // should set reason for FetchFragmentationStall
42644c9c1deSEaston Man    // topdown_stage.reasons(TopDownCounters.FetchFragmentationStall.id) := true.B
42744c9c1deSEaston Man    for (i <- 0 until DecodeWidth) {
42844c9c1deSEaston Man      when(i.U < deqWasteCount) {
42944c9c1deSEaston Man        io.stallReason.reason(DecodeWidth - i - 1) := TopDownCounters.FetchFragBubble.id.U
43044c9c1deSEaston Man      }
43144c9c1deSEaston Man    }
43244c9c1deSEaston Man  }
43344c9c1deSEaston Man
43444c9c1deSEaston Man  when(io.stallReason.backReason.valid) {
43544c9c1deSEaston Man    io.stallReason.reason.map(_ := io.stallReason.backReason.bits)
43644c9c1deSEaston Man  }
43744c9c1deSEaston Man
43844c9c1deSEaston Man  // Debug info
43944c9c1deSEaston Man  XSError(
44044c9c1deSEaston Man    deqPtr.value =/= deqBankPtr.value + deqInBankPtr(deqBankPtr.value).value * IBufNBank.asUInt,
44144c9c1deSEaston Man    "Dequeue PTR mismatch"
44244c9c1deSEaston Man  )
44305cc2a4eSXuan Hu  XSError(isBefore(enqPtr, deqPtr) && !isFull(enqPtr, deqPtr), "\ndeqPtr is older than enqPtr!\n")
44405cc2a4eSXuan Hu
44544c9c1deSEaston Man  XSDebug(io.flush, "IBuffer Flushed\n")
44644c9c1deSEaston Man
4478b33cd30Sklin02  XSDebug(io.in.fire, "Enque:\n")
4488b33cd30Sklin02  XSDebug(io.in.fire, p"MASK=${Binary(io.in.bits.valid)}\n")
44944c9c1deSEaston Man  for (i <- 0 until PredictWidth) {
4508b33cd30Sklin02    XSDebug(io.in.fire, p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n")
45144c9c1deSEaston Man  }
45244c9c1deSEaston Man
45344c9c1deSEaston Man  for (i <- 0 until DecodeWidth) {
454cf7d6b7aSMuzi    XSDebug(
455cf7d6b7aSMuzi      io.out(i).fire,
45644c9c1deSEaston Man      p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" +
45744c9c1deSEaston Man        p"v=${io.out(i).valid} r=${io.out(i).ready} " +
458cf7d6b7aSMuzi        p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n"
459cf7d6b7aSMuzi    )
46044c9c1deSEaston Man  }
46144c9c1deSEaston Man
46205cc2a4eSXuan Hu  XSDebug(p"numValid: ${numValid}\n")
46344c9c1deSEaston Man  XSDebug(p"EnqNum: ${numEnq}\n")
46444c9c1deSEaston Man  XSDebug(p"DeqNum: ${numDeq}\n")
46544c9c1deSEaston Man
46644c9c1deSEaston Man  val afterInit  = RegInit(false.B)
46744c9c1deSEaston Man  val headBubble = RegInit(false.B)
468cf7d6b7aSMuzi  when(io.in.fire)(afterInit := true.B)
46944c9c1deSEaston Man  when(io.flush) {
47044c9c1deSEaston Man    headBubble := true.B
47105cc2a4eSXuan Hu  }.elsewhen(numValid =/= 0.U) {
47244c9c1deSEaston Man    headBubble := false.B
47344c9c1deSEaston Man  }
47405cc2a4eSXuan Hu  val instrHungry = afterInit && (numValid === 0.U) && !headBubble
47544c9c1deSEaston Man
47605cc2a4eSXuan Hu  QueuePerf(IBufSize, numValid, !allowEnq)
47744c9c1deSEaston Man  XSPerfAccumulate("flush", io.flush)
47844c9c1deSEaston Man  XSPerfAccumulate("hungry", instrHungry)
47944c9c1deSEaston Man
48005cc2a4eSXuan Hu  val ibuffer_IDWidth_hvButNotFull = afterInit && (numValid =/= 0.U) && (numValid < DecodeWidth.U) && !headBubble
48144c9c1deSEaston Man  XSPerfAccumulate("ibuffer_IDWidth_hvButNotFull", ibuffer_IDWidth_hvButNotFull)
48227d10d0cSEaston Man
4839cd76b21SZhaoyang You  val FrontBubble = Mux(decodeCanAccept && !headBubble, DecodeWidth.U - numOut, 0.U)
48444c9c1deSEaston Man
485e836c770SZhaoyang You  val fetchLatency = decodeCanAccept && !headBubble && numOut === 0.U
486e836c770SZhaoyang You
487e836c770SZhaoyang You  XSPerfAccumulate("if_fetch_bubble", FrontBubble)
488e836c770SZhaoyang You  XSPerfAccumulate("if_fetch_bubble_eq_max", fetchLatency)
489e836c770SZhaoyang You
49044c9c1deSEaston Man  val perfEvents = Seq(
49144c9c1deSEaston Man    ("IBuffer_Flushed  ", io.flush),
49244c9c1deSEaston Man    ("IBuffer_hungry   ", instrHungry),
49305cc2a4eSXuan Hu    ("IBuffer_1_4_valid", (numValid > (0 * (IBufSize / 4)).U) & (numValid < (1 * (IBufSize / 4)).U)),
49405cc2a4eSXuan Hu    ("IBuffer_2_4_valid", (numValid >= (1 * (IBufSize / 4)).U) & (numValid < (2 * (IBufSize / 4)).U)),
49505cc2a4eSXuan Hu    ("IBuffer_3_4_valid", (numValid >= (2 * (IBufSize / 4)).U) & (numValid < (3 * (IBufSize / 4)).U)),
49605cc2a4eSXuan Hu    ("IBuffer_4_4_valid", (numValid >= (3 * (IBufSize / 4)).U) & (numValid < (4 * (IBufSize / 4)).U)),
49705cc2a4eSXuan Hu    ("IBuffer_full     ", numValid.andR),
498e836c770SZhaoyang You    ("Front_Bubble     ", FrontBubble),
499e836c770SZhaoyang You    ("Fetch_Latency_Bound", fetchLatency)
50044c9c1deSEaston Man  )
50144c9c1deSEaston Man  generatePerfEvent()
50244c9c1deSEaston Man}
503