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()) 5405cc2a4eSXuan Hu val decodeCanAccept = Input(Bool()) 5544c9c1deSEaston Man val stallReason = new StallReasonIO(DecodeWidth) 5644c9c1deSEaston Man} 5744c9c1deSEaston Man 5844c9c1deSEaston Manclass IBufEntry(implicit p: Parameters) extends XSBundle { 5944c9c1deSEaston Man val inst = UInt(32.W) 6044c9c1deSEaston Man val pc = UInt(VAddrBits.W) 6144c9c1deSEaston Man val foldpc = UInt(MemPredPCWidth.W) 6244c9c1deSEaston Man val pd = new PreDecodeInfo 6344c9c1deSEaston Man val pred_taken = Bool() 6444c9c1deSEaston Man val ftqPtr = new FtqPtr 6544c9c1deSEaston Man val ftqOffset = UInt(log2Ceil(PredictWidth).W) 6644c9c1deSEaston Man val ipf = Bool() 67d0de7e4aSpeixiaokun val igpf = Bool() 6844c9c1deSEaston Man val acf = Bool() 6944c9c1deSEaston Man val crossPageIPFFix = Bool() 7044c9c1deSEaston Man val triggered = new TriggerCf 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) 7644c9c1deSEaston Man pd := fetch.pd(i) 7744c9c1deSEaston Man pred_taken := fetch.ftqOffset(i).valid 7844c9c1deSEaston Man ftqPtr := fetch.ftqPtr 7944c9c1deSEaston Man ftqOffset := fetch.ftqOffset(i).bits 8044c9c1deSEaston Man ipf := fetch.ipf(i) 81d0de7e4aSpeixiaokun igpf:= fetch.igpf(i) 8244c9c1deSEaston Man acf := fetch.acf(i) 8344c9c1deSEaston Man crossPageIPFFix := fetch.crossPageIPFFix(i) 8444c9c1deSEaston Man triggered := fetch.triggered(i) 8544c9c1deSEaston Man this 8644c9c1deSEaston Man } 8744c9c1deSEaston Man 8844c9c1deSEaston Man def toCtrlFlow: CtrlFlow = { 8944c9c1deSEaston Man val cf = Wire(new CtrlFlow) 9044c9c1deSEaston Man cf.instr := inst 9144c9c1deSEaston Man cf.pc := pc 9244c9c1deSEaston Man cf.foldpc := foldpc 9344c9c1deSEaston Man cf.exceptionVec := 0.U.asTypeOf(ExceptionVec()) 9444c9c1deSEaston Man cf.exceptionVec(instrPageFault) := ipf 95d0de7e4aSpeixiaokun cf.exceptionVec(instrGuestPageFault) := igpf 9644c9c1deSEaston Man cf.exceptionVec(instrAccessFault) := acf 9744c9c1deSEaston Man cf.trigger := triggered 9844c9c1deSEaston Man cf.pd := pd 9944c9c1deSEaston Man cf.pred_taken := pred_taken 10044c9c1deSEaston Man cf.crossPageIPFFix := crossPageIPFFix 10144c9c1deSEaston Man cf.storeSetHit := DontCare 10244c9c1deSEaston Man cf.waitForRobIdx := DontCare 10344c9c1deSEaston Man cf.loadWaitBit := DontCare 10444c9c1deSEaston Man cf.loadWaitStrict := DontCare 10544c9c1deSEaston Man cf.ssid := DontCare 10644c9c1deSEaston Man cf.ftqPtr := ftqPtr 10744c9c1deSEaston Man cf.ftqOffset := ftqOffset 10844c9c1deSEaston Man cf 10944c9c1deSEaston Man } 11044c9c1deSEaston Man} 11144c9c1deSEaston Man 11244c9c1deSEaston Manclass IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents { 11344c9c1deSEaston Man val io = IO(new IBufferIO) 11444c9c1deSEaston Man 11505cc2a4eSXuan Hu // io alias 11605cc2a4eSXuan Hu private val decodeCanAccept = io.decodeCanAccept 11705cc2a4eSXuan Hu 11844c9c1deSEaston Man // Parameter Check 11944c9c1deSEaston Man private val bankSize = IBufSize / IBufNBank 12044c9c1deSEaston Man require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize") 12144c9c1deSEaston Man require(IBufNBank >= DecodeWidth, 12244c9c1deSEaston Man s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth") 12344c9c1deSEaston Man 12444c9c1deSEaston Man // IBuffer is organized as raw registers 12544c9c1deSEaston Man // This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled 12644c9c1deSEaston Man // . + + E E E - . 12744c9c1deSEaston Man // . + + E E E - . 12844c9c1deSEaston Man // . . + E E E - . 12944c9c1deSEaston Man // . . + E E E E - 13044c9c1deSEaston Man // As shown above, + means enqueue, - means dequeue, E is current content 13144c9c1deSEaston Man // When dequeue, read port is organized like a banked FIFO 13244c9c1deSEaston Man // Dequeue reads no more than 1 entry from each bank sequentially, this can be exploit to reduce area 13344c9c1deSEaston Man // Enqueue writes cannot benefit from this characteristic unless use a SRAM 13444c9c1deSEaston Man // For detail see Enqueue and Dequeue below 13544c9c1deSEaston Man private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry))) 13644c9c1deSEaston Man private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)( 13744c9c1deSEaston Man bankID => VecInit.tabulate(bankSize)( 13844c9c1deSEaston Man inBankOffset => ibuf(bankID + inBankOffset * IBufNBank) 13944c9c1deSEaston Man ) 14044c9c1deSEaston Man ) 14144c9c1deSEaston Man 1428fae59bbSEaston Man 1438fae59bbSEaston Man // Bypass wire 1448fae59bbSEaston Man private val bypassEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 1458fae59bbSEaston Man // Normal read wire 1468fae59bbSEaston Man private val deqEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 1478fae59bbSEaston Man // Output register 1488fae59bbSEaston Man private val outputEntries = RegInit(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry)))) 1498fae59bbSEaston Man 15044c9c1deSEaston Man // Between Bank 15144c9c1deSEaston Man private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr))) 15244c9c1deSEaston Man private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0) 15305cc2a4eSXuan Hu private val deqBankPtrVecNext = Wire(deqBankPtrVec.cloneType) 15444c9c1deSEaston Man // Inside Bank 15544c9c1deSEaston Man private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))) 15605cc2a4eSXuan Hu private val deqInBankPtrNext = Wire(deqInBankPtr.cloneType) 15744c9c1deSEaston Man 15844c9c1deSEaston Man val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr)) 15905cc2a4eSXuan Hu val deqPtrNext = Wire(deqPtr.cloneType) 16044c9c1deSEaston Man 16144c9c1deSEaston Man val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr))) 16244c9c1deSEaston Man val enqPtr = enqPtrVec(0) 16344c9c1deSEaston Man 1648fae59bbSEaston Man val numTryEnq = WireDefault(0.U) 1658fae59bbSEaston Man val numEnq = Mux(io.in.fire, numTryEnq, 0.U) 1668fae59bbSEaston Man 16705cc2a4eSXuan Hu // Record the insts in output entries are from bypass or deq. 16805cc2a4eSXuan Hu // Update deqPtr if they are from deq 16905cc2a4eSXuan Hu val currentOutUseBypass = RegInit(false.B) 170*e778bb8aSxiaofeibao-xjtu val numBypassRemain = RegInit(0.U(log2Up(DecodeWidth).W)) 171*e778bb8aSxiaofeibao-xjtu val numBypassRemainNext = Wire(numBypassRemain.cloneType) 172*e778bb8aSxiaofeibao-xjtu 173*e778bb8aSxiaofeibao-xjtu // empty and decode can accept insts and previous bypass insts are all out 174*e778bb8aSxiaofeibao-xjtu val useBypass = enqPtr === deqPtr && decodeCanAccept && (numBypassRemain === 0.U || currentOutUseBypass && numBypassRemainNext === 0.U) 17505cc2a4eSXuan Hu 17605cc2a4eSXuan Hu // The number of decode accepted insts. 17705cc2a4eSXuan Hu // Since decode promises accepting insts in order, use priority encoder to simplify the accumulation. 17805cc2a4eSXuan Hu private val numOut: UInt = PriorityMuxDefault(io.out.map(x => !x.ready) zip (0 until DecodeWidth).map(_.U), DecodeWidth.U) 17905cc2a4eSXuan Hu private val numDeq = Mux(currentOutUseBypass, 0.U, numOut) 18005cc2a4eSXuan Hu 18105cc2a4eSXuan Hu // counter current number of valid 18205cc2a4eSXuan Hu val numValid = distanceBetween(enqPtr, deqPtr) 18305cc2a4eSXuan Hu val numValidAfterDeq = numValid - numDeq 18405cc2a4eSXuan Hu // counter next number of valid 18505cc2a4eSXuan Hu val numValidNext = numValid + numEnq - numDeq 18605cc2a4eSXuan Hu val allowEnq = RegInit(true.B) 18705cc2a4eSXuan Hu val numFromFetch = Mux(io.in.valid, PopCount(io.in.bits.enqEnable), 0.U) 18805cc2a4eSXuan Hu val numBypass = PopCount(bypassEntries.map(_.valid)) 18905cc2a4eSXuan Hu 19005cc2a4eSXuan Hu allowEnq := (IBufSize - PredictWidth).U >= numValidNext // Disable when almost full 19144c9c1deSEaston Man 1928fae59bbSEaston Man val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i))) 1938fae59bbSEaston Man val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i)) 1948fae59bbSEaston Man 1958fae59bbSEaston Man // when using bypass, bypassed entries do not enqueue 1968fae59bbSEaston Man when(useBypass) { 1978fae59bbSEaston Man when(numFromFetch >= DecodeWidth.U) { 1988fae59bbSEaston Man numTryEnq := numFromFetch - DecodeWidth.U 1998fae59bbSEaston Man } .otherwise { 2008fae59bbSEaston Man numTryEnq := 0.U 2018fae59bbSEaston Man } 2028fae59bbSEaston Man } .otherwise { 2038fae59bbSEaston Man numTryEnq := numFromFetch 2048fae59bbSEaston Man } 2058fae59bbSEaston Man 2068fae59bbSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2078fae59bbSEaston Man // Bypass 2088fae59bbSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2098fae59bbSEaston Man bypassEntries.zipWithIndex.foreach { 2108fae59bbSEaston Man case (entry, idx) => 2118fae59bbSEaston Man // Select 2128fae59bbSEaston Man val validOH = Range(0, PredictWidth).map { 2138fae59bbSEaston Man i => 2148fae59bbSEaston Man io.in.bits.valid(i) && 2158fae59bbSEaston Man io.in.bits.enqEnable(i) && 2168fae59bbSEaston Man enqOffset(i) === idx.asUInt 2178fae59bbSEaston Man } // Should be OneHot 2188fae59bbSEaston Man entry.valid := validOH.reduce(_ || _) && io.in.fire && !io.flush 2198fae59bbSEaston Man entry.bits := Mux1H(validOH, enqData) 2208fae59bbSEaston Man 2218fae59bbSEaston Man // Debug Assertion 2229afa8a47STang Haojin XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot") 2238fae59bbSEaston Man } 2248fae59bbSEaston Man 2258fae59bbSEaston Man // => Decode Output 2268fae59bbSEaston Man // clean register output 2278fae59bbSEaston Man io.out zip outputEntries foreach { 2288fae59bbSEaston Man case (io, reg) => 2298fae59bbSEaston Man io.valid := reg.valid 2308fae59bbSEaston Man io.bits := reg.bits.toCtrlFlow 2318fae59bbSEaston Man } 232*e778bb8aSxiaofeibao-xjtu (outputEntries zip bypassEntries zip deqEntries).zipWithIndex.foreach { 233*e778bb8aSxiaofeibao-xjtu case (((out, bypass), deq), i) => 23405cc2a4eSXuan Hu when(decodeCanAccept) { 23505cc2a4eSXuan Hu when(useBypass && io.in.valid) { 2368fae59bbSEaston Man out := bypass 23705cc2a4eSXuan Hu currentOutUseBypass := true.B 238*e778bb8aSxiaofeibao-xjtu }.elsewhen(currentOutUseBypass && numBypassRemainNext =/= 0.U) { 239*e778bb8aSxiaofeibao-xjtu out := Mux(i.U < numBypassRemainNext, outputEntries(i.U + numOut), 0.U.asTypeOf(out)) 240*e778bb8aSxiaofeibao-xjtu currentOutUseBypass := true.B 241*e778bb8aSxiaofeibao-xjtu }.otherwise { 242*e778bb8aSxiaofeibao-xjtu out := deq 243*e778bb8aSxiaofeibao-xjtu currentOutUseBypass := false.B 2448fae59bbSEaston Man } 2458fae59bbSEaston Man } 2468fae59bbSEaston Man } 2478fae59bbSEaston Man 248*e778bb8aSxiaofeibao-xjtu when(useBypass && io.in.valid) { 249*e778bb8aSxiaofeibao-xjtu numBypassRemain := numBypass 250*e778bb8aSxiaofeibao-xjtu }.elsewhen(currentOutUseBypass) { 251*e778bb8aSxiaofeibao-xjtu numBypassRemain := numBypassRemainNext 252*e778bb8aSxiaofeibao-xjtu }.otherwise { 253*e778bb8aSxiaofeibao-xjtu assert(numBypassRemain === 0.U, "numBypassRemain should keep 0 when not in currentOutUseBypass") 254*e778bb8aSxiaofeibao-xjtu } 255*e778bb8aSxiaofeibao-xjtu numBypassRemainNext := numBypassRemain - numOut 256*e778bb8aSxiaofeibao-xjtu 25744c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 25844c9c1deSEaston Man // Enqueue 25944c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 26044c9c1deSEaston Man io.in.ready := allowEnq 26144c9c1deSEaston Man // Data 26244c9c1deSEaston Man ibuf.zipWithIndex.foreach { 26344c9c1deSEaston Man case (entry, idx) => { 26444c9c1deSEaston Man // Select 26544c9c1deSEaston Man val validOH = Range(0, PredictWidth).map { 2668fae59bbSEaston Man i => 2678fae59bbSEaston Man val useBypassMatch = enqOffset(i) >= DecodeWidth.U && 2688fae59bbSEaston Man enqPtrVec(enqOffset(i) - DecodeWidth.U).value === idx.asUInt 2698fae59bbSEaston Man val normalMatch = enqPtrVec(enqOffset(i)).value === idx.asUInt 2708fae59bbSEaston Man val m = Mux(useBypass, useBypassMatch, normalMatch) // when using bypass, bypassed entries do not enqueue 2718fae59bbSEaston Man 2728fae59bbSEaston Man io.in.bits.valid(i) && io.in.bits.enqEnable(i) && m 27344c9c1deSEaston Man } // Should be OneHot 27444c9c1deSEaston Man val wen = validOH.reduce(_ || _) && io.in.fire && !io.flush 27544c9c1deSEaston Man 27644c9c1deSEaston Man // Write port 27744c9c1deSEaston Man // Each IBuffer entry has a PredictWidth -> 1 Mux 27844c9c1deSEaston Man val writeEntry = Mux1H(validOH, enqData) 27944c9c1deSEaston Man entry := Mux(wen, writeEntry, entry) 28044c9c1deSEaston Man 28144c9c1deSEaston Man // Debug Assertion 28278c76c74STang Haojin XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot") 28344c9c1deSEaston Man } 28444c9c1deSEaston Man } 28544c9c1deSEaston Man // Pointer maintenance 28644c9c1deSEaston Man when (io.in.fire && !io.flush) { 2878fae59bbSEaston Man enqPtrVec := VecInit(enqPtrVec.map(_ + numTryEnq)) 28844c9c1deSEaston Man } 28944c9c1deSEaston Man 29044c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 29144c9c1deSEaston Man // Dequeue 29244c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 29305cc2a4eSXuan Hu val validVec = Mux(numValidAfterDeq >= DecodeWidth.U, 29444c9c1deSEaston Man ((1 << DecodeWidth) - 1).U, 29505cc2a4eSXuan Hu UIntToMask(numValidAfterDeq(log2Ceil(DecodeWidth) - 1, 0), DecodeWidth) 29644c9c1deSEaston Man ) 29744c9c1deSEaston Man // Data 29844c9c1deSEaston Man // Read port 29944c9c1deSEaston Man // 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1 30044c9c1deSEaston Man // Should be better than IBufSize -> 1 in area, with no significant latency increase 30144c9c1deSEaston Man private val readStage1: Vec[IBufEntry] = VecInit.tabulate(IBufNBank)( 30205cc2a4eSXuan Hu bankID => Mux1H(UIntToOH(deqInBankPtrNext(bankID).value), bankedIBufView(bankID)) 30344c9c1deSEaston Man ) 30444c9c1deSEaston Man for (i <- 0 until DecodeWidth) { 3058fae59bbSEaston Man deqEntries(i).valid := validVec(i) 30605cc2a4eSXuan Hu deqEntries(i).bits := Mux1H(UIntToOH(deqBankPtrVecNext(i).value), readStage1) 30744c9c1deSEaston Man } 30844c9c1deSEaston Man // Pointer maintenance 309ac3c9508SXuan Hu deqBankPtrVecNext := VecInit(deqBankPtrVec.map(_ + numDeq)) 310ac3c9508SXuan Hu deqPtrNext := deqPtr + numDeq 31105cc2a4eSXuan Hu deqInBankPtrNext.zip(deqInBankPtr).zipWithIndex.foreach { 31205cc2a4eSXuan Hu case ((ptrNext, ptr), idx) => { 31344c9c1deSEaston Man // validVec[k] == bankValid[deqBankPtr + k] 31444c9c1deSEaston Man // So bankValid[n] == validVec[n - deqBankPtr] 31544c9c1deSEaston Man val validIdx = Mux(idx.asUInt >= deqBankPtr.value, 31644c9c1deSEaston Man idx.asUInt - deqBankPtr.value, 31744c9c1deSEaston Man ((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0) 31845b8fd86SEaston Man )(log2Ceil(DecodeWidth) - 1, 0) 31944c9c1deSEaston Man val bankAdvance = Mux(validIdx >= DecodeWidth.U, 32044c9c1deSEaston Man false.B, 32105cc2a4eSXuan Hu io.out(validIdx).ready // `ready` depends on `valid`, so we need only `ready`, not fire 32205cc2a4eSXuan Hu ) && !currentOutUseBypass 32305cc2a4eSXuan Hu ptrNext := Mux(bankAdvance , ptr + 1.U, ptr) 32444c9c1deSEaston Man } 32544c9c1deSEaston Man } 32644c9c1deSEaston Man 32744c9c1deSEaston Man // Flush 32844c9c1deSEaston Man when (io.flush) { 32944c9c1deSEaston Man allowEnq := true.B 33044c9c1deSEaston Man enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr)) 33144c9c1deSEaston Man deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr)) 33244c9c1deSEaston Man deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)) 33344c9c1deSEaston Man deqPtr := 0.U.asTypeOf(new IBufPtr()) 3348fae59bbSEaston Man outputEntries.foreach(_.valid := false.B) 335*e778bb8aSxiaofeibao-xjtu currentOutUseBypass := false.B 336*e778bb8aSxiaofeibao-xjtu numBypassRemain := 0.U 33705cc2a4eSXuan Hu }.otherwise { 33805cc2a4eSXuan Hu deqPtr := deqPtrNext 33905cc2a4eSXuan Hu deqInBankPtr := deqInBankPtrNext 34005cc2a4eSXuan Hu deqBankPtrVec := deqBankPtrVecNext 34144c9c1deSEaston Man } 34244c9c1deSEaston Man io.full := !allowEnq 34344c9c1deSEaston Man 34444c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 34544c9c1deSEaston Man // TopDown 34644c9c1deSEaston Man ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 34744c9c1deSEaston Man val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 34844c9c1deSEaston Man topdown_stage := io.in.bits.topdown_info 34944c9c1deSEaston Man when(io.flush) { 35044c9c1deSEaston Man when(io.ControlRedirect) { 35144c9c1deSEaston Man when(io.ControlBTBMissBubble) { 35244c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 35344c9c1deSEaston Man }.elsewhen(io.TAGEMissBubble) { 35444c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 35544c9c1deSEaston Man }.elsewhen(io.SCMissBubble) { 35644c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 35744c9c1deSEaston Man }.elsewhen(io.ITTAGEMissBubble) { 35844c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 35944c9c1deSEaston Man }.elsewhen(io.RASMissBubble) { 36044c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 36144c9c1deSEaston Man } 36244c9c1deSEaston Man }.elsewhen(io.MemVioRedirect) { 36344c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 36444c9c1deSEaston Man }.otherwise { 36544c9c1deSEaston Man topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 36644c9c1deSEaston Man } 36744c9c1deSEaston Man } 36844c9c1deSEaston Man 36944c9c1deSEaston Man 37044c9c1deSEaston Man val dequeueInsufficient = Wire(Bool()) 37144c9c1deSEaston Man val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W)) 37244c9c1deSEaston Man val deqValidCount = PopCount(validVec.asBools) 37344c9c1deSEaston Man val deqWasteCount = DecodeWidth.U - deqValidCount 37444c9c1deSEaston Man dequeueInsufficient := deqValidCount < DecodeWidth.U 37544c9c1deSEaston Man matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse) 37644c9c1deSEaston Man 37744c9c1deSEaston Man io.stallReason.reason.map(_ := 0.U) 37844c9c1deSEaston Man for (i <- 0 until DecodeWidth) { 37944c9c1deSEaston Man when(i.U < deqWasteCount) { 38044c9c1deSEaston Man io.stallReason.reason(DecodeWidth - i - 1) := matchBubble 38144c9c1deSEaston Man } 38244c9c1deSEaston Man } 38344c9c1deSEaston Man 38444c9c1deSEaston Man when(!(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR)) { 38544c9c1deSEaston Man // should set reason for FetchFragmentationStall 38644c9c1deSEaston Man // topdown_stage.reasons(TopDownCounters.FetchFragmentationStall.id) := true.B 38744c9c1deSEaston Man for (i <- 0 until DecodeWidth) { 38844c9c1deSEaston Man when(i.U < deqWasteCount) { 38944c9c1deSEaston Man io.stallReason.reason(DecodeWidth - i - 1) := TopDownCounters.FetchFragBubble.id.U 39044c9c1deSEaston Man } 39144c9c1deSEaston Man } 39244c9c1deSEaston Man } 39344c9c1deSEaston Man 39444c9c1deSEaston Man when(io.stallReason.backReason.valid) { 39544c9c1deSEaston Man io.stallReason.reason.map(_ := io.stallReason.backReason.bits) 39644c9c1deSEaston Man } 39744c9c1deSEaston Man 39844c9c1deSEaston Man // Debug info 39944c9c1deSEaston Man XSError( 40044c9c1deSEaston Man deqPtr.value =/= deqBankPtr.value + deqInBankPtr(deqBankPtr.value).value * IBufNBank.asUInt, 40144c9c1deSEaston Man "Dequeue PTR mismatch" 40244c9c1deSEaston Man ) 40305cc2a4eSXuan Hu XSError(isBefore(enqPtr, deqPtr) && !isFull(enqPtr, deqPtr), "\ndeqPtr is older than enqPtr!\n") 40405cc2a4eSXuan Hu 40544c9c1deSEaston Man XSDebug(io.flush, "IBuffer Flushed\n") 40644c9c1deSEaston Man 40744c9c1deSEaston Man when(io.in.fire) { 40844c9c1deSEaston Man XSDebug("Enque:\n") 40944c9c1deSEaston Man XSDebug(p"MASK=${Binary(io.in.bits.valid)}\n") 41044c9c1deSEaston Man for(i <- 0 until PredictWidth){ 41144c9c1deSEaston Man XSDebug(p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n") 41244c9c1deSEaston Man } 41344c9c1deSEaston Man } 41444c9c1deSEaston Man 41544c9c1deSEaston Man for (i <- 0 until DecodeWidth) { 41644c9c1deSEaston Man XSDebug(io.out(i).fire, 41744c9c1deSEaston Man p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" + 41844c9c1deSEaston Man p"v=${io.out(i).valid} r=${io.out(i).ready} " + 41944c9c1deSEaston Man p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n") 42044c9c1deSEaston Man } 42144c9c1deSEaston Man 42205cc2a4eSXuan Hu XSDebug(p"numValid: ${numValid}\n") 42344c9c1deSEaston Man XSDebug(p"EnqNum: ${numEnq}\n") 42444c9c1deSEaston Man XSDebug(p"DeqNum: ${numDeq}\n") 42544c9c1deSEaston Man 42644c9c1deSEaston Man val afterInit = RegInit(false.B) 42744c9c1deSEaston Man val headBubble = RegInit(false.B) 42844c9c1deSEaston Man when (io.in.fire) { afterInit := true.B } 42944c9c1deSEaston Man when (io.flush) { 43044c9c1deSEaston Man headBubble := true.B 43105cc2a4eSXuan Hu } .elsewhen(numValid =/= 0.U) { 43244c9c1deSEaston Man headBubble := false.B 43344c9c1deSEaston Man } 43405cc2a4eSXuan Hu val instrHungry = afterInit && (numValid === 0.U) && !headBubble 43544c9c1deSEaston Man 43605cc2a4eSXuan Hu QueuePerf(IBufSize, numValid, !allowEnq) 43744c9c1deSEaston Man XSPerfAccumulate("flush", io.flush) 43844c9c1deSEaston Man XSPerfAccumulate("hungry", instrHungry) 43944c9c1deSEaston Man 44005cc2a4eSXuan Hu val ibuffer_IDWidth_hvButNotFull = afterInit && (numValid =/= 0.U) && (numValid < DecodeWidth.U) && !headBubble 44144c9c1deSEaston Man XSPerfAccumulate("ibuffer_IDWidth_hvButNotFull", ibuffer_IDWidth_hvButNotFull) 44244c9c1deSEaston Man /* 44344c9c1deSEaston Man XSPerfAccumulate("ICacheMissBubble", Mux(matchBubbleVec(TopDownCounters.ICacheMissBubble.id), deqWasteCount, 0.U)) 44444c9c1deSEaston Man XSPerfAccumulate("ITLBMissBubble", Mux(matchBubbleVec(TopDownCounters.ITLBMissBubble.id), deqWasteCount, 0.U)) 44544c9c1deSEaston Man XSPerfAccumulate("ControlRedirectBubble", Mux(matchBubbleVec(TopDownCounters.ControlRedirectBubble.id), deqWasteCount, 0.U)) 44644c9c1deSEaston Man XSPerfAccumulate("MemVioRedirectBubble", Mux(matchBubbleVec(TopDownCounters.MemVioRedirectBubble.id), deqWasteCount, 0.U)) 44744c9c1deSEaston Man XSPerfAccumulate("OtherRedirectBubble", Mux(matchBubbleVec(TopDownCounters.OtherRedirectBubble.id), deqWasteCount, 0.U)) 44844c9c1deSEaston Man XSPerfAccumulate("BTBMissBubble", Mux(matchBubbleVec(TopDownCounters.BTBMissBubble.id), deqWasteCount, 0.U)) 44944c9c1deSEaston Man XSPerfAccumulate("OverrideBubble", Mux(matchBubbleVec(TopDownCounters.OverrideBubble.id), deqWasteCount, 0.U)) 45044c9c1deSEaston Man XSPerfAccumulate("FtqUpdateBubble", Mux(matchBubbleVec(TopDownCounters.FtqUpdateBubble.id), deqWasteCount, 0.U)) 45144c9c1deSEaston Man XSPerfAccumulate("FtqFullStall", Mux(matchBubbleVec(TopDownCounters.FtqFullStall.id), deqWasteCount, 0.U)) 45244c9c1deSEaston Man XSPerfAccumulate("FetchFragmentBubble", 45344c9c1deSEaston Man Mux(deqWasteCount === DecodeWidth.U || topdown_stage.reasons.asUInt.orR, 0.U, deqWasteCount)) 45444c9c1deSEaston Man XSPerfAccumulate("TAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.TAGEMissBubble.id), deqWasteCount, 0.U)) 45544c9c1deSEaston Man XSPerfAccumulate("SCMissBubble", Mux(matchBubbleVec(TopDownCounters.SCMissBubble.id), deqWasteCount, 0.U)) 45644c9c1deSEaston Man XSPerfAccumulate("ITTAGEMissBubble", Mux(matchBubbleVec(TopDownCounters.ITTAGEMissBubble.id), deqWasteCount, 0.U)) 45744c9c1deSEaston Man XSPerfAccumulate("RASMissBubble", Mux(matchBubbleVec(TopDownCounters.RASMissBubble.id), deqWasteCount, 0.U)) 45844c9c1deSEaston Man */ 45944c9c1deSEaston Man 46044c9c1deSEaston Man val perfEvents = Seq( 46144c9c1deSEaston Man ("IBuffer_Flushed ", io.flush ), 46244c9c1deSEaston Man ("IBuffer_hungry ", instrHungry ), 46305cc2a4eSXuan Hu ("IBuffer_1_4_valid", (numValid > (0*(IBufSize/4)).U) & (numValid < (1*(IBufSize/4)).U) ), 46405cc2a4eSXuan Hu ("IBuffer_2_4_valid", (numValid >= (1*(IBufSize/4)).U) & (numValid < (2*(IBufSize/4)).U) ), 46505cc2a4eSXuan Hu ("IBuffer_3_4_valid", (numValid >= (2*(IBufSize/4)).U) & (numValid < (3*(IBufSize/4)).U) ), 46605cc2a4eSXuan Hu ("IBuffer_4_4_valid", (numValid >= (3*(IBufSize/4)).U) & (numValid < (4*(IBufSize/4)).U) ), 46705cc2a4eSXuan Hu ("IBuffer_full ", numValid.andR ), 46844c9c1deSEaston Man ("Front_Bubble ", PopCount((0 until DecodeWidth).map(i => io.out(i).ready && !io.out(i).valid))) 46944c9c1deSEaston Man ) 47044c9c1deSEaston Man generatePerfEvent() 47144c9c1deSEaston Man} 472