diff --git a/src/src/pipeline/dispatch/NewDispatchStage.scala b/src/src/pipeline/dispatch/NewDispatchStage.scala index 268bb286..20a58959 100644 --- a/src/src/pipeline/dispatch/NewDispatchStage.scala +++ b/src/src/pipeline/dispatch/NewDispatchStage.scala @@ -9,10 +9,8 @@ import pipeline.dispatch.bundles.ScoreboardChangeNdPort import pipeline.dispatch.enums.ScoreboardState import pipeline.rob.bundles.InstWbNdPort import pipeline.dispatch.bundles.ReservationStationBundle -import pipeline.dispatch.rs.InOrderReservationStation import control.enums.ExceptionPos -import pipeline.dispatch.rs.OutOfOrderReservationStation -import pipeline.dispatch.rs.SimpleOoOReservationStation +import pipeline.dispatch.rs._ import pmu.bundles.PmuDispatchBundle // class DispatchNdPort extends Bundle { @@ -61,7 +59,15 @@ class NewDispatchStage( val reservationStations = Seq.range(0, pipelineNum).map { idx => Module( if (Param.isOutOfOrderIssue && idx != Param.loadStoreIssuePipelineIndex) - new SimpleOoOReservationStation( + // new SimpleOoOReservationStation( + // Param.Width.Rob._channelLength, + // true + // ) + new OoOReservationStation( + Param.Width.Rob._channelLength, + 1, + 1, + 1, Param.Width.Rob._channelLength, true ) diff --git a/src/src/pipeline/dispatch/rs/BaseReservationStation.scala b/src/src/pipeline/dispatch/rs/BaseReservationStation.scala index e33f0251..121ab087 100644 --- a/src/src/pipeline/dispatch/rs/BaseReservationStation.scala +++ b/src/src/pipeline/dispatch/rs/BaseReservationStation.scala @@ -6,6 +6,7 @@ import pipeline.dispatch.bundles.ReservationStationBundle import pipeline.rob.bundles.InstWbNdPort import spec.Param import pmu.bundles.PmuDispatchBundle +import os.read abstract class BaseReservationStation( queueLength: Int, @@ -22,4 +23,5 @@ abstract class BaseReservationStation( val pmu_dispatchInfo = if (Param.usePmu) Some(Output(new PmuDispatchBundle)) else None }) + require(queueLength == channelNum * channelLength) } diff --git a/src/src/pipeline/dispatch/rs/OoOReservationStation.scala b/src/src/pipeline/dispatch/rs/OoOReservationStation.scala new file mode 100644 index 00000000..de0dcd6e --- /dev/null +++ b/src/src/pipeline/dispatch/rs/OoOReservationStation.scala @@ -0,0 +1,204 @@ +package pipeline.dispatch.rs + +import chisel3._ +import chisel3.util._ +import pipeline.common.DistributedQueuePlus +import pipeline.dispatch.bundles.ReservationStationBundle +import pipeline.rob.enums.RobDistributeSel +import spec.Param.isWritebackPassThroughWakeUp +import chisel3.experimental.Param +import spec._ +import utils._ + +class OoOReservationStation( + queueLength: Int, + enqMaxNum: Int, + deqMaxNum: Int, + channelNum: Int, + channelLength: Int, + supportCheckForIssue: Boolean = true) + extends BaseReservationStation( + queueLength, + enqMaxNum, + deqMaxNum, + channelNum, + channelLength + ) { + require(supportCheckForIssue == true) + + // Fallback + io.dequeuePorts.foreach(_ <> DontCare) + io.enqueuePorts.foreach(_.ready := false.B) + io.dequeuePorts.foreach(_.valid := false.B) + + require(queueLength > 1) + require(queueLength > 1) + require(isPow2(queueLength)) + + // TODO: delete + require(deqMaxNum == 1) + + val ramValids = RegInit(VecInit(Seq.fill(queueLength)(false.B))) + val ram = RegInit(VecInit(Seq.fill(queueLength)((ReservationStationBundle.default)))) + val ramFillRes = WireDefault(ram) + ram + .lazyZip(ramFillRes) + .foreach { + case (elem, set) => + set := elem + elem.robResult.readResults.zip(set.robResult.readResults).foreach { + case (readResult, setReadResult) => + if (spec.Param.isOptimizedByMultiMux) { + val mux = Module(new MultiMux1(spec.Param.pipelineNum, UInt(spec.Width.Reg.data), zeroWord)) + mux.io.inputs.zip(io.writebacks).foreach { + case (input, wb) => + input.valid := wb.en && readResult.result === wb.robId + input.bits := wb.data + } + when(readResult.sel === RobDistributeSel.robId && mux.io.output.valid) { + setReadResult.sel := RobDistributeSel.realData + setReadResult.result := mux.io.output.bits + } + } else { + + io.writebacks.foreach { wb => + when(readResult.sel === RobDistributeSel.robId && wb.en && readResult.result === wb.robId) { + setReadResult.sel := RobDistributeSel.realData + setReadResult.result := wb.data + } + } + } + } + } + + val enqEns = io.enqueuePorts.map { port => port.valid && port.ready } + val deqEns = io.dequeuePorts.map { port => port.valid && port.ready } + val ptr = RegInit(0.U(log2Ceil(queueLength + 1).W)) + val enqStartPtr = WireDefault(ptr -& deqEns.map(_.asUInt).reduce(_ +& _)) + val newPtr = WireDefault(ptr +& enqEns.map(_.asUInt).reduce(_ +& _) -& deqEns.map(_.asUInt).reduce(_ +& _)) + ptr := newPtr + ramValids.zipWithIndex.foreach { + case (valid, idx) => + valid := idx.U < newPtr + } + + val enqs = Wire(Vec(enqMaxNum, Flipped(Decoupled(new ReservationStationBundle)))) + enqs.zip(io.enqueuePorts).foreach { + case (enq, in) => + in.ready := enq.ready + enq.valid := in.valid + enq.bits := in.bits + in.bits.regReadPort.preExeInstInfo.gprReadPorts + .lazyZip(in.bits.robResult.readResults) + .lazyZip(enq.bits.robResult.readResults) + .foreach { + case (readPort, robReadResult, dst) => + io.writebacks.foreach { wb => + if (spec.Param.isOptimizedByMultiMux) { + val mux = Module(new MultiMux1(spec.Param.pipelineNum, UInt(spec.Width.Reg.data), zeroWord)) + mux.io.inputs.zip(io.writebacks).foreach { + case (input, wb) => + input.valid := wb.en && wb.robId === robReadResult.result + input.bits := wb.data + } + when(mux.io.output.valid && readPort.en && robReadResult.sel === RobDistributeSel.robId) { + dst.sel := RobDistributeSel.realData + dst.result := mux.io.output.bits + } + } else { + when( + wb.en && readPort.en && + robReadResult.sel === RobDistributeSel.robId && + wb.robId === robReadResult.result + ) { + dst.sel := RobDistributeSel.realData + dst.result := wb.data + } + } + } + } + } + + enqs.zipWithIndex.foreach { + case (enq, idx) => + enq.ready := ptr < (queueLength - idx).U + } + + val enableToDequeues = WireDefault(VecInit(Seq.fill(queueLength)(false.B))) + val enableToDequeueNum = enableToDequeues.map(_.asUInt).reduce(_ +& _) + enableToDequeues.lazyZip(ramFillRes).lazyZip(ramValids).zipWithIndex.foreach { + case ((en, elem, elemValid), idx) => + en := elemValid && elem.robResult.readResults.map(_.sel === RobDistributeSel.realData).reduce(_ && _) + if (idx != 0) { + when(elem.regReadPort.preExeInstInfo.forbidOutOfOrder) { + en := false.B + } + } + // 备选 ipc++ 但延迟++ + // when( + // elem.regReadPort.preExeInstInfo.forbidOutOfOrder && + // ramFillRes.take(idx).map(_.regReadPort.preExeInstInfo.forbidOutOfOrder).foldLeft(false.B)(_ || _) + // ) { + // en := false.B + // } + } + + io.dequeuePorts.zipWithIndex.foreach { + case (deq, idx) => + deq.valid := idx.U < enableToDequeueNum + } + + // assert deq num = 1 + val selectedIndices = Seq(PriorityEncoder(enableToDequeues)) + + io.dequeuePorts.zip(selectedIndices).foreach { + case (deq, selectedIndex) => + deq.bits := ramFillRes(selectedIndex) + } + + // compress & update + val ramOutFlags = WireDefault(VecInit(Seq.fill(queueLength)(false.B))) + selectedIndices.zipWithIndex.foreach { + case (selectIndex, idx) => + ramOutFlags(selectIndex) := deqEns(idx) + } + + val shiftNums = Wire(Vec(queueLength, UInt(log2Ceil(deqMaxNum + 1).W))) + shiftNums.zipWithIndex.foreach { + case (dst, idx) => + dst := ramOutFlags.take(idx).map(_.asUInt).foldLeft(0.U)(_ +& _) + } + + ramFillRes.zip(shiftNums).zipWithIndex.foreach { + case ((nextElem, shiftNum), idx) => + ram(idx.U -& shiftNum) := nextElem + } + + enqs.zip(enqEns).zipWithIndex.foreach { + case ((enq, en), idx) => + when(en) { // can delete ? + ram(enqStartPtr + idx.U) := enq.bits + } + } + + if (Param.usePmu) { + val pmu = io.pmu_dispatchInfo.get + val isFull = ptr === queueLength.U + val isEmpty = ptr === 0.U + pmu.enqueue := io.enqueuePorts.head.valid && io.enqueuePorts.head.ready && !io.isFlush + pmu.isFull := isFull && !io.isFlush + pmu.bubbleFromBackend := io.dequeuePorts.head.valid && !io.dequeuePorts.head.ready && !io.isFlush + pmu.bubbleFromRSEmpty := isEmpty && !io.isFlush + pmu.bubbleFromDataDependence := !pmu.bubbleFromRSEmpty && + !pmu.bubbleFromBackend && + !io.dequeuePorts.head.valid && + !isEmpty && + !io.isFlush + } + + when(io.isFlush) { + ramValids.foreach(_ := false.B) + ptr := 0.U + } + +} diff --git a/src/src/pipeline/dispatch/rs/OutOfOrderReservationStation.scala b/src/src/pipeline/dispatch/rs/OutOfOrderReservationStation.scala deleted file mode 100644 index dbfbc2b1..00000000 --- a/src/src/pipeline/dispatch/rs/OutOfOrderReservationStation.scala +++ /dev/null @@ -1,236 +0,0 @@ -package pipeline.dispatch.rs - -import chisel3._ -import chisel3.util._ -import pipeline.dispatch.bundles.ReservationStationBundle -import pipeline.rob.enums.RobDistributeSel -import utils.MultiCounter - -class OutOfOrderReservationStation( - queueLength: Int, - enqMaxNum: Int, - deqMaxNum: Int, - channelNum: Int, - channelLength: Int, - supportCheckForIssue: Boolean = true) - extends BaseReservationStation( - queueLength, - enqMaxNum, - deqMaxNum, - channelNum, - channelLength - ) { - - require(supportCheckForIssue == true) - -// Fallback - io.dequeuePorts.foreach(_ <> DontCare) - io.enqueuePorts.foreach(_.ready := false.B) - io.dequeuePorts.foreach(_.valid := false.B) - - require(queueLength > enqMaxNum) - require(queueLength > deqMaxNum) - require(isPow2(queueLength)) - - val ram = RegInit(VecInit(Seq.fill(queueLength)(0.U.asTypeOf(Valid(new ReservationStationBundle))))) - - val enq_ptr = Module(new MultiCounter(queueLength, enqMaxNum)) - val deq_ptr = Module(new MultiCounter(queueLength, deqMaxNum)) - - enq_ptr.io.inc := 0.U - enq_ptr.io.flush := io.isFlush - deq_ptr.io.inc := 0.U - deq_ptr.io.flush := io.isFlush - - val maybeFull = RegInit(false.B) - val ptrMatch = enq_ptr.io.value === deq_ptr.io.value - val isEmpty = WireDefault(ptrMatch && !maybeFull) - val isFull = WireDefault(ptrMatch && maybeFull) - - val storeNum = WireDefault( - Mux( - enq_ptr.io.value === deq_ptr.io.value, - Mux(isEmpty, 0.U, queueLength.U), - Mux( - enq_ptr.io.value > deq_ptr.io.value, - enq_ptr.io.value - deq_ptr.io.value, - (queueLength.U -& deq_ptr.io.value) +& enq_ptr.io.value - ) - ) - ) - val emptyNum = WireDefault(queueLength.U - storeNum) - - val isEmptyBy = WireDefault(VecInit(Seq.range(0, deqMaxNum).map(_.U === storeNum))) - val isFullBy = WireDefault(VecInit(Seq.range(0, enqMaxNum).map(_.U === emptyNum))) - - io.enqueuePorts.zipWithIndex.foreach { - case (enq, idx) => - enq.ready := !isFullBy.take(idx + 1).reduce(_ || _) - } - - val enqEn = io.enqueuePorts.map(port => (port.ready && port.valid)) - val enqueueNum = enqEn.map(_.asUInt).reduce(_ +& _) - - val deqEn = io.dequeuePorts.map(port => (port.ready && port.valid)) - val dequeueNum = deqEn.map(_.asUInt).reduce(_ +& _) - - enq_ptr.io.inc := enqueueNum - deq_ptr.io.inc := dequeueNum - - when(enqueueNum > dequeueNum) { - maybeFull := true.B - }.elsewhen(enqueueNum < dequeueNum) { - maybeFull := false.B - } - - // dequeue - // invalidate which are dequeue - deqEn.zipWithIndex.foreach { - case (en, idx) => - when(en) { - ram(deq_ptr.io.incResults(idx)).valid := false.B - } - } - - // select which can issue - val ramDownView = WireDefault(VecInit(Seq.range(0, queueLength).map { idx => - ram(deq_ptr.io.incResults(idx)) - })) - - val ramDownViewEnableDeq = Wire(Vec(queueLength, Bool())) - - ramDownViewEnableDeq.lazyZip(ramDownView).zipWithIndex.foreach { - case ((en, elem), idx) => - en := elem.valid && elem.bits.robResult.readResults.forall( - _.sel === RobDistributeSel.realData - ) - when( - // elem.bits.regReadPort.preExeInstInfo.needCsr || - // VecInit(ExeInst.Sel.jumpBranch, ExeInst.Sel.loadStore) - // .contains(elem.bits.regReadPort.preExeInstInfo.exeSel - elem.bits.regReadPort.preExeInstInfo.forbidOutOfOrder - ) { - if (idx >= deqMaxNum) { - en := false.B - } else { - when(!ramDownViewEnableDeq.take(idx).foldLeft(true.B)(_ && _)) { - en := false.B - } - } - } - } - - // select dequeue num of elem to issue - val selectedDownViewIndices = Wire(Vec(deqMaxNum, UInt(log2Ceil(queueLength).W))) - - selectedDownViewIndices.zipWithIndex.foreach { - case (selectIndex, idx) => - val preSelect = selectedDownViewIndices.take(idx) - val enables = - ramDownViewEnableDeq.zipWithIndex.map { - case (en, en_idx) => - en && preSelect.map(_ =/= en_idx.U).foldLeft(true.B)(_ && _) - } - selectIndex := PriorityEncoder(enables) - } - - io.dequeuePorts.lazyZip(selectedDownViewIndices).foreach { - case (out, selectIndex) => - out.valid := ramDownViewEnableDeq(selectIndex) - out.bits := ram(deq_ptr.io.incResults(selectIndex)).bits - } - - // compress - // deq_ptr - out1 - out2 - enq_ptr - // for those between out1 and out2, idx += 1 - // for those between deq_ptr and out1 idx += 2 if deqNum >= 2 - val compressFlows = WireDefault( - 0.U.asTypeOf(Vec(deqMaxNum, Vec(queueLength, Valid(new ReservationStationBundle)))) - ) - selectedDownViewIndices.lazyZip(deqEn).zipWithIndex.foreach { - case ((outIndex, en), offsetTimes) => - val src: Vec[Valid[ReservationStationBundle]] = - if (offsetTimes == 0) { - ramDownView - } else { - compressFlows(offsetTimes - 1) - } - when(en) { - src.zipWithIndex.foreach { - case (elem, src_idx) => - when(src_idx.U === outIndex) { - // pass - }.elsewhen(src_idx.U < outIndex) { - // up one - if (src_idx != queueLength - 1) { - compressFlows(offsetTimes)(src_idx + 1) := elem - } - }.otherwise { - // keep position - compressFlows(offsetTimes)(src_idx) := elem - } - } - }.otherwise { - src.zipWithIndex.foreach { - case (elem, src_idx) => - // keep position - compressFlows(offsetTimes)(src_idx) := elem - } - } - } - - // write - compressFlows(deqMaxNum - 1).zipWithIndex.foreach { - case (src, idx) => - ram(deq_ptr.io.incResults(idx)) := src - - io.writebacks.foreach { wb => - src.bits.regReadPort.preExeInstInfo.gprReadPorts - .lazyZip(src.bits.robResult.readResults) - .lazyZip(ram(deq_ptr.io.incResults(idx)).bits.robResult.readResults) - .foreach { - case (readPort, robReadResult, dst) => - when( - wb.en && readPort.en && - robReadResult.sel === RobDistributeSel.robId && - wb.robId === robReadResult.result - ) { - dst.sel := RobDistributeSel.realData - dst.result := wb.data - } - } - } - } - - // enqueue - io.enqueuePorts.lazyZip(enqEn).zipWithIndex.foreach { - case ((in, en), idx) => - when(en) { - ram(enq_ptr.io.incResults(idx)).bits := in.bits - ram(enq_ptr.io.incResults(idx)).valid := true.B - - io.writebacks.foreach { wb => - in.bits.regReadPort.preExeInstInfo.gprReadPorts - .lazyZip(in.bits.robResult.readResults) - .lazyZip(ram(enq_ptr.io.incResults(idx)).bits.robResult.readResults) - .foreach { - case (readPort, robReadResult, dst) => - when( - wb.en && readPort.en && - robReadResult.sel === RobDistributeSel.robId && - wb.robId === robReadResult.result - ) { - dst.sel := RobDistributeSel.realData - dst.result := wb.data - } - } - } - } - } - - when(io.isFlush) { - ram.foreach(_.valid := false.B) - maybeFull := false.B - } - -} diff --git a/src/src/utils/MultiCounter.scala b/src/src/utils/MultiCounter.scala index 229edc4f..5b454bdb 100644 --- a/src/src/utils/MultiCounter.scala +++ b/src/src/utils/MultiCounter.scala @@ -4,10 +4,11 @@ import chisel3._ import chisel3.util._ class MultiCounter( - maxCount: Int, - maxIncNum: Int, - init: Int = 0, - supportSet: Boolean = false) + maxCount: Int, + maxIncNum: Int, + init: Int = 0, + supportSet: Boolean = false, + needRecurrent: Boolean = true) extends Module { require(maxCount >= maxIncNum) val value_w = log2Ceil(maxCount) @@ -37,7 +38,7 @@ class MultiCounter( incResults.zipWithIndex.foreach { case (incResult, inc) => - if (isMaxCountPow2) { + if (isMaxCountPow2 || !needRecurrent) { incResult := counter + inc.U } else { val rawAdd = Wire(UInt((value_w + 1).W))