xref: /XiangShan/src/main/scala/xiangshan/backend/fu/FuncUnit.scala (revision b6279fc62b995344eb1f409e6a3b794762f82d5e)
1package xiangshan.backend.fu
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import utility.DataHoldBypass
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
15
16class FuncUnitCtrlInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
17  val fuOpType    = FuOpType()
18  val robIdx      = new RobPtr
19  val pdest       = UInt(PhyRegIdxWidth.W)
20  val rfWen       = OptionWrapper(cfg.needIntWen, Bool())
21  val fpWen       = OptionWrapper(cfg.needFpWen,  Bool())
22  val vecWen      = OptionWrapper(cfg.needVecWen, Bool())
23  val flushPipe   = OptionWrapper(cfg.flushPipe,  Bool())
24  val preDecode   = OptionWrapper(cfg.hasPredecode, new PreDecodeInfo)
25  val ftqIdx      = OptionWrapper(cfg.needPc || cfg.replayInst || cfg.isSta, new FtqPtr)
26  val ftqOffset   = OptionWrapper(cfg.needPc || cfg.replayInst || cfg.isSta, UInt(log2Up(PredictWidth).W))
27  val predictInfo = OptionWrapper(cfg.hasRedirect, new Bundle {
28    val target    = UInt(VAddrData().dataWidth.W)
29    val taken     = Bool()
30  })
31  val fpu         = OptionWrapper(cfg.writeFflags, new FPUCtrlSignals)
32  val vpu         = OptionWrapper(cfg.needVecCtrl, new VPUCtrlSignals)
33}
34
35class FuncUnitCtrlOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
36  val robIdx        = new RobPtr
37  val pdest         = UInt(PhyRegIdxWidth.W) // Todo: use maximum of pregIdxWidth of different pregs
38  val rfWen         = OptionWrapper(cfg.needIntWen, Bool())
39  val fpWen         = OptionWrapper(cfg.needFpWen,  Bool())
40  val vecWen        = OptionWrapper(cfg.needVecWen, Bool())
41  val exceptionVec  = OptionWrapper(cfg.exceptionOut.nonEmpty, ExceptionVec())
42  val flushPipe     = OptionWrapper(cfg.flushPipe,  Bool())
43  val replay        = OptionWrapper(cfg.replayInst, Bool())
44  val preDecode     = OptionWrapper(cfg.hasPredecode, new PreDecodeInfo)
45  val fpu           = OptionWrapper(cfg.writeFflags, new FPUCtrlSignals)
46  val vpu           = OptionWrapper(cfg.needVecCtrl, new VPUCtrlSignals)
47}
48
49class FuncUnitDataInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
50  val src       = MixedVec(cfg.genSrcDataVec)
51  val imm       = UInt(cfg.dataBits.W)
52  val pc        = OptionWrapper(cfg.needPc, UInt(VAddrData().dataWidth.W))
53
54  def getSrcVConfig : UInt = src(cfg.vconfigIdx)
55  def getSrcMask    : UInt = src(cfg.maskSrcIdx)
56}
57
58class FuncUnitDataOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
59  val data      = UInt(cfg.dataBits.W)
60  val fflags    = OptionWrapper(cfg.writeFflags, UInt(5.W))
61  val vxsat     = OptionWrapper(cfg.writeVxsat, Vxsat())
62  val pc        = OptionWrapper(cfg.isFence, UInt(VAddrData().dataWidth.W))
63  val redirect  = OptionWrapper(cfg.hasRedirect, ValidIO(new Redirect))
64}
65
66class FuncUnitInput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
67  val ctrl = new FuncUnitCtrlInput(cfg)
68  val data = new FuncUnitDataInput(cfg)
69  val perfDebugInfo = new PerfDebugInfo()
70}
71
72class FuncUnitOutput(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
73  val ctrl = new FuncUnitCtrlOutput(cfg)
74  val res = new FuncUnitDataOutput(cfg)
75  val perfDebugInfo = new PerfDebugInfo()
76}
77
78class FuncUnitIO(cfg: FuConfig)(implicit p: Parameters) extends XSBundle {
79  val flush = Flipped(ValidIO(new Redirect))
80  val in = Flipped(DecoupledIO(new FuncUnitInput(cfg)))
81  val out = DecoupledIO(new FuncUnitOutput(cfg))
82  val csrio = if (cfg.isCsr) Some(new CSRFileIO) else None
83  val fenceio = if (cfg.isFence) Some(new FenceIO) else None
84  val frm = if (cfg.needSrcFrm) Some(Input(UInt(3.W))) else None
85  val vxrm = if (cfg.needSrcVxrm) Some(Input(UInt(2.W))) else None
86  val vlIsZero = OptionWrapper(cfg.writeVConfig, Output(Bool()))
87  val vlIsVlmax = OptionWrapper(cfg.writeVConfig, Output(Bool()))
88}
89
90abstract class FuncUnit(val cfg: FuConfig)(implicit p: Parameters) extends XSModule {
91  val io = IO(new FuncUnitIO(cfg))
92
93  // should only be used in non-piped fu
94  def connectNonPipedCtrlSingal: Unit = {
95    io.out.bits.ctrl.robIdx := RegEnable(io.in.bits.ctrl.robIdx, io.in.fire)
96    io.out.bits.ctrl.pdest  := RegEnable(io.in.bits.ctrl.pdest, io.in.fire)
97    io.out.bits.ctrl.rfWen  .foreach(_ := RegEnable(io.in.bits.ctrl.rfWen.get, io.in.fire))
98    io.out.bits.ctrl.fpWen  .foreach(_ := RegEnable(io.in.bits.ctrl.fpWen.get, io.in.fire))
99    io.out.bits.ctrl.vecWen .foreach(_ := RegEnable(io.in.bits.ctrl.vecWen.get, io.in.fire))
100    // io.out.bits.ctrl.flushPipe should be connected in fu
101    io.out.bits.ctrl.preDecode.foreach(_ := RegEnable(io.in.bits.ctrl.preDecode.get, io.in.fire))
102    io.out.bits.ctrl.fpu      .foreach(_ := RegEnable(io.in.bits.ctrl.fpu.get, io.in.fire))
103    io.out.bits.ctrl.vpu      .foreach(_ := RegEnable(io.in.bits.ctrl.vpu.get, io.in.fire))
104    io.out.bits.perfDebugInfo := RegEnable(io.in.bits.perfDebugInfo, io.in.fire)
105  }
106
107  def connect0LatencyCtrlSingal: Unit = {
108    io.out.bits.ctrl.robIdx := io.in.bits.ctrl.robIdx
109    io.out.bits.ctrl.pdest := io.in.bits.ctrl.pdest
110    io.out.bits.ctrl.rfWen.foreach(_ := io.in.bits.ctrl.rfWen.get)
111    io.out.bits.ctrl.fpWen.foreach(_ := io.in.bits.ctrl.fpWen.get)
112    io.out.bits.ctrl.vecWen.foreach(_ := io.in.bits.ctrl.vecWen.get)
113    // io.out.bits.ctrl.flushPipe should be connected in fu
114    io.out.bits.ctrl.preDecode.foreach(_ := io.in.bits.ctrl.preDecode.get)
115    io.out.bits.ctrl.fpu.foreach(_ := io.in.bits.ctrl.fpu.get)
116    io.out.bits.ctrl.vpu.foreach(_ := io.in.bits.ctrl.vpu.get)
117    io.out.bits.perfDebugInfo := io.in.bits.perfDebugInfo
118  }
119}
120
121/**
122  * @author LinJiaWei, Yinan Xu
123  */
124trait HasPipelineReg { this: FuncUnit =>
125  def latency: Int
126
127  require(latency >= 0)
128
129  val validVec = io.in.valid +: Seq.fill(latency)(RegInit(false.B))
130  val rdyVec = Seq.fill(latency)(Wire(Bool())) :+ io.out.ready
131  val ctrlVec = io.in.bits.ctrl +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.ctrl)))
132  val dataVec = io.in.bits.data +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.data)))
133  val perfVec = io.in.bits.perfDebugInfo +: Seq.fill(latency)(Reg(chiselTypeOf(io.in.bits.perfDebugInfo)))
134
135  val robIdxVec = ctrlVec.map(_.robIdx)
136  val pcVec = dataVec.map(_.pc)
137
138  // if flush(0), valid 0 will not given, so set flushVec(0) to false.B
139  val flushVec = validVec.zip(robIdxVec).map(x => x._1 && x._2.needFlush(io.flush))
140
141  for (i <- 0 until latency) {
142    rdyVec(i) := !validVec(i + 1) || rdyVec(i + 1)
143  }
144
145  for (i <- 1 to latency) {
146    when(rdyVec(i - 1) && validVec(i - 1) && !flushVec(i - 1)) {
147      validVec(i) := validVec(i - 1)
148      ctrlVec(i) := ctrlVec(i - 1)
149      dataVec(i) := dataVec(i - 1)
150      perfVec(i) := perfVec(i - 1)
151    }.elsewhen(flushVec(i) || rdyVec(i)) {
152      validVec(i) := false.B
153    }
154  }
155
156  io.in.ready := rdyVec.head
157  io.out.valid := validVec.last
158  io.out.bits.res.pc.zip(pcVec.last).foreach { case (l, r) => l := r }
159
160  io.out.bits.ctrl.robIdx := ctrlVec.last.robIdx
161  io.out.bits.ctrl.pdest := ctrlVec.last.pdest
162  io.out.bits.ctrl.rfWen.foreach(_ := ctrlVec.last.rfWen.get)
163  io.out.bits.ctrl.fpWen.foreach(_ := ctrlVec.last.fpWen.get)
164  io.out.bits.ctrl.vecWen.foreach(_ := ctrlVec.last.vecWen.get)
165  io.out.bits.ctrl.fpu.foreach(_ := ctrlVec.last.fpu.get)
166  io.out.bits.ctrl.vpu.foreach(_ := ctrlVec.last.vpu.get)
167  io.out.bits.perfDebugInfo := perfVec.last
168
169  // vstart illegal
170  if (cfg.exceptionOut.nonEmpty) {
171    val outVstart = ctrlVec.last.vpu.get.vstart
172    val vstartIllegal = outVstart =/= 0.U
173    io.out.bits.ctrl.exceptionVec.get := 0.U.asTypeOf(io.out.bits.ctrl.exceptionVec.get)
174    io.out.bits.ctrl.exceptionVec.get(illegalInstr) := vstartIllegal
175  }
176
177  def regEnable(i: Int): Bool = validVec(i - 1) && rdyVec(i - 1) && !flushVec(i - 1)
178
179  def PipelineReg[TT <: Data](i: Int)(next: TT) = RegEnable(
180    next,
181    regEnable(i)
182  )
183
184  def S1Reg[TT <: Data](next: TT): TT = PipelineReg[TT](1)(next)
185
186  def S2Reg[TT <: Data](next: TT): TT = PipelineReg[TT](2)(next)
187
188  def S3Reg[TT <: Data](next: TT): TT = PipelineReg[TT](3)(next)
189
190  def S4Reg[TT <: Data](next: TT): TT = PipelineReg[TT](4)(next)
191
192  def S5Reg[TT <: Data](next: TT): TT = PipelineReg[TT](5)(next)
193
194}
195
196abstract class PipedFuncUnit(override val cfg: FuConfig)(implicit p: Parameters) extends FuncUnit(cfg)
197  with HasPipelineReg {
198  override def latency: Int = cfg.latency.latencyVal.get
199}
200