xref: /XiangShan/src/main/scala/xiangshan/backend/datapath/RFWBConflictChecker.scala (revision bb2f3f51dd67f6e16e0cc1ffe43368c9fc7e4aef)
1package xiangshan.backend.datapath
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import utils.OptionWrapper
7import utils.SeqUtils.MixedVec2
8import xiangshan.backend.BackendParams
9import xiangshan.backend.datapath.DataConfig._
10import xiangshan.backend.datapath.WbConfig.{NoWB, PregWB}
11import xiangshan.backend.regfile.PregParams
12
13case class RFWBCollideCheckerParams (
14  inWbCfgs: Seq[Seq[Set[PregWB]]],
15  pregParams: PregParams,
16) {
17  def genInputBundle: MixedVec2[DecoupledIO[RFWBCollideCheckerBundle]] = {
18    val pregWidth = pregParams.addrWidth
19    utils.SeqUtils.mapToMixedVec2(this.filteredCfgs, (wb: PregWB) => DecoupledIO(new RFWBCollideCheckerBundle(wb, pregWidth)))
20  }
21
22  def filteredCfgs: Seq[Seq[PregWB]] = inWbCfgs.map(_.map(x =>
23    if (x.map(_.dataCfg).contains(pregParams.dataCfg))
24      x.find(x => x.dataCfg == pregParams.dataCfg).get
25    else
26      NoWB()
27  ))
28
29  def portMax = filteredCfgs.flatten.map(_.port).max
30}
31
32class RFWBCollideCheckerBundle(var wbCfg: Option[PregWB], pregWidth: Int) extends Bundle {
33
34  def this(wbCfg_ : PregWB, pregWidth_ : Int) = this(Some(wbCfg_), pregWidth_)
35
36  def this(pregWidth_ : Int) = this(None, pregWidth_)
37}
38
39class RFWBCollideCheckerIO(val params: RFWBCollideCheckerParams)(implicit p: Parameters) extends Bundle {
40  private val pregWidth = params.pregParams.addrWidth
41  val in: MixedVec2[DecoupledIO[RFWBCollideCheckerBundle]] = Flipped(params.genInputBundle)
42  val out = Vec(params.portMax + 1, Valid(new RFWBCollideCheckerBundle(pregWidth)))
43}
44
45private object ArbiterCtrl {
46  def apply(request: Seq[Bool]): Seq[Bool] = request.length match {
47    case 0 => Seq()
48    case 1 => Seq(true.B)
49    case _ => request.head +: request.tail.init.scanLeft(request.head)(_ || _).map(!_)
50  }
51}
52
53// when io.in.valid is false.B, io.in.ready is true.B
54class WBArbiter[T <: Data](val gen: T, val n: Int) extends Module {
55  val io = IO(new ArbiterIO(gen, n))
56
57  // These parameters are not carefully set, and may be improved in the future
58  private val CounterWidth = 3
59  private val CounterThreshold = 7
60
61  /* To avoid some weird deadlock caused by delay of og0Cancel */
62  // Use a saturation counter to record the number of consecutive failed requests for each input port
63  // When a counter reaches the threshold, mark it as full
64  // Port marked as full will be prioritized the next time it sends a request
65
66  val cancelCounter      = RegInit(VecInit(Seq.fill(n)(0.U(CounterWidth.W))))
67  val isFull             = RegInit(VecInit(Seq.fill(n)(false.B)))
68  val cancelCounterNext  = Wire(Vec(n, UInt(CounterWidth.W)))
69  val isFullNext         = Wire(Vec(n, Bool()))
70  val hasFull            = RegInit(false.B)
71  val hasFullReq         = Wire(Bool())
72  val finalValid         = Wire(Vec(n, Bool()))
73
74  cancelCounter := cancelCounterNext
75  isFull        := isFullNext
76  hasFull       := isFullNext.asUInt.orR
77  hasFullReq    := io.in.zip(isFull).map{case (in, full) => in.valid && full}.reduce(_ || _)
78
79  cancelCounterNext.zip(isFullNext).zip(cancelCounter).zip(isFull).zipWithIndex.foreach{ case ((((cntNext, fullNext), cnt), full), i) =>
80    when (io.in(i).valid && !io.in(i).ready) {
81      cntNext   := Mux(cnt === CounterThreshold.U, CounterThreshold.U, cnt + 1.U)
82      fullNext  := cnt(CounterWidth - 1, 1).andR  // counterNext === CounterThreshold.U
83    }.elsewhen (io.in(i).valid && io.in(i).ready) {
84      cntNext   := 0.U
85      fullNext  := false.B
86    }.otherwise {
87      cntNext   := cnt
88      fullNext  := full
89    }
90  }
91
92  finalValid := io.in.zipWithIndex.map{ case (in, i) => in.valid && (!hasFull || !hasFullReq || isFull(i)) }
93
94  io.chosen := (n - 1).asUInt
95  io.out.bits := io.in(n - 1).bits
96  for (i <- n - 2 to 0 by -1) {
97    when(finalValid(i)) {
98      io.chosen := i.asUInt
99      io.out.bits := io.in(i).bits
100    }
101  }
102
103  // in_valid    grant      ready
104  // 0           *          1
105  // 1           0          0
106  // 1           1          1
107  val grant = ArbiterCtrl(finalValid)
108  for (((in, g), v) <- io.in.zip(grant).zip(finalValid))
109    in.ready := (g && v || !in.valid) && io.out.ready
110  io.out.valid := !grant.last || finalValid.last
111}
112
113// used in WbDataPath
114class RealWBArbiter[T <: Data](val gen: T, val n: Int) extends Module {
115  val io = IO(new ArbiterIO(gen, n))
116
117  io.chosen := (n - 1).asUInt
118  io.out.bits := io.in(n - 1).bits
119  for (i <- n - 2 to 0 by -1) {
120    when(io.in(i).valid) {
121      io.chosen := i.asUInt
122      io.out.bits := io.in(i).bits
123    }
124  }
125
126  val grant = ArbiterCtrl(io.in.map(_.valid))
127  for ((in, g) <- io.in.zip(grant))
128    in.ready := (g || !in.valid) && io.out.ready
129  io.out.valid := !grant.last || io.in.last.valid
130}
131
132abstract class RFWBCollideCheckerBase(params: RFWBCollideCheckerParams)(implicit p: Parameters) extends Module {
133  protected def portRange: Range
134
135  val io = IO(new RFWBCollideCheckerIO(params))
136  dontTouch(io)
137
138  protected val pregParams = params.pregParams
139  protected val pregWidth = pregParams.addrWidth
140
141  protected val inGroup = io.in
142    .flatten
143    .groupBy(_.bits.wbCfg.get.port)
144    .map(x => (x._1, x._2.sortBy(_.bits.wbCfg.get.priority)))
145
146  protected val arbiters: Seq[Option[WBArbiter[RFWBCollideCheckerBundle]]] = portRange.map { portIdx =>
147    OptionWrapper(
148      inGroup.isDefinedAt(portIdx),
149      Module(new WBArbiter(
150        new RFWBCollideCheckerBundle(pregWidth),
151        inGroup(portIdx).size
152      ))
153    )
154  }
155
156  // connection of IntWB or VfWB
157  arbiters.zipWithIndex.foreach { case (arb, portIdx) =>
158    if (arb.nonEmpty) {
159      arb.get.io.in.zip(inGroup(portIdx)).foreach { case (arbiterIn, ioIn) =>
160        arbiterIn <> ioIn
161      }
162    }
163  }
164
165  // connection of NoWB
166  io.in.map(_.map(x =>
167    if (x.bits.wbCfg.get.isInstanceOf[NoWB]) {
168      x.ready := true.B
169    }
170  ))
171
172  io.out.zip(arbiters).foreach { case (out, arb) =>
173    if (arb.nonEmpty) {
174      val arbOut = arb.get.io.out
175      arbOut.ready := true.B
176      out.valid := arbOut.valid
177      out.bits := arbOut.bits
178    } else {
179      out := 0.U.asTypeOf(out)
180    }
181  }
182}
183
184class IntRFWBCollideChecker(
185  backendParams: BackendParams
186)(implicit
187  p:Parameters
188) extends RFWBCollideCheckerBase(RFWBCollideCheckerParams(backendParams.getAllWbCfgs, backendParams.intPregParams)) {
189  override protected def portRange: Range = 0 to backendParams.getWbPortIndices(IntData()).max
190}
191
192class FpRFWBCollideChecker(
193  backendParams: BackendParams
194)(implicit
195  p:Parameters
196) extends RFWBCollideCheckerBase(RFWBCollideCheckerParams(backendParams.getAllWbCfgs, backendParams.fpPregParams)) {
197  override protected def portRange: Range = 0 to backendParams.getWbPortIndices(FpData()).max
198}
199
200class VfRFWBCollideChecker(
201  backendParams: BackendParams
202)(implicit
203  p:Parameters
204) extends RFWBCollideCheckerBase(RFWBCollideCheckerParams(backendParams.getAllWbCfgs, backendParams.vfPregParams)) {
205  override protected def portRange: Range = 0 to backendParams.getWbPortIndices(VecData()).max
206}
207
208class V0RFWBCollideChecker(
209  backendParams: BackendParams
210)(implicit
211  p:Parameters
212) extends RFWBCollideCheckerBase(RFWBCollideCheckerParams(backendParams.getAllWbCfgs, backendParams.v0PregParams)) {
213  override protected def portRange: Range = 0 to backendParams.getWbPortIndices(V0Data()).max
214}
215
216class VlRFWBCollideChecker(
217  backendParams: BackendParams
218)(implicit
219  p:Parameters
220) extends RFWBCollideCheckerBase(RFWBCollideCheckerParams(backendParams.getAllWbCfgs, backendParams.vlPregParams)) {
221  override protected def portRange: Range = 0 to backendParams.getWbPortIndices(VlData()).max
222}
223