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