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