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