xref: /XiangShan/src/main/scala/xiangshan/backend/BackendParams.scala (revision 04c99ecade0a43f799280ad61b6acbae487d6c91)
1/***************************************************************************************
2  * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3  * Copyright (c) 2020-2021 Peng Cheng Laboratory
4  *
5  * XiangShan is licensed under Mulan PSL v2.
6  * You can use this software according to the terms and conditions of the Mulan PSL v2.
7  * You may obtain a copy of Mulan PSL v2 at:
8  *          http://license.coscl.org.cn/MulanPSL2
9  *
10  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13  *
14  * See the Mulan PSL v2 for more details.
15  ***************************************************************************************/
16
17package xiangshan.backend
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan.backend.Bundles._
23import xiangshan.backend.datapath.DataConfig._
24import xiangshan.backend.datapath.RdConfig._
25import xiangshan.backend.datapath.WbConfig._
26import xiangshan.backend.datapath.{WakeUpConfig, WbArbiterParams}
27import xiangshan.backend.exu.ExeUnitParams
28import xiangshan.backend.issue._
29import xiangshan.backend.regfile._
30import xiangshan.DebugOptionsKey
31
32import scala.reflect.{ClassTag, classTag}
33
34case class BackendParams(
35  schdParams : Map[SchedulerType, SchdBlockParams],
36  pregParams : Seq[PregParams],
37  iqWakeUpParams : Seq[WakeUpConfig],
38) {
39
40  configChecks
41
42  def debugEn(implicit p: Parameters): Boolean = p(DebugOptionsKey).AlwaysBasicDiff || p(DebugOptionsKey).EnableDifftest
43  def intSchdParams = schdParams.get(IntScheduler())
44  def vfSchdParams = schdParams.get(VfScheduler())
45  def memSchdParams = schdParams.get(MemScheduler())
46  def allSchdParams: Seq[SchdBlockParams] =
47    (Seq(intSchdParams) :+ vfSchdParams :+ memSchdParams)
48    .filter(_.nonEmpty)
49    .map(_.get)
50  def allIssueParams: Seq[IssueBlockParams] =
51    allSchdParams.map(_.issueBlockParams).flatten
52  def allExuParams: Seq[ExeUnitParams] =
53    allIssueParams.map(_.exuBlockParams).flatten
54
55  // filter not fake exu unit
56  def allRealExuParams =
57    allExuParams.filterNot(_.fakeUnit)
58
59  def intPregParams: IntPregParams = pregParams.collectFirst { case x: IntPregParams => x }.get
60  def vfPregParams: VfPregParams = pregParams.collectFirst { case x: VfPregParams => x }.get
61  def getPregParams: Map[DataConfig, PregParams] = {
62    pregParams.map(x => (x.dataCfg, x)).toMap
63  }
64
65  def pregIdxWidth = pregParams.map(_.addrWidth).max
66
67  def numSrc      : Int = allSchdParams.map(_.issueBlockParams.map(_.numSrc).max).max
68  def numRegSrc   : Int = allSchdParams.map(_.issueBlockParams.map(_.numRegSrc).max).max
69  def numVecRegSrc: Int = allSchdParams.map(_.issueBlockParams.map(_.numVecSrc).max).max
70
71
72  def AluCnt = allSchdParams.map(_.AluCnt).sum
73  def StaCnt = allSchdParams.map(_.StaCnt).sum
74  def StdCnt = allSchdParams.map(_.StdCnt).sum
75  def LduCnt = allSchdParams.map(_.LduCnt).sum
76  def HyuCnt = allSchdParams.map(_.HyuCnt).sum
77  def VlduCnt = allSchdParams.map(_.VlduCnt).sum
78  def VstuCnt = allSchdParams.map(_.VstuCnt).sum
79  def LsExuCnt = StaCnt + LduCnt + HyuCnt
80  val LdExuCnt = LduCnt + HyuCnt
81  def JmpCnt = allSchdParams.map(_.JmpCnt).sum
82  def BrhCnt = allSchdParams.map(_.BrhCnt).sum
83  def CsrCnt = allSchdParams.map(_.CsrCnt).sum
84  def IqCnt = allSchdParams.map(_.issueBlockParams.length).sum
85
86  def numPcReadPort = allSchdParams.map(_.numPcReadPort).sum
87  def numTargetReadPort = allRealExuParams.count(x => x.needTarget)
88
89  def numPregRd(dataCfg: DataConfig) = this.getRfReadSize(dataCfg)
90  def numPregWb(dataCfg: DataConfig) = this.getRfWriteSize(dataCfg)
91
92  def numNoDataWB = allSchdParams.map(_.numNoDataWB).sum
93  def numExu = allSchdParams.map(_.numExu).sum
94  def vconfigPort = 0 // Todo: remove it
95
96  def numException = allRealExuParams.count(_.exceptionOut.nonEmpty)
97
98  def numRedirect = allSchdParams.map(_.numRedirect).sum
99
100  def genIntWriteBackBundle(implicit p: Parameters) = {
101    Seq.fill(this.getIntRfWriteSize)(new RfWritePortWithConfig(IntData(), intPregParams.addrWidth))
102  }
103
104  def genVfWriteBackBundle(implicit p: Parameters) = {
105    Seq.fill(this.getVfRfWriteSize)(new RfWritePortWithConfig(VecData(), vfPregParams.addrWidth))
106  }
107
108  def genWriteBackBundles(implicit p: Parameters): Seq[RfWritePortWithConfig] = {
109    genIntWriteBackBundle ++ genVfWriteBackBundle
110  }
111
112  def genWrite2CtrlBundles(implicit p: Parameters): MixedVec[ValidIO[ExuOutput]] = {
113    MixedVec(allSchdParams.map(_.genExuOutputValidBundle.flatten).flatten)
114  }
115
116  def getIntWbArbiterParams: WbArbiterParams = {
117    val intWbCfgs: Seq[IntWB] = allSchdParams.flatMap(_.getWbCfgs.flatten.flatten.filter(_.writeInt)).map(_.asInstanceOf[IntWB])
118    datapath.WbArbiterParams(intWbCfgs, intPregParams, this)
119  }
120
121  def getVfWbArbiterParams: WbArbiterParams = {
122    val vfWbCfgs: Seq[VfWB] = allSchdParams.flatMap(_.getWbCfgs.flatten.flatten.filter(x => x.writeVec || x.writeFp)).map(_.asInstanceOf[VfWB])
123    datapath.WbArbiterParams(vfWbCfgs, vfPregParams, this)
124  }
125
126  /**
127    * Get regfile read port params
128    *
129    * @param dataCfg [[IntData]] or [[VecData]]
130    * @return Seq[port->Seq[(exuIdx, priority)]
131    */
132  def getRdPortParams(dataCfg: DataConfig) = {
133    // port -> Seq[exuIdx, priority]
134    val cfgs: Seq[(Int, Seq[(Int, Int)])] = allRealExuParams
135      .flatMap(x => x.rfrPortConfigs.flatten.map(xx => (xx, x.exuIdx)))
136      .filter { x => x._1.getDataConfig == dataCfg }
137      .map(x => (x._1.port, (x._2, x._1.priority)))
138      .groupBy(_._1)
139      .map(x => (x._1, x._2.map(_._2).sortBy({ case (priority, _) => priority })))
140      .toSeq
141      .sortBy(_._1)
142    cfgs
143  }
144
145  /**
146    * Get regfile write back port params
147    *
148    * @param dataCfg [[IntData]] or [[VecData]]
149    * @return Seq[port->Seq[(exuIdx, priority)]
150    */
151  def getWbPortParams(dataCfg: DataConfig) = {
152    val cfgs: Seq[(Int, Seq[(Int, Int)])] = allRealExuParams
153      .flatMap(x => x.wbPortConfigs.map(xx => (xx, x.exuIdx)))
154      .filter { x => x._1.dataCfg == dataCfg }
155      .map(x => (x._1.port, (x._2, x._1.priority)))
156      .groupBy(_._1)
157      .map(x => (x._1, x._2.map(_._2)))
158      .toSeq
159      .sortBy(_._1)
160    cfgs
161  }
162
163  def getRdPortIndices(dataCfg: DataConfig) = {
164    this.getRdPortParams(dataCfg).map(_._1)
165  }
166
167  def getWbPortIndices(dataCfg: DataConfig) = {
168    this.getWbPortParams(dataCfg).map(_._1)
169  }
170
171  def getRdCfgs[T <: RdConfig](implicit tag: ClassTag[T]): Seq[Seq[Seq[RdConfig]]] = {
172    val rdCfgs: Seq[Seq[Seq[RdConfig]]] = allIssueParams.map(
173      _.exuBlockParams.map(
174        _.rfrPortConfigs.map(
175          _.collectFirst{ case x: T => x }
176            .getOrElse(NoRD())
177        )
178      )
179    )
180    rdCfgs
181  }
182
183  def getAllWbCfgs: Seq[Seq[Set[PregWB]]] = {
184    allIssueParams.map(_.exuBlockParams.map(_.wbPortConfigs.toSet))
185  }
186
187  def getWbCfgs[T <: PregWB](implicit tag: ClassTag[T]): Seq[Seq[PregWB]] = {
188    val wbCfgs: Seq[Seq[PregWB]] = allIssueParams.map(_.exuBlockParams.map(_.wbPortConfigs.collectFirst{ case x: T => x }.getOrElse(NoWB())))
189    wbCfgs
190  }
191
192  /**
193    * Get size of read ports of int regfile
194    *
195    * @return if [[IntPregParams.numRead]] is [[None]], get size of ports in [[IntRD]]
196    */
197  def getIntRfReadSize = {
198    this.intPregParams.numRead.getOrElse(this.getRdPortIndices(IntData()).size)
199  }
200
201  /**
202    * Get size of write ports of vf regfile
203    *
204    * @return if [[IntPregParams.numWrite]] is [[None]], get size of ports in [[IntWB]]
205    */
206  def getIntRfWriteSize = {
207    this.intPregParams.numWrite.getOrElse(this.getWbPortIndices(IntData()).size)
208  }
209
210  /**
211    * Get size of read ports of int regfile
212    *
213    * @return if [[VfPregParams.numRead]] is [[None]], get size of ports in [[VfRD]]
214    */
215  def getVfRfReadSize = {
216    this.vfPregParams.numRead.getOrElse(this.getRdPortIndices(VecData()).size)
217  }
218
219  /**
220    * Get size of write ports of vf regfile
221    *
222    * @return if [[VfPregParams.numWrite]] is [[None]], get size of ports in [[VfWB]]
223    */
224  def getVfRfWriteSize = {
225    this.vfPregParams.numWrite.getOrElse(this.getWbPortIndices(VecData()).size)
226  }
227
228  def getRfReadSize(dataCfg: DataConfig) = {
229    this.getPregParams(dataCfg).numRead.getOrElse(this.getRdPortIndices(dataCfg).size)
230  }
231
232  def getRfWriteSize(dataCfg: DataConfig) = {
233    this.getPregParams(dataCfg).numWrite.getOrElse(this.getWbPortIndices(dataCfg).size)
234  }
235
236  def getExuIdx(name: String): Int = {
237    val exuParams = allRealExuParams
238    if (name != "WB") {
239      val foundExu = exuParams.find(_.name == name)
240      require(foundExu.nonEmpty, s"exu $name not find")
241      foundExu.get.exuIdx
242    } else
243      -1
244  }
245
246  def getExuName(idx: Int): String = {
247    val exuParams = allRealExuParams
248    exuParams(idx).name
249  }
250
251  def getLdExuIdx(exu: ExeUnitParams): Int = {
252    val ldExuParams = allRealExuParams.filter(x => x.hasHyldaFu || x.hasLoadFu)
253    ldExuParams.indexOf(exu)
254  }
255
256  def getIntWBExeGroup: Map[Int, Seq[ExeUnitParams]] = allRealExuParams.groupBy(x => x.getIntWBPort.getOrElse(IntWB(port = -1)).port).filter(_._1 != -1)
257  def getVfWBExeGroup: Map[Int, Seq[ExeUnitParams]] = allRealExuParams.groupBy(x => x.getVfWBPort.getOrElse(VfWB(port = -1)).port).filter(_._1 != -1)
258
259  private def isContinuous(portIndices: Seq[Int]): Boolean = {
260    val portIndicesSet = portIndices.toSet
261    portIndicesSet.min == 0 && portIndicesSet.max == portIndicesSet.size - 1
262  }
263
264  def configChecks = {
265    checkReadPortContinuous
266    checkWritePortContinuous
267    configCheck
268  }
269
270  def checkReadPortContinuous = {
271    pregParams.foreach { x =>
272      if (x.numRead.isEmpty) {
273        val portIndices: Seq[Int] = getRdPortIndices(x.dataCfg)
274        require(isContinuous(portIndices),
275          s"The read ports of ${x.getClass.getSimpleName} should be continuous, " +
276            s"when numRead of ${x.getClass.getSimpleName} is None. The read port indices are $portIndices")
277      }
278    }
279  }
280
281  def checkWritePortContinuous = {
282    pregParams.foreach { x =>
283      if (x.numWrite.isEmpty) {
284        val portIndices: Seq[Int] = getWbPortIndices(x.dataCfg)
285        require(
286          isContinuous(portIndices),
287          s"The write ports of ${x.getClass.getSimpleName} should be continuous, " +
288            s"when numWrite of ${x.getClass.getSimpleName} is None. The write port indices are $portIndices"
289        )
290      }
291    }
292  }
293
294  def configCheck = {
295    // check 0
296    val maxPortSource = 4
297
298    allRealExuParams.map {
299      case exuParam => exuParam.wbPortConfigs.collectFirst { case x: IntWB => x }
300    }.filter(_.isDefined).groupBy(_.get.port).foreach {
301      case (wbPort, priorities) => assert(priorities.size <= maxPortSource, "There has " + priorities.size + " exu's " + "Int WBport is " + wbPort + ", but the maximum is " + maxPortSource + ".")
302    }
303    allRealExuParams.map {
304      case exuParam => exuParam.wbPortConfigs.collectFirst { case x: VfWB => x }
305    }.filter(_.isDefined).groupBy(_.get.port).foreach {
306      case (wbPort, priorities) => assert(priorities.size <= maxPortSource, "There has " + priorities.size + " exu's " + "Vf  WBport is " + wbPort + ", but the maximum is " + maxPortSource + ".")
307    }
308
309    // check 1
310    val wbTypes = Seq(IntWB(), VfWB())
311    val rdTypes = Seq(IntRD(), VfRD())
312    for(wbType <- wbTypes){
313      for(rdType <- rdTypes){
314        allRealExuParams.map {
315          case exuParam =>
316            val wbPortConfigs = exuParam.wbPortConfigs
317            val wbConfigs = wbType match{
318              case _: IntWB => wbPortConfigs.collectFirst { case x: IntWB => x }
319              case _: VfWB  => wbPortConfigs.collectFirst { case x: VfWB => x }
320              case _        => None
321            }
322            val rfReadPortConfigs = exuParam.rfrPortConfigs
323            val rdConfigs = rdType match{
324              case _: IntRD => rfReadPortConfigs.flatten.filter(_.isInstanceOf[IntRD])
325              case _: VfRD  => rfReadPortConfigs.flatten.filter(_.isInstanceOf[VfRD])
326              case _        => Seq()
327            }
328            (wbConfigs, rdConfigs)
329        }.filter(_._1.isDefined)
330          .sortBy(_._1.get.priority)
331          .groupBy(_._1.get.port).map {
332            case (_, intWbRdPairs) =>
333              intWbRdPairs.map(_._2).flatten
334        }.map(rdCfgs => rdCfgs.groupBy(_.port).foreach {
335          case (_, rdCfgs) =>
336            rdCfgs.zip(rdCfgs.drop(1)).foreach { case (cfg0, cfg1) => assert(cfg0.priority <= cfg1.priority) }
337        })
338      }
339    }
340  }
341}
342