xref: /XiangShan/src/main/scala/xiangshan/backend/exu/ExeUnit.scala (revision 92b88f30156d46e844042eea94f7121557fd09a1)
1package xiangshan.backend.exu
2
3import chipsalliance.rocketchip.config.Parameters
4import chisel3._
5import chisel3.util._
6import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
7import utility.DelayN
8import utils._
9import xiangshan.backend.fu.{CSRFileIO, FenceIO, FuncUnitInput}
10import xiangshan.backend.Bundles.{ExuInput, ExuOutput, MemExuInput, MemExuOutput}
11import xiangshan.{HasXSParameter, Redirect, XSBundle, XSModule}
12
13class ExeUnitIO(params: ExeUnitParams)(implicit p: Parameters) extends XSBundle {
14  val flush = Flipped(ValidIO(new Redirect()))
15  val in = Flipped(DecoupledIO(new ExuInput(params)))
16  val out = DecoupledIO(new ExuOutput(params))
17  val csrio = if (params.hasCSR) Some(new CSRFileIO) else None
18  val fenceio = if (params.hasFence) Some(new FenceIO) else None
19  val frm = if (params.needSrcFrm) Some(Input(UInt(3.W))) else None
20}
21
22class ExeUnit(exuParams: ExeUnitParams)(implicit p: Parameters) extends LazyModule {
23  lazy val module = new ExeUnitImp(this)(p, exuParams)
24}
25
26class ExeUnitImp(
27  override val wrapper: ExeUnit
28)(implicit
29  p: Parameters, exuParams: ExeUnitParams
30) extends LazyModuleImp(wrapper) with HasXSParameter{
31  private val fuCfgs = exuParams.fuConfigs
32
33  val io = IO(new ExeUnitIO(exuParams))
34
35  val funcUnits = fuCfgs.map(cfg => {
36    assert(cfg.fuGen != null, cfg.name + "Cfg'fuGen is null !!!")
37    val module = cfg.fuGen(p, cfg)
38    module
39  })
40
41  val busy = RegInit(false.B)
42  val robIdx = RegEnable(io.in.bits.robIdx, io.in.fire)
43  when (io.in.fire && io.in.bits.robIdx.needFlush(io.flush)) {
44    busy := false.B
45  }.elsewhen(busy && robIdx.needFlush(io.flush)){
46    busy := false.B
47  }.elsewhen(io.out.fire) {
48    busy := false.B
49  }.elsewhen(io.in.fire) {
50    busy := true.B
51  }
52  val intWbPort = exuParams.getIntWBPort
53  val intFlag = if(intWbPort.isDefined) backendParams.allExuParams.map(exuParam => (exuParam.getIntWBPort, exuParam.latencyCertain))
54    .filter(_._1.isDefined)
55    .filter(_._1.get.port == intWbPort.get.port)
56    .map(_._2)
57    .reduce(_ | _)
58  else true
59
60  val vfWbPort = exuParams.getVfWBPort
61  val vfFlag = if (vfWbPort.isDefined) backendParams.allExuParams.map(exuParam => (exuParam.getVfWBPort, exuParam.latencyCertain))
62    .filter(_._1.isDefined)
63    .filter(_._1.get.port == vfWbPort.get.port)
64    .map(_._2)
65    .reduce(_ | _)
66  else true
67
68  if(intFlag && vfFlag){
69    busy := false.B
70  }
71  dontTouch(io.out.ready)
72  // rob flush --> funcUnits
73  funcUnits.zipWithIndex.foreach { case (fu, i) =>
74    fu.io.flush <> io.flush
75  }
76
77  def acceptCond(input: ExuInput): Seq[Bool] = {
78    input.params.fuConfigs.map(_.fuSel(input))
79  }
80
81  val in1ToN = Module(new Dispatcher(new ExuInput(exuParams), funcUnits.length, acceptCond))
82
83  // ExeUnit.in <---> Dispatcher.in
84  in1ToN.io.in.valid := io.in.valid && !busy
85  in1ToN.io.in.bits := io.in.bits
86  io.in.ready := !busy && in1ToN.io.in.ready
87
88  // Dispatcher.out <---> FunctionUnits
89  in1ToN.io.out.zip(funcUnits.map(_.io.in)).foreach {
90    case (source: DecoupledIO[ExuInput], sink: DecoupledIO[FuncUnitInput]) =>
91      sink.valid := source.valid
92      source.ready := sink.ready
93
94      sink.bits.data.src.zip(source.bits.src).foreach { case(fuSrc, exuSrc) => fuSrc := exuSrc }
95      sink.bits.data.pc          .foreach(x => x := source.bits.pc.get)
96      sink.bits.data.imm         := source.bits.imm
97      sink.bits.ctrl.fuOpType    := source.bits.fuOpType
98      sink.bits.ctrl.robIdx      := source.bits.robIdx
99      sink.bits.ctrl.pdest       := source.bits.pdest
100      sink.bits.ctrl.rfWen       .foreach(x => x := source.bits.rfWen.get)
101      sink.bits.ctrl.fpWen       .foreach(x => x := source.bits.fpWen.get)
102      sink.bits.ctrl.vecWen      .foreach(x => x := source.bits.vecWen.get)
103      sink.bits.ctrl.flushPipe   .foreach(x => x := source.bits.flushPipe.get)
104      sink.bits.ctrl.preDecode   .foreach(x => x := source.bits.preDecode.get)
105      sink.bits.ctrl.ftqIdx      .foreach(x => x := source.bits.ftqIdx.get)
106      sink.bits.ctrl.ftqOffset   .foreach(x => x := source.bits.ftqOffset.get)
107      sink.bits.ctrl.predictInfo .foreach(x => x := source.bits.predictInfo.get)
108      sink.bits.ctrl.fpu         .foreach(x => x := source.bits.fpu.get)
109      sink.bits.ctrl.vpu         .foreach(x => x := source.bits.vpu.get)
110  }
111
112  private val fuOutValidOH = funcUnits.map(_.io.out.valid)
113  XSError(PopCount(fuOutValidOH) > 1.U, p"fuOutValidOH ${Binary(VecInit(fuOutValidOH).asUInt)} should be one-hot)\n")
114  private val fuOutBitsVec = funcUnits.map(_.io.out.bits)
115  private val fuRedirectVec: Seq[Option[ValidIO[Redirect]]] = funcUnits.map(_.io.out.bits.res.redirect)
116
117  // Assume that one fu can only write int or fp or vec,
118  // otherwise, wenVec should be assigned to wen in fu.
119  private val fuIntWenVec = funcUnits.map(x => x.cfg.writeIntRf.B && x.io.out.bits.ctrl.rfWen.getOrElse(false.B))
120  private val fuFpWenVec  = funcUnits.map(x => x.cfg.writeFpRf.B  && x.io.out.bits.ctrl.fpWen.getOrElse(false.B))
121  private val fuVecWenVec = funcUnits.map(x => x.cfg.writeVecRf.B && x.io.out.bits.ctrl.vecWen.getOrElse(false.B))
122  // FunctionUnits <---> ExeUnit.out
123  io.out.valid := Cat(fuOutValidOH).orR
124  funcUnits.foreach(fu => fu.io.out.ready := io.out.ready)
125
126  // select one fu's result
127  io.out.bits.data := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.res.data))
128  io.out.bits.robIdx := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.robIdx))
129  io.out.bits.pdest := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.pdest))
130  io.out.bits.intWen.foreach(x => x := Mux1H(fuOutValidOH, fuIntWenVec))
131  io.out.bits.fpWen.foreach(x => x := Mux1H(fuOutValidOH, fuFpWenVec))
132  io.out.bits.vecWen.foreach(x => x := Mux1H(fuOutValidOH, fuVecWenVec))
133  io.out.bits.redirect.foreach(x => x := Mux1H((fuOutValidOH zip fuRedirectVec).filter(_._2.isDefined).map(x => (x._1, x._2.get))))
134  io.out.bits.fflags.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.res.fflags.getOrElse(0.U.asTypeOf(io.out.bits.fflags.get)))))
135  io.out.bits.vxsat.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.res.vxsat.getOrElse(0.U.asTypeOf(io.out.bits.vxsat.get)))))
136  io.out.bits.exceptionVec.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.exceptionVec.getOrElse(0.U.asTypeOf(io.out.bits.exceptionVec.get)))))
137  io.out.bits.flushPipe.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.flushPipe.getOrElse(0.U.asTypeOf(io.out.bits.flushPipe.get)))))
138  io.out.bits.replay.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.replay.getOrElse(0.U.asTypeOf(io.out.bits.replay.get)))))
139  io.out.bits.predecodeInfo.foreach(x => x := Mux1H(fuOutValidOH, fuOutBitsVec.map(_.ctrl.preDecode.getOrElse(0.U.asTypeOf(io.out.bits.predecodeInfo.get)))))
140
141  io.csrio.foreach(exuio => funcUnits.foreach(fu => fu.io.csrio.foreach{
142    fuio =>
143      exuio <> fuio
144      fuio.exception := DelayN(exuio.exception, 2)
145  }))
146  io.fenceio.foreach(exuio => funcUnits.foreach(fu => fu.io.fenceio.foreach(fuio => fuio <> exuio)))
147  io.frm.foreach(exuio => funcUnits.foreach(fu => fu.io.frm.foreach(fuio => fuio <> exuio)))
148
149  // debug info
150  io.out.bits.debug     := 0.U.asTypeOf(io.out.bits.debug)
151  io.out.bits.debugInfo := 0.U.asTypeOf(io.out.bits.debugInfo)
152}
153
154class DispatcherIO[T <: Data](private val gen: T, n: Int) extends Bundle {
155  val in = Flipped(DecoupledIO(gen))
156
157  val out = Vec(n, DecoupledIO(gen))
158}
159
160class Dispatcher[T <: Data](private val gen: T, n: Int, acceptCond: T => Seq[Bool])
161  (implicit p: Parameters)
162  extends Module {
163
164  val io = IO(new DispatcherIO(gen, n))
165
166  private val acceptVec: Vec[Bool] = VecInit(acceptCond(io.in.bits))
167
168  XSError(io.in.valid && PopCount(acceptVec) > 1.U, s"s[ExeUnit] accept vec should no more than 1, ${Binary(acceptVec.asUInt)} ")
169  XSError(io.in.valid && PopCount(acceptVec) === 0.U, "[ExeUnit] there is a inst not dispatched to any fu")
170
171  io.out.zipWithIndex.foreach { case (out, i) =>
172    out.valid := acceptVec(i) && io.in.valid
173    out.bits := io.in.bits
174  }
175
176  io.in.ready := Cat(io.out.map(_.ready)).orR
177}
178
179class MemExeUnitIO (implicit p: Parameters) extends XSBundle {
180  val flush = Flipped(ValidIO(new Redirect()))
181  val in = Flipped(DecoupledIO(new MemExuInput()))
182  val out = DecoupledIO(new MemExuOutput())
183}
184
185class MemExeUnit(exuParams: ExeUnitParams)(implicit p: Parameters) extends XSModule {
186  val io = IO(new MemExeUnitIO)
187  val fu = exuParams.fuConfigs.head.fuGen(p, exuParams.fuConfigs.head)
188  fu.io.flush             := io.flush
189  fu.io.in.valid          := io.in.valid
190  io.in.ready             := fu.io.in.ready
191
192  fu.io.in.bits.ctrl.robIdx    := io.in.bits.uop.robIdx
193  fu.io.in.bits.ctrl.pdest     := io.in.bits.uop.pdest
194  fu.io.in.bits.ctrl.fuOpType  := io.in.bits.uop.fuOpType
195  fu.io.in.bits.data.imm       := io.in.bits.uop.imm
196  fu.io.in.bits.data.src.zip(io.in.bits.src).foreach(x => x._1 := x._2)
197
198  io.out.valid            := fu.io.out.valid
199  fu.io.out.ready         := io.out.ready
200
201  io.out.bits             := 0.U.asTypeOf(io.out.bits) // dontCare other fields
202  io.out.bits.data        := fu.io.out.bits.res.data
203  io.out.bits.uop.robIdx  := fu.io.out.bits.ctrl.robIdx
204  io.out.bits.uop.pdest   := fu.io.out.bits.ctrl.pdest
205  io.out.bits.uop.fuType  := io.in.bits.uop.fuType
206  io.out.bits.uop.fuOpType:= io.in.bits.uop.fuOpType
207  io.out.bits.uop.sqIdx   := io.in.bits.uop.sqIdx
208
209  io.out.bits.debug       := 0.U.asTypeOf(io.out.bits.debug)
210}
211