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