@@ -69,7 +69,7 @@ class ReservationStation(implicit p: Parameters) extends CoreModule()(p) {
6969 def collFiredTable (row : Int ): Vec [Bool ] = collFiredTable(row.U )
7070 // where the operand lives in the collector banks
7171 val collPtrTable = Mem (numEntries, Vec (Isa .maxNumRegs, UInt (collEntryWidth.W )))
72- val collPriorityTable = Wire (Vec (numEntries, Bool ()))
72+ val collAllReadyTable = Wire (Vec (numEntries, Bool ()))
7373
7474 (0 until numEntries).map { i =>
7575 val uop = instTable(i).uop
@@ -119,55 +119,69 @@ class ReservationStation(implicit p: Parameters) extends CoreModule()(p) {
119119 .map { case (r, (b, cf)) => ! r && ! b && ! cf})
120120 val needCollect = valid && needCollectOps.reduce(_ || _)
121121 // is this uop RAW-cleared and only waiting for collection?
122- val priority = needCollect && (needCollectOps === VecInit (opReadys.map(! _)))
123- (needCollect, needCollectOps, priority )
122+ val needCollectAllReady = needCollect && (needCollectOps === VecInit (opReadys.map(! _)))
123+ (needCollect, needCollectOps, needCollectAllReady )
124124 }
125125 // select a single entry for collection
126126 // TODO: @perf: currently a simple priority encoder; might introduce fairness
127127 // problem
128128 val collBitvec = WireDefault (VecInit (needCollects.map(_._1)))
129- collPriorityTable := VecInit (needCollects.map(_._3))
129+ collAllReadyTable := VecInit (needCollects.map(_._3))
130130 dontTouch(collBitvec)
131- dontTouch(collPriorityTable)
132-
133- // Prioritize rows that has no RAW-busy ops, and only needs collection as the
134- // last step before issue. Otherwise, rows with partial ops can take up
135- // valuable space in the collector banks.
131+ dontTouch(collAllReadyTable)
132+
133+ // don't allow early-firing collector requests for partial operands of an
134+ // instruction. Partial collects may result in a deadlock with insufficient
135+ // collector entries where the younger instruction requesting a partial
136+ // collect blocks collection of an older instruction, but has RAW hazard to
137+ // that older instruction.
138+ val allowPartialCollect = false
139+ // If allowPartialCollect == true, prioritize rows that has no RAW-busy ops
140+ // (no partial-collects), and only needs collection as the last step before
141+ // issue. Otherwise, rows with partial ops can take up valuable space in the
142+ // collector banks.
136143 //
137- // NOTE: It's debatable whether this logic should be in the collector or not.
138- // But for that, we need some kind of bookkeeping in the collector for the
144+ // NOTE: Arguably all of this should be in the collector module. But for
145+ // that, we need some kind of bookkeeping in the collector for the
139146 // partial-collect uops, which is what the collector banks are meant for,
140147 // which are expensive.
141- val anyPriority = collPriorityTable .reduce(_ || _)
142- val firstPriorityRow = PriorityEncoder (collPriorityTable )
148+ val allReadyExists = collAllReadyTable .reduce(_ || _)
149+ val firstAllReadyRow = PriorityEncoder (collAllReadyTable )
143150 val firstNeedRow = PriorityEncoder (collBitvec)
144- val collRow = Mux (anyPriority, firstPriorityRow, firstNeedRow)
151+ val collRow = Mux (! allowPartialCollect.B || allReadyExists,
152+ firstAllReadyRow, firstNeedRow)
145153 dontTouch(collRow)
146154
147155 val collOpNeed = VecInit (needCollects.map(_._2))(collRow)
156+ val collValid = (if (allowPartialCollect) {
157+ allReadyExists
158+ } else {
159+ collOpNeed.reduce(_ || _)
160+ })
148161 val collUop = instTable(collRow).uop
149162 val collPC = WireDefault (collUop.pc)
150163 dontTouch(collPC)
151164 val collRegs = Seq (collUop.inst.rs1, collUop.inst.rs2, collUop.inst.rs3)
152165
153- // this is clunky, but Mem does not support partial-field updates
154- val newCollPtr = WireDefault (collPtrTable(collRow))
155166 assert(collOpNeed.length == io.collector.readReq.bits.regs.length)
156167 assert(collRegs.length == io.collector.readReq.bits.regs.length)
168+
169+ io.collector.readReq.valid := collValid
170+ // this is clunky, but Mem does not support partial-field updates
171+ val newCollPtr = WireDefault (collPtrTable(collRow))
157172 (collOpNeed lazyZip collRegs lazyZip io.collector.readReq.bits.regs)
158173 .zipWithIndex.foreach { case ((need, pReg, collPort), rsi) =>
159174 assert(collPort.data.isEmpty)
160- collPort.enable := need
175+ collPort.enable := collValid && need
161176 collPort.pReg := Mux (need, pReg, 0 .U )
162177 // TODO: currently assumes DuplicatedCollector with only 1 entry
163178 newCollPtr(rsi) := 0 .U
164179 }
165180 io.collector.readReq.bits.rsEntryId := collRow
166- io.collector.readReq.valid := io.collector.readReq.bits.anyEnabled()
167181 when (io.collector.readReq.fire) {
168- val fired = (collFiredTable(collRow) zip io.collector.readReq.bits.regs.map(_.enable))
182+ val newFired = (collFiredTable(collRow) zip io.collector.readReq.bits.regs.map(_.enable))
169183 .map { case (a,b) => a || b }
170- collFiredTable(collRow) := fired
184+ collFiredTable(collRow) := newFired
171185 collPtrTable(collRow) := newCollPtr
172186
173187 printf(cf " RS: collector request fired at row: ${collRow}, pc: ${collUop.pc}%x \n " )
@@ -271,25 +285,30 @@ class ReservationStation(implicit p: Parameters) extends CoreModule()(p) {
271285 (issueScheduler.io.in zip eligibles).foreach { case (s, e) => s <> e }
272286 val issueScheduled = issueScheduler.io.out
273287
274- // drive the operands port upon issue via collector's combinational readData
288+ // drive collector's operand serve port upon issue, for use in EX
275289 val issuedId = WireDefault (issueScheduler.io.out.bits.entryId)
276- io.collector.readData.regs.zipWithIndex.foreach { case (port, rsi) =>
277- port.enable := issueScheduled.fire && hasOpTable(issuedId)(rsi)
278- port.collEntry := collPtrTable(issuedId)(rsi)
279- port.pReg match {
280- // for no-collector config, collEntry pointer is not used; use pRegs to
281- // actually drive SRAMs
282- case Some (pReg) => pReg := rsTable(issuedId)(rsi)
283- case None => assert(useCollector,
284- " collector data port has unnecessary pReg field instantiated when useCollector == true" )
285- }
286- // port.data input is not used
287- }
290+ io.collector.readData.req.valid := issueScheduled.valid
291+ io.collector.readData.req.bits.collEntry := 0 .U // fixed for DuplicatedCollector
292+ io.collector.readData.resp.ready := issueScheduled.fire
293+ assert(useCollector, " FIXME: !useCollector is broken currently" )
294+ // io.collector.readData.req.bits.zipWithIndex.foreach { case (port, rsi) =>
295+ // port.enable := issueScheduled.fire && hasOpTable(issuedId)(rsi)
296+ // port.pReg match {
297+ // // for no-collector config, collEntry pointer is not used; use pRegs to
298+ // // actually drive SRAMs
299+ // // FIXME: remove
300+ // case Some(pReg) => pReg := rsTable(issuedId)(rsi)
301+ // case None => assert(useCollector,
302+ // "collector data port has unnecessary pReg field instantiated when useCollector == true")
303+ // }
304+ // // port.data input is not used
305+ // }
288306 dontTouch(issuedId)
289307
290308 // if not using collector, RS only directly uses the readData port and never
291309 // sends readReq / gets readResp back, so we need to signal scoreboard
292310 // explicitly at issue time
311+ // FIXME: Hacky; handle this altogether in Collector
293312 if (! useCollector) {
294313 io.scb.updateColl.enable := issueScheduled.fire
295314 io.scb.updateColl.reads.foreach(_ := 0 .U .asTypeOf(new ScoreboardRegUpdate ))
@@ -309,8 +328,8 @@ class ReservationStation(implicit p: Parameters) extends CoreModule()(p) {
309328 // implication due to sequential reads unlike collector buffers with
310329 // combinational reads. In that case, we need to align the issue timing with
311330 // the SRAM round-trip.
312- val collectorSequentialRead = ! useCollector
313- if (collectorSequentialRead ) {
331+ val operandOneCycleLate = ! useCollector
332+ if (operandOneCycleLate ) {
314333 val queue = Module (
315334 new Queue (gen = chiselTypeOf(io.issue.bits), entries = 1 , pipe = true )
316335 )
@@ -404,7 +423,7 @@ class ReservationStation(implicit p: Parameters) extends CoreModule()(p) {
404423 cf " hasOp: ${hasOpTable(i)(0 )}${hasOpTable(i)(1 )}${hasOpTable(i)(2 )} | " +
405424 cf " opReady: ${opReadyTable(i)(0 )}${opReadyTable(i)(1 )}${opReadyTable(i)(2 )} | " +
406425 cf " busy: ${busyTable(i)(0 )}${busyTable(i)(1 )}${busyTable(i)(2 )} | " +
407- cf " collPriority: ${collPriorityTable (i)} | " +
426+ cf " collPriority: ${collAllReadyTable (i)} | " +
408427 cf " collFired: ${collFiredTable(i)(0 )}${collFiredTable(i)(1 )}${collFiredTable(i)(2 )}" +
409428 cf " \n " )
410429 }
0 commit comments