xref: /XiangShan/src/main/scala/xiangshan/backend/exu/ExeUnitParams.scala (revision 0c7ebb58175b51109677230e8cbab09e73166956)
1package xiangshan.backend.exu
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import xiangshan.backend.BackendParams
7import xiangshan.backend.Bundles.{ExuBypassBundle, ExuInput, ExuOutput}
8import xiangshan.backend.datapath.DataConfig.DataConfig
9import xiangshan.backend.datapath.RdConfig._
10import xiangshan.backend.datapath.WbConfig.{IntWB, PregWB, VfWB}
11import xiangshan.backend.datapath.{DataConfig, WakeUpConfig}
12import xiangshan.backend.fu.{FuConfig, FuType}
13import xiangshan.backend.issue.{IntScheduler, SchedulerType, VfScheduler}
14
15case class ExeUnitParams(
16  name          : String,
17  fuConfigs     : Seq[FuConfig],
18  wbPortConfigs : Seq[PregWB],
19  rfrPortConfigs: Seq[Seq[RdConfig]],
20  copyPdest: Boolean = false,
21  copyDistance: Int = 1,
22  fakeUnit      : Boolean = false,
23)(
24  implicit
25  val schdType: SchedulerType,
26) {
27  // calculated configs
28  var iqWakeUpSourcePairs: Seq[WakeUpConfig] = Seq()
29  var iqWakeUpSinkPairs: Seq[WakeUpConfig] = Seq()
30  // used in bypass to select data of exu output
31  var exuIdx: Int = -1
32  var backendParam: BackendParams = null
33
34  val numIntSrc: Int = fuConfigs.map(_.numIntSrc).max
35  val numFpSrc: Int = fuConfigs.map(_.numFpSrc).max
36  val numVecSrc: Int = fuConfigs.map(_.numVecSrc).max
37  val numVfSrc: Int = fuConfigs.map(_.numVfSrc).max
38  val numRegSrc: Int = fuConfigs.map(_.numRegSrc).max
39  val numSrc: Int = fuConfigs.map(_.numSrc).max
40  val dataBitsMax: Int = fuConfigs.map(_.dataBits).max
41  val readIntRf: Boolean = numIntSrc > 0
42  val readFpRf: Boolean = numFpSrc > 0
43  val readVecRf: Boolean = numVecSrc > 0
44  val writeIntRf: Boolean = fuConfigs.map(_.writeIntRf).reduce(_ || _)
45  val writeFpRf: Boolean = fuConfigs.map(_.writeFpRf).reduce(_ || _)
46  val writeVecRf: Boolean = fuConfigs.map(_.writeVecRf).reduce(_ || _)
47  val writeVfRf: Boolean = writeFpRf || writeVecRf
48  val writeFflags: Boolean = fuConfigs.map(_.writeFflags).reduce(_ || _)
49  val writeVxsat: Boolean = fuConfigs.map(_.writeVxsat).reduce(_ || _)
50  val hasNoDataWB: Boolean = fuConfigs.map(_.hasNoDataWB).reduce(_ || _)
51  val hasRedirect: Boolean = fuConfigs.map(_.hasRedirect).reduce(_ || _)
52  val hasPredecode: Boolean = fuConfigs.map(_.hasPredecode).reduce(_ || _)
53  val exceptionOut: Seq[Int] = fuConfigs.map(_.exceptionOut).reduce(_ ++ _).distinct.sorted
54  val hasLoadError: Boolean = fuConfigs.map(_.hasLoadError).reduce(_ || _)
55  val flushPipe: Boolean = fuConfigs.map(_.flushPipe).reduce(_ || _)
56  val replayInst: Boolean = fuConfigs.map(_.replayInst).reduce(_ || _)
57  val trigger: Boolean = fuConfigs.map(_.trigger).reduce(_ || _)
58  val needExceptionGen: Boolean = exceptionOut.nonEmpty || flushPipe || replayInst || trigger
59  val needPc: Boolean = fuConfigs.map(_.needPc).reduce(_ || _)
60  val needTarget: Boolean = fuConfigs.map(_.needTargetPc).reduce(_ || _)
61  val needPdInfo: Boolean = fuConfigs.map(_.needPdInfo).reduce(_ || _)
62  val needSrcFrm: Boolean = fuConfigs.map(_.needSrcFrm).reduce(_ || _)
63  val needFPUCtrl: Boolean = fuConfigs.map(_.needFPUCtrl).reduce(_ || _)
64  val needVPUCtrl: Boolean = fuConfigs.map(_.needVecCtrl).reduce(_ || _)
65  val isHighestWBPriority: Boolean = wbPortConfigs.forall(_.priority == 0)
66
67  def rdPregIdxWidth: Int = {
68    this.pregRdDataCfgSet.map(dataCfg => backendParam.getPregParams(dataCfg).addrWidth).fold(0)(_ max _)
69  }
70
71  def wbPregIdxWidth: Int = {
72    this.pregWbDataCfgSet.map(dataCfg => backendParam.getPregParams(dataCfg).addrWidth).fold(0)(_ max _)
73  }
74
75  val writeIntFuConfigs: Seq[FuConfig] = fuConfigs.filter(x => x.writeIntRf)
76  val writeVfFuConfigs: Seq[FuConfig] = fuConfigs.filter(x => x.writeFpRf || x.writeVecRf)
77
78  /**
79    * Check if this exu has certain latency
80    */
81  def latencyCertain: Boolean = fuConfigs.map(x => x.latency.latencyVal.nonEmpty).reduce(_ && _)
82  def intLatencyCertain: Boolean = writeIntFuConfigs.forall(x => x.latency.latencyVal.nonEmpty)
83  def vfLatencyCertain: Boolean = writeVfFuConfigs.forall(x => x.latency.latencyVal.nonEmpty)
84  // only load use it
85  def hasUncertainLatencyVal: Boolean = fuConfigs.map(x => x.latency.uncertainLatencyVal.nonEmpty).reduce(_ || _)
86
87  /**
88    * Get mapping from FuType to Latency value.
89    * If both [[latencyCertain]] and [[hasUncertainLatencyVal]] are false, get empty [[Map]]
90    *
91    * @return Map[ [[BigInt]], Latency]
92    */
93  def fuLatencyMap: Map[FuType.OHType, Int] = {
94    if (latencyCertain)
95      fuConfigs.map(x => (x.fuType, x.latency.latencyVal.get)).toMap
96    else if (hasUncertainLatencyVal)
97      fuConfigs.map(x => (x.fuType, x.latency.uncertainLatencyVal)).toMap.filter(_._2.nonEmpty).map(x => (x._1, x._2.get))
98    else
99      Map()
100  }
101
102  /**
103    * Get set of latency of function units.
104    * If both [[latencyCertain]] and [[hasUncertainLatencyVal]] are false, get empty [[Set]]
105    *
106    * @return Set[Latency]
107    */
108  def fuLatancySet: Set[Int] = fuLatencyMap.values.toSet
109
110  def latencyValMax: Int = fuLatancySet.fold(0)(_ max _)
111
112  def intFuLatencyMap: Map[FuType.OHType, Int] = {
113    if (intLatencyCertain)
114      writeIntFuConfigs.map(x => (x.fuType, x.latency.latencyVal.get)).toMap
115    else
116      Map()
117  }
118
119  def intLatencyValMax: Int = intFuLatencyMap.values.fold(0)(_ max _)
120
121  def vfFuLatencyMap: Map[FuType.OHType, Int] = {
122    if (vfLatencyCertain)
123      writeVfFuConfigs.map(x => (x.fuType, x.latency.latencyVal.get)).toMap
124    else
125      Map()
126  }
127
128  def vfLatencyValMax: Int = vfFuLatencyMap.values.fold(0)(_ max _)
129
130  /**
131    * Check if this exu has fixed latency
132    */
133  def isFixedLatency: Boolean = {
134    if (latencyCertain)
135      return fuConfigs.map(x => x.latency.latencyVal.get == fuConfigs.head.latency.latencyVal.get).reduce(_ && _)
136    false
137  }
138
139  def hasCSR: Boolean = fuConfigs.map(_.isCsr).reduce(_ || _)
140
141  def hasFence: Boolean = fuConfigs.map(_.isFence).reduce(_ || _)
142
143  def hasBrhFu = fuConfigs.map(_.fuType == FuType.brh).reduce(_ || _)
144
145  def hasJmpFu = fuConfigs.map(_.fuType == FuType.jmp).reduce(_ || _)
146
147  def hasLoadFu = fuConfigs.map(_.name == "ldu").reduce(_ || _)
148
149  def hasVLoadFu = fuConfigs.map(_.fuType == FuType.vldu).reduce(_ || _)
150
151  def hasVStoreFu = fuConfigs.map(_.fuType == FuType.vstu).reduce(_ || _)
152
153  def hasStoreAddrFu = fuConfigs.map(_.name == "sta").reduce(_ || _)
154
155  def hasStdFu = fuConfigs.map(_.name == "std").reduce(_ || _)
156
157  def hasMemAddrFu = hasLoadFu || hasStoreAddrFu || hasVLoadFu || hasHyldaFu || hasHystaFu || hasVLoadFu || hasVStoreFu
158
159  def hasHyldaFu = fuConfigs.map(_.name == "hylda").reduce(_ || _)
160
161  def hasHystaFu = fuConfigs.map(_.name == "hysta").reduce(_ || _)
162
163  def hasLoadExu = hasLoadFu || hasHyldaFu
164
165  def hasStoreAddrExu = hasStoreAddrFu || hasHystaFu
166
167  def hasVecFu = fuConfigs.map(x => FuConfig.VecArithFuConfigs.contains(x)).reduce(_ || _)
168
169  def getSrcDataType(srcIdx: Int): Set[DataConfig] = {
170    fuConfigs.map(_.getSrcDataType(srcIdx)).reduce(_ ++ _)
171  }
172
173  def immType: Set[UInt] = fuConfigs.map(x => x.immType).reduce(_ ++ _)
174
175  def getWBSource: SchedulerType = {
176    schdType
177  }
178
179  def hasCrossWb: Boolean = {
180    schdType match {
181      case IntScheduler() => writeFpRf || writeVecRf
182      case VfScheduler() => writeIntRf
183      case _ => false
184    }
185  }
186
187  def canAccept(fuType: UInt): Bool = {
188    Cat(fuConfigs.map(_.fuType.U === fuType)).orR
189  }
190
191  def hasUncertainLatency: Boolean = fuConfigs.map(_.latency.latencyVal.isEmpty).reduce(_ || _)
192
193  def bindBackendParam(param: BackendParams): Unit = {
194    backendParam = param
195  }
196
197  def updateIQWakeUpConfigs(cfgs: Seq[WakeUpConfig]) = {
198    this.iqWakeUpSourcePairs = cfgs.filter(_.source.name == this.name)
199    this.iqWakeUpSinkPairs = cfgs.filter(_.sink.name == this.name)
200    if (this.isIQWakeUpSource) {
201      require(!this.hasUncertainLatency || hasLoadFu || hasHyldaFu, s"${this.name} is a not-LDU IQ wake up source , but has UncertainLatency")
202    }
203  }
204
205  def updateExuIdx(idx: Int): Unit = {
206    this.exuIdx = idx
207  }
208
209  def isIQWakeUpSource = this.iqWakeUpSourcePairs.nonEmpty
210
211  def isIQWakeUpSink = this.iqWakeUpSinkPairs.nonEmpty
212
213  def getIntWBPort = {
214    wbPortConfigs.collectFirst {
215      case x: IntWB => x
216    }
217  }
218
219  def getVfWBPort = {
220    wbPortConfigs.collectFirst {
221      case x: VfWB => x
222    }
223  }
224
225  /**
226    * Get the [[DataConfig]] that this exu need to read
227    */
228  def pregRdDataCfgSet: Set[DataConfig] = {
229    this.rfrPortConfigs.flatten.map(_.getDataConfig).toSet
230  }
231
232  /**
233    * Get the [[DataConfig]] that this exu need to write
234    */
235  def pregWbDataCfgSet: Set[DataConfig] = {
236    this.wbPortConfigs.map(_.dataCfg).toSet
237  }
238
239  def getRfReadDataCfgSet: Seq[Set[DataConfig]] = {
240    val fuSrcsCfgSet: Seq[Seq[Set[DataConfig]]] = fuConfigs.map(_.getRfReadDataCfgSet)
241    val alignedFuSrcsCfgSet: Seq[Seq[Set[DataConfig]]] = fuSrcsCfgSet.map(x => x ++ Seq.fill(numRegSrc - x.length)(Set[DataConfig]()))
242
243    val exuSrcsCfgSet = alignedFuSrcsCfgSet.reduce((x, y) => (x zip y).map { case (cfg1, cfg2) => cfg1 union cfg2 })
244
245    exuSrcsCfgSet
246  }
247
248  /**
249    * Get the [[DataConfig]] mapped indices of source data of exu
250    *
251    * @example
252    * {{{
253    *   fuCfg.srcData = Seq(VecData(), VecData(), VecData(), MaskSrcData(), VConfigData())
254    *   getRfReadSrcIdx(VecData()) = Seq(0, 1, 2)
255    *   getRfReadSrcIdx(MaskSrcData()) = Seq(3)
256    *   getRfReadSrcIdx(VConfigData()) = Seq(4)
257    * }}}
258    * @return Map[DataConfig -> Seq[indices]]
259    */
260  def getRfReadSrcIdx: Map[DataConfig, Seq[Int]] = {
261    val dataCfgs = DataConfig.RegSrcDataSet
262    val rfRdDataCfgSet = this.getRfReadDataCfgSet
263    dataCfgs.toSeq.map { cfg =>
264      (
265        cfg,
266        rfRdDataCfgSet.zipWithIndex.map { case (set, srcIdx) =>
267          if (set.contains(cfg))
268            Option(srcIdx)
269          else
270            None
271        }.filter(_.nonEmpty).map(_.get)
272      )
273    }.toMap
274  }
275
276  def genExuModule(implicit p: Parameters): ExeUnit = {
277    new ExeUnit(this)
278  }
279
280  def genExuInputBundle(implicit p: Parameters): ExuInput = {
281    new ExuInput(this)
282  }
283
284  def genExuOutputBundle(implicit p: Parameters): ExuOutput = {
285    new ExuOutput(this)
286  }
287
288  def genExuBypassBundle(implicit p: Parameters): ExuBypassBundle = {
289    new ExuBypassBundle(this)
290  }
291}
292