xref: /XiangShan/src/main/scala/xiangshan/backend/datapath/WbArbiter.scala (revision a8db15d829fbeffc63c1e3101725a2131cedc087)
1package xiangshan.backend.datapath
2
3import chipsalliance.rocketchip.config.Parameters
4import chisel3._
5import chisel3.util._
6import difftest.{DifftestFpWriteback, DifftestIntWriteback}
7import xiangshan.backend.BackendParams
8import xiangshan.backend.Bundles.{ExuOutput, WriteBackBundle}
9import xiangshan.backend.regfile.RfWritePortWithConfig
10import xiangshan.{Redirect, XSBundle, XSModule}
11
12class WbArbiterIO()(implicit p: Parameters, params: WbArbiterParams) extends XSBundle {
13  val flush = Flipped(ValidIO(new Redirect))
14  val in: MixedVec[DecoupledIO[WriteBackBundle]] = Flipped(params.genInput)
15  val out: MixedVec[ValidIO[WriteBackBundle]] = params.genOutput
16
17  def inGroup: Map[Int, IndexedSeq[DecoupledIO[WriteBackBundle]]] = in.groupBy(_.bits.params.port)
18}
19
20class WbArbiter(params: WbArbiterParams)(implicit p: Parameters) extends XSModule {
21  val io = IO(new WbArbiterIO()(p, params))
22  // Todo: Sorted by priority
23  private val inGroup: Map[Int, IndexedSeq[DecoupledIO[WriteBackBundle]]] = io.inGroup
24
25  private val arbiters: Seq[Option[Arbiter[WriteBackBundle]]] = Seq.tabulate(params.numOut) { x => {
26    if (inGroup.contains(x)) {
27      Some(Module(new Arbiter(new WriteBackBundle(inGroup.values.head.head.bits.params), inGroup(x).length)))
28    } else {
29      None
30    }
31  }}
32
33  arbiters.zipWithIndex.foreach { case (arb, i) =>
34    if (arb.nonEmpty) {
35      arb.get.io.in.zip(inGroup(i)).foreach { case (arbIn, wbIn) =>
36        arbIn <> wbIn
37      }
38    }
39  }
40
41  io.out.zip(arbiters).foreach { case (wbOut, arb) =>
42    if (arb.nonEmpty) {
43      val arbOut = arb.get.io.out
44      arbOut.ready := true.B
45      wbOut.valid := arbOut.valid
46      wbOut.bits := arbOut.bits
47    } else {
48      wbOut := 0.U.asTypeOf(wbOut)
49    }
50  }
51
52  def getInOutMap: Map[Int, Int] = {
53    (params.wbCfgs.indices zip params.wbCfgs.map(_.port)).toMap
54  }
55}
56
57class WbDataPathIO()(implicit p: Parameters, params: BackendParams) extends XSBundle {
58  val flush = Flipped(ValidIO(new Redirect()))
59
60  val fromTop = new Bundle {
61    val hartId = Input(UInt(8.W))
62  }
63
64  val fromIntExu: MixedVec[MixedVec[DecoupledIO[ExuOutput]]] = Flipped(params.intSchdParams.get.genExuOutputDecoupledBundle)
65
66  val fromVfExu: MixedVec[MixedVec[DecoupledIO[ExuOutput]]] = Flipped(params.vfSchdParams.get.genExuOutputDecoupledBundle)
67
68  val fromMemExu: MixedVec[MixedVec[DecoupledIO[ExuOutput]]] = Flipped(params.memSchdParams.get.genExuOutputDecoupledBundle)
69
70  val toIntPreg = Flipped(MixedVec(Vec(params.intPregParams.numWrite,
71    new RfWritePortWithConfig(params.intPregParams.dataCfg, params.intPregParams.addrWidth))))
72
73  val toVfPreg = Flipped(MixedVec(Vec(params.vfPregParams.numWrite,
74    new RfWritePortWithConfig(params.vfPregParams.dataCfg, params.vfPregParams.addrWidth))))
75
76  val toCtrlBlock = new Bundle {
77    val writeback: MixedVec[ValidIO[ExuOutput]] = params.genWrite2CtrlBundles
78  }
79}
80
81class WbDataPath(params: BackendParams)(implicit p: Parameters) extends XSModule {
82  val io = IO(new WbDataPathIO()(p, params))
83
84  // alias
85  val intArbiterInputs = (io.fromIntExu ++ io.fromVfExu ++ io.fromMemExu).flatten.filter(_.bits.params.writeIntRf)
86  val vfArbiterInputs = (io.fromIntExu ++ io.fromVfExu ++ io.fromMemExu).flatten.filter(_.bits.params.writeVfRf)
87  println(s"[WbDataPath] write int preg: " +
88    s"IntExu(${io.fromIntExu.flatten.count(_.bits.params.writeIntRf)}) " +
89    s"VfExu(${io.fromVfExu.flatten.count(_.bits.params.writeIntRf)}) " +
90    s"MemExu(${io.fromMemExu.flatten.count(_.bits.params.writeIntRf)})"
91  )
92  println(s"[WbDataPath] write vf preg: " +
93    s"IntExu(${io.fromIntExu.flatten.count(_.bits.params.writeVfRf)}) " +
94    s"VfExu(${io.fromVfExu.flatten.count(_.bits.params.writeVfRf)}) " +
95    s"MemExu(${io.fromMemExu.flatten.count(_.bits.params.writeVfRf)})"
96  )
97
98  // modules
99  private val intWbArbiter = Module(new WbArbiter(params.getIntWbArbiterParams))
100  private val vfWbArbiter = Module(new WbArbiter(params.getVfWbArbiterParams))
101  println(s"[WbDataPath] int preg write back port num: ${intWbArbiter.io.out.size}, active port: ${intWbArbiter.io.inGroup.keys.toSeq.sorted}")
102  println(s"[WbDataPath] vf preg write back port num: ${vfWbArbiter.io.out.size}, active port: ${vfWbArbiter.io.inGroup.keys.toSeq.sorted}")
103
104  // module assign
105  intWbArbiter.io.flush <> io.flush
106  require(intWbArbiter.io.in.size == intArbiterInputs.size, s"intWbArbiter input size: ${intWbArbiter.io.in.size}, all vf wb size: ${intArbiterInputs.size}")
107  intWbArbiter.io.in.zip(intArbiterInputs).foreach { case (arbiterIn, in) =>
108    arbiterIn.valid := in.valid && in.bits.intWen.get
109    in.ready := arbiterIn.ready
110    arbiterIn.bits.fromExuOutput(in.bits)
111  }
112  private val intWbArbiterOut = intWbArbiter.io.out
113
114  vfWbArbiter.io.flush <> io.flush
115  require(vfWbArbiter.io.in.size == vfArbiterInputs.size, s"vfWbArbiter input size: ${vfWbArbiter.io.in.size}, all vf wb size: ${vfArbiterInputs.size}")
116  vfWbArbiter.io.in.zip(vfArbiterInputs).foreach { case (arbiterIn, in) =>
117    arbiterIn.valid := in.valid && (in.bits.fpWen.getOrElse(false.B) || in.bits.vecWen.getOrElse(false.B))
118    in.ready := arbiterIn.ready
119    arbiterIn.bits.fromExuOutput(in.bits)
120  }
121
122  private val vfWbArbiterOut = vfWbArbiter.io.out
123
124  private val intExuInputs = io.fromIntExu.flatten
125  private val intExuWBs = WireInit(MixedVecInit(io.fromIntExu.flatten))
126  private val vfExuInputs = io.fromVfExu.flatten
127  private val vfExuWBs = WireInit(MixedVecInit(io.fromVfExu.flatten))
128  private val memExuInputs = io.fromMemExu.flatten
129  private val memExuWBs = WireInit(MixedVecInit(io.fromMemExu.flatten))
130
131  // only fired port can write back to ctrl block
132  (intExuWBs zip intExuInputs).foreach { case (wb, input) => wb.valid := input.fire }
133  (vfExuWBs zip vfExuInputs).foreach { case (wb, input) => wb.valid := input.fire }
134  (memExuWBs zip memExuInputs).foreach { case (wb, input) => wb.valid := input.fire }
135
136  // the ports not writting back pregs are always ready
137  (intExuInputs ++ vfExuInputs ++ memExuInputs).foreach( x =>
138    if (x.bits.params.hasNoDataWB) x.ready := true.B
139  )
140
141  // io assign
142  private val toIntPreg: MixedVec[RfWritePortWithConfig] = MixedVecInit(intWbArbiterOut.map(x => x.bits.asIntRfWriteBundle(x.fire)))
143  private val toVfPreg: MixedVec[RfWritePortWithConfig] = MixedVecInit(vfWbArbiterOut.map(x => x.bits.asVfRfWriteBundle(x.fire)))
144
145  private val wb2Ctrl = intExuWBs ++ vfExuWBs ++ memExuWBs
146
147  io.toIntPreg := toIntPreg
148  io.toVfPreg := toVfPreg
149  io.toCtrlBlock.writeback.zip(wb2Ctrl).foreach { case (sink, source) =>
150    sink.valid := source.valid
151    sink.bits := source.bits
152    source.ready := true.B
153  }
154
155  if (env.EnableDifftest || env.AlwaysBasicDiff) {
156    intWbArbiterOut.foreach(out => {
157      val difftest = Module(new DifftestIntWriteback)
158      difftest.io.clock := clock
159      difftest.io.coreid := io.fromTop.hartId
160      difftest.io.valid := out.fire && out.bits.rfWen
161      difftest.io.dest := out.bits.pdest
162      difftest.io.data := out.bits.data
163    })
164  }
165
166  if (env.EnableDifftest || env.AlwaysBasicDiff) {
167    vfWbArbiterOut.foreach(out => {
168      val difftest = Module(new DifftestFpWriteback)
169      difftest.io.clock := clock
170      difftest.io.coreid := io.fromTop.hartId
171      difftest.io.valid := out.fire // all fp instr will write fp rf
172      difftest.io.dest := out.bits.pdest
173      difftest.io.data := out.bits.data
174    })
175  }
176
177}
178
179
180
181
182