xref: /XiangShan/src/main/scala/xiangshan/backend/fu/FuncUnit.scala (revision 211d620b07edb797ba35b635d24fef4e7294bae2)
1package xiangshan.backend.fu
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import utility._
7import utils.OptionWrapper
8import xiangshan._
9import xiangshan.backend.Bundles.VPUCtrlSignals
10import xiangshan.backend.rob.RobPtr
11import xiangshan.frontend.{FtqPtr, PreDecodeInfo}
12import xiangshan.backend.datapath.DataConfig._
13import xiangshan.backend.fu.vector.Bundles.Vxsat
14import xiangshan.ExceptionNO.illegalInstr
15import xiangshan.backend.fu.vector.Bundles.VType
16import xiangshan.backend.fu.wrapper.{CSRInput, CSRToDecode}
17
18class FuncUnitCtrlInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
19  val fuOpType    = FuOpType()
20  val robIdx      = new RobPtr
21  val pdest       = UInt(PhyRegIdxWidth.W)
22  val rfWen       = OptionWrapper(cfg.needIntWen, Bool())
23  val fpWen       = OptionWrapper(cfg.needFpWen,  Bool())
24  val vecWen      = OptionWrapper(cfg.needVecWen, Bool())
25  val v0Wen       = OptionWrapper(cfg.needV0Wen, Bool())
26  val vlWen       = OptionWrapper(cfg.needVlWen, Bool())
27  val flushPipe   = OptionWrapper(cfg.flushPipe,  Bool())
28  val preDecode   = OptionWrapper(cfg.hasPredecode, new PreDecodeInfo)
29  val ftqIdx      = OptionWrapper(cfg.needPc || cfg.replayInst || cfg.isSta || cfg.isCsr, new FtqPtr)
30  val ftqOffset   = OptionWrapper(cfg.needPc || cfg.replayInst || cfg.isSta || cfg.isCsr, UInt(log2Up(PredictWidth).W))
31  val predictInfo = OptionWrapper(cfg.needPdInfo, new Bundle {
32    val target    = UInt(VAddrData().dataWidth.W)
33    val taken     = Bool()
34  })
35  val fpu         = OptionWrapper(cfg.writeFflags, new FPUCtrlSignals)
36  val vpu         = OptionWrapper(cfg.needVecCtrl, new VPUCtrlSignals)
37}
38
39class FuncUnitCtrlOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
40  val robIdx        = new RobPtr
41  val pdest         = UInt(PhyRegIdxWidth.W) // Todo: use maximum of pregIdxWidth of different pregs
42  val rfWen         = OptionWrapper(cfg.needIntWen, Bool())
43  val fpWen         = OptionWrapper(cfg.needFpWen,  Bool())
44  val vecWen        = OptionWrapper(cfg.needVecWen, Bool())
45  val v0Wen         = OptionWrapper(cfg.needV0Wen, Bool())
46  val vlWen         = OptionWrapper(cfg.needVlWen, Bool())
47  val exceptionVec  = OptionWrapper(cfg.exceptionOut.nonEmpty, ExceptionVec())
48  val flushPipe     = OptionWrapper(cfg.flushPipe,  Bool())
49  val replay        = OptionWrapper(cfg.replayInst, Bool())
50  val preDecode     = OptionWrapper(cfg.hasPredecode, new PreDecodeInfo)
51  val fpu           = OptionWrapper(cfg.writeFflags, new FPUCtrlSignals)
52  val vpu           = OptionWrapper(cfg.needVecCtrl, new VPUCtrlSignals)
53}
54
55class FuncUnitDataInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
56  val src       = MixedVec(cfg.genSrcDataVec)
57  val imm       = UInt(cfg.destDataBits.W)
58  val pc        = OptionWrapper(cfg.needPc, UInt(VAddrData().dataWidth.W))
59
60  def getSrcVConfig : UInt = src(cfg.vconfigIdx)
61  def getSrcMask    : UInt = src(cfg.maskSrcIdx)
62}
63
64class FuncUnitDataOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
65  val data      = UInt(cfg.destDataBits.W)
66  val fflags    = OptionWrapper(cfg.writeFflags, UInt(5.W))
67  val vxsat     = OptionWrapper(cfg.writeVxsat, Vxsat())
68  val pc        = OptionWrapper(cfg.isFence, UInt(VAddrData().dataWidth.W))
69  val redirect  = OptionWrapper(cfg.hasRedirect, ValidIO(new Redirect))
70}
71
72class FuncUnitInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
73  val ctrl = new FuncUnitCtrlInput(cfg)
74  val data = new FuncUnitDataInput(cfg)
75  val perfDebugInfo = new PerfDebugInfo()
76}
77
78class FuncUnitOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
79  val ctrl = new FuncUnitCtrlOutput(cfg)
80  val res = new FuncUnitDataOutput(cfg)
81  val perfDebugInfo = new PerfDebugInfo()
82}
83
84class FuncUnitIO(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
85  val flush = Flipped(ValidIO(new Redirect))
86  val in = Flipped(DecoupledIO(new FuncUnitInput(cfg)))
87  val out = DecoupledIO(new FuncUnitOutput(cfg))
88  val csrin = OptionWrapper(cfg.isCsr, new CSRInput)
89  val csrio = OptionWrapper(cfg.isCsr, new CSRFileIO)
90  val csrToDecode = OptionWrapper(cfg.isCsr, Output(new CSRToDecode))
91  val fenceio = OptionWrapper(cfg.isFence, new FenceIO)
92  val frm = OptionWrapper(cfg.needSrcFrm, Input(UInt(3.W)))
93  val vxrm = OptionWrapper(cfg.needSrcVxrm, Input(UInt(2.W)))
94  val vtype = OptionWrapper(cfg.writeVlRf, (Valid(new VType)))
95  val vlIsZero = OptionWrapper(cfg.writeVlRf, Output(Bool()))
96  val vlIsVlmax = OptionWrapper(cfg.writeVlRf, Output(Bool()))
97  val instrAddrTransType = Option.when(cfg.isJmp || cfg.isBrh)(Input(new AddrTransType))
98}
99
100abstract class FuncUnit(val cfg: FuConfig)(implicit p: Parameters) extends XSModule with HasCriticalErrors {
101  val io = IO(new FuncUnitIO(cfg))
102  val criticalErrors = Seq(("none", false.B))
103
104  // should only be used in non-piped fu
105  def connectNonPipedCtrlSingal: Unit = {
106    io.out.bits.ctrl.robIdx := RegEnable(io.in.bits.ctrl.robIdx, io.in.fire)
107    io.out.bits.ctrl.pdest  := RegEnable(io.in.bits.ctrl.pdest, io.in.fire)
108    io.out.bits.ctrl.rfWen  .foreach(_ := RegEnable(io.in.bits.ctrl.rfWen.get, io.in.fire))
109    io.out.bits.ctrl.fpWen  .foreach(_ := RegEnable(io.in.bits.ctrl.fpWen.get, io.in.fire))
110    io.out.bits.ctrl.vecWen .foreach(_ := RegEnable(io.in.bits.ctrl.vecWen.get, io.in.fire))
111    io.out.bits.ctrl.v0Wen .foreach(_ := RegEnable(io.in.bits.ctrl.v0Wen.get, io.in.fire))
112    io.out.bits.ctrl.vlWen .foreach(_ := RegEnable(io.in.bits.ctrl.vlWen.get, io.in.fire))
113    // io.out.bits.ctrl.flushPipe should be connected in fu
114    io.out.bits.ctrl.preDecode.foreach(_ := RegEnable(io.in.bits.ctrl.preDecode.get, io.in.fire))
115    io.out.bits.ctrl.fpu      .foreach(_ := RegEnable(io.in.bits.ctrl.fpu.get, io.in.fire))
116    io.out.bits.ctrl.vpu      .foreach(_ := RegEnable(io.in.bits.ctrl.vpu.get, io.in.fire))
117    io.out.bits.perfDebugInfo := RegEnable(io.in.bits.perfDebugInfo, io.in.fire)
118  }
119
120  def connectNonPipedCtrlSingalForCSR: Unit = {
121    io.out.bits.ctrl.robIdx := DataHoldBypass(io.in.bits.ctrl.robIdx, io.in.fire)
122    io.out.bits.ctrl.pdest := DataHoldBypass(io.in.bits.ctrl.pdest, io.in.fire)
123    io.out.bits.ctrl.rfWen.foreach(_ := DataHoldBypass(io.in.bits.ctrl.rfWen.get, io.in.fire))
124    io.out.bits.ctrl.fpWen.foreach(_ := DataHoldBypass(io.in.bits.ctrl.fpWen.get, io.in.fire))
125    io.out.bits.ctrl.vecWen.foreach(_ := DataHoldBypass(io.in.bits.ctrl.vecWen.get, io.in.fire))
126    io.out.bits.ctrl.v0Wen.foreach(_ := DataHoldBypass(io.in.bits.ctrl.v0Wen.get, io.in.fire))
127    io.out.bits.ctrl.vlWen.foreach(_ := DataHoldBypass(io.in.bits.ctrl.vlWen.get, io.in.fire))
128    // io.out.bits.ctrl.flushPipe should be connected in fu
129    io.out.bits.ctrl.preDecode.foreach(_ := DataHoldBypass(io.in.bits.ctrl.preDecode.get, io.in.fire))
130    io.out.bits.ctrl.fpu.foreach(_ := DataHoldBypass(io.in.bits.ctrl.fpu.get, io.in.fire))
131    io.out.bits.ctrl.vpu.foreach(_ := DataHoldBypass(io.in.bits.ctrl.vpu.get, io.in.fire))
132    io.out.bits.perfDebugInfo := DataHoldBypass(io.in.bits.perfDebugInfo, io.in.fire)
133  }
134
135  def connect0LatencyCtrlSingal: Unit = {
136    io.out.bits.ctrl.robIdx := io.in.bits.ctrl.robIdx
137    io.out.bits.ctrl.pdest := io.in.bits.ctrl.pdest
138    io.out.bits.ctrl.rfWen.foreach(_ := io.in.bits.ctrl.rfWen.get)
139    io.out.bits.ctrl.fpWen.foreach(_ := io.in.bits.ctrl.fpWen.get)
140    io.out.bits.ctrl.vecWen.foreach(_ := io.in.bits.ctrl.vecWen.get)
141    io.out.bits.ctrl.v0Wen.foreach(_ := io.in.bits.ctrl.v0Wen.get)
142    io.out.bits.ctrl.vlWen.foreach(_ := io.in.bits.ctrl.vlWen.get)
143    // io.out.bits.ctrl.flushPipe should be connected in fu
144    io.out.bits.ctrl.preDecode.foreach(_ := io.in.bits.ctrl.preDecode.get)
145    io.out.bits.ctrl.fpu.foreach(_ := io.in.bits.ctrl.fpu.get)
146    io.out.bits.ctrl.vpu.foreach(_ := io.in.bits.ctrl.vpu.get)
147    io.out.bits.perfDebugInfo := io.in.bits.perfDebugInfo
148  }
149}
150
151/**
152  * @author LinJiaWei, Yinan Xu
153  */
154trait HasPipelineReg { this: FuncUnit =>
155  def latency: Int
156
157  val latdiff :Int = cfg.latency.extraLatencyVal.getOrElse(0)
158  val preLat :Int = latency - latdiff
159  require(latency >= 0 && latdiff >=0)
160
161  def pipelineReg(init: FuncUnitInput , valid:Bool, ready: Bool,latency: Int, flush:ValidIO[Redirect]): (Seq[FuncUnitInput],Seq[Bool],Seq[Bool])={
162    val rdyVec = Seq.fill(latency)(Wire(Bool())) :+ ready
163    val validVec = valid +: Seq.fill(latency)(RegInit(false.B))
164    val ctrlVec = init.ctrl +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.ctrl)))
165    val dataVec = init.data +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.data)))
166    val perfVec = init.perfDebugInfo +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.perfDebugInfo)))
167
168
169
170    val robIdxVec = ctrlVec.map(_.robIdx)
171
172    // if flush(0), valid 0 will not given, so set flushVec(0) to false.B
173    val flushVec = validVec.zip(robIdxVec).map(x => x._1 && x._2.needFlush(flush))
174
175    for (i <- 0 until latency) {
176      rdyVec(i) := !validVec(i + 1) || rdyVec(i + 1).asTypeOf(Bool())
177    }
178    for (i <- 1 to latency) {
179      when(rdyVec(i - 1) && validVec(i - 1) && !flushVec(i - 1)) {
180        validVec(i) := validVec(i - 1)
181        ctrlVec(i) := ctrlVec(i - 1)
182        dataVec(i) := dataVec(i - 1)
183        perfVec(i) := perfVec(i - 1)
184      }.elsewhen(flushVec(i) || rdyVec(i)) {
185        validVec(i) := false.B
186      }
187    }
188
189    (ctrlVec.zip(dataVec).zip(perfVec).map{
190      case(( ctrl,data), perf) => {
191        val out = Wire(new FuncUnitInput(cfg))
192        out.ctrl := ctrl
193        out.data := data
194        out.perfDebugInfo := perf
195        out
196      }
197    },validVec, rdyVec)
198  }
199  val (pipeReg : Seq[FuncUnitInput],validVec ,rdyVec ) = pipelineReg(io.in.bits, io.in.valid,io.out.ready,preLat, io.flush)
200  val ctrlVec = pipeReg.map(_.ctrl)
201  val dataVec = pipeReg.map(_.data)
202  val perfVec = pipeReg.map(_.perfDebugInfo)
203  val robIdxVec = ctrlVec.map(_.robIdx)
204  val pipeflushVec = validVec.zip(robIdxVec).map(x => x._1 && x._2.needFlush(io.flush))
205
206
207  val fixtiminginit = Wire(new FuncUnitInput(cfg))
208  fixtiminginit.ctrl := ctrlVec.last
209  fixtiminginit.data := dataVec.last
210  fixtiminginit.perfDebugInfo := perfVec.last
211
212  // fixtiming pipelinereg
213  val (fixpipeReg : Seq[FuncUnitInput], fixValidVec, fixRdyVec) = pipelineReg(fixtiminginit, validVec.last,rdyVec.head ,latdiff, io.flush)
214  val fixCtrlVec = fixpipeReg.map(_.ctrl)
215  val fixDataVec = fixpipeReg.map(_.data)
216  val fixPerfVec = fixpipeReg.map(_.perfDebugInfo)
217  val fixrobIdxVec = ctrlVec.map(_.robIdx)
218  val fixflushVec = fixValidVec.zip(fixrobIdxVec).map(x => x._1 && x._2.needFlush(io.flush))
219  val flushVec = pipeflushVec ++ fixflushVec
220  val pcVec = fixDataVec.map(_.pc)
221
222  io.in.ready := fixRdyVec.head
223  io.out.valid := fixValidVec.last
224  io.out.bits.res.pc.zip(pcVec.last).foreach { case (l, r) => l := r }
225
226  io.out.bits.ctrl.robIdx := fixCtrlVec.last.robIdx
227  io.out.bits.ctrl.pdest := fixCtrlVec.last.pdest
228  io.out.bits.ctrl.rfWen.foreach(_ := fixCtrlVec.last.rfWen.get)
229  io.out.bits.ctrl.fpWen.foreach(_ := fixCtrlVec.last.fpWen.get)
230  io.out.bits.ctrl.vecWen.foreach(_ := fixCtrlVec.last.vecWen.get)
231  io.out.bits.ctrl.v0Wen.foreach(_ := fixCtrlVec.last.v0Wen.get)
232  io.out.bits.ctrl.vlWen.foreach(_ := fixCtrlVec.last.vlWen.get)
233  io.out.bits.ctrl.fpu.foreach(_ := fixCtrlVec.last.fpu.get)
234  io.out.bits.ctrl.vpu.foreach(_ := fixCtrlVec.last.vpu.get)
235  io.out.bits.perfDebugInfo := fixPerfVec.last
236
237  // vstart illegal
238  if (cfg.exceptionOut.nonEmpty) {
239    val outVstart = fixCtrlVec.last.vpu.get.vstart
240    val vstartIllegal = outVstart =/= 0.U
241    io.out.bits.ctrl.exceptionVec.get := 0.U.asTypeOf(io.out.bits.ctrl.exceptionVec.get)
242    io.out.bits.ctrl.exceptionVec.get(illegalInstr) := vstartIllegal
243  }
244
245  def regEnable(i: Int): Bool = validVec(i - 1) && rdyVec(i - 1) && !flushVec(i - 1)
246
247  def PipelineReg[TT <: Data](i: Int)(next: TT) = {
248    val lat = preLat min i
249    RegEnable(
250      next,
251      regEnable(lat)
252    )
253  }
254
255  def SNReg[TT <: Data](in: TT, n: Int): TT ={
256    val lat = preLat min n
257    var next = in
258    for (i <- 1 to lat) {
259      next = PipelineReg[TT](i)(next)
260    }
261    next
262  }
263
264  def S1Reg[TT <: Data](next: TT): TT = PipelineReg[TT](1)(next)
265
266  def S2Reg[TT <: Data](next: TT): TT = PipelineReg[TT](2)(next)
267
268  def S3Reg[TT <: Data](next: TT): TT = PipelineReg[TT](3)(next)
269
270  def S4Reg[TT <: Data](next: TT): TT = PipelineReg[TT](4)(next)
271
272  def S5Reg[TT <: Data](next: TT): TT = PipelineReg[TT](5)(next)
273
274}
275
276abstract class PipedFuncUnit(override val cfg: FuConfig)(implicit p: Parameters) extends FuncUnit(cfg)
277  with HasPipelineReg {
278  override def latency: Int = cfg.latency.latencyVal.get
279}
280