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 ---