xref: /XiangShan/src/main/scala/xiangshan/backend/Bundles.scala (revision 1592abd11eecf7bec0f1453ffe4a7617167f8ba9)
1package xiangshan.backend
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util.BitPat.bitPatToUInt
6import chisel3.util._
7import utils.BundleUtils.makeValid
8import utils.OptionWrapper
9import xiangshan._
10import xiangshan.backend.datapath.DataConfig._
11import xiangshan.backend.datapath.DataSource
12import xiangshan.backend.datapath.WbConfig.PregWB
13import xiangshan.backend.decode.{ImmUnion, XDecode}
14import xiangshan.backend.exu.ExeUnitParams
15import xiangshan.backend.fu.FuType
16import xiangshan.backend.fu.fpu.Bundles.Frm
17import xiangshan.backend.fu.vector.Bundles._
18import xiangshan.backend.issue.{IssueBlockParams, IssueQueueDeqRespBundle, SchedulerType}
19import xiangshan.backend.issue.EntryBundles._
20import xiangshan.backend.regfile.{RfReadPortWithConfig, RfWritePortWithConfig}
21import xiangshan.backend.rob.RobPtr
22import xiangshan.frontend._
23import xiangshan.mem.{LqPtr, SqPtr}
24import yunsuan.vector.VIFuParam
25import xiangshan.backend.trace._
26import utility._
27
28object Bundles {
29  /**
30   * Connect Same Name Port like bundleSource := bundleSinkBudle.
31   *
32   * There is no limit to the number of ports on both sides.
33   *
34   * Don't forget to connect the remaining ports!
35   */
36  def connectSamePort (bundleSource: Bundle, bundleSink: Bundle):Unit = {
37    bundleSource.elements.foreach { case (name, data) =>
38      if (bundleSink.elements.contains(name))
39        data := bundleSink.elements(name)
40    }
41  }
42  // frontend -> backend
43  class StaticInst(implicit p: Parameters) extends XSBundle {
44    val instr            = UInt(32.W)
45    val pc               = UInt(VAddrBits.W)
46    val foldpc           = UInt(MemPredPCWidth.W)
47    val exceptionVec     = ExceptionVec()
48    val isFetchMalAddr   = Bool()
49    val trigger          = TriggerAction()
50    val preDecodeInfo    = new PreDecodeInfo
51    val pred_taken       = Bool()
52    val crossPageIPFFix  = Bool()
53    val ftqPtr           = new FtqPtr
54    val ftqOffset        = UInt(log2Up(PredictWidth).W)
55    val isLastInFtqEntry = Bool()
56    val debug_seqNum     = InstSeqNum()
57
58    def connectCtrlFlow(source: CtrlFlow): Unit = {
59      this.instr            := source.instr
60      this.pc               := source.pc
61      this.foldpc           := source.foldpc
62      this.exceptionVec     := source.exceptionVec
63      this.isFetchMalAddr   := source.backendException
64      this.trigger          := source.trigger
65      this.preDecodeInfo    := source.pd
66      this.pred_taken       := source.pred_taken
67      this.crossPageIPFFix  := source.crossPageIPFFix
68      this.ftqPtr           := source.ftqPtr
69      this.ftqOffset        := source.ftqOffset
70      this.isLastInFtqEntry := source.isLastInFtqEntry
71      this.debug_seqNum     := source.debug_seqNum
72    }
73  }
74
75  // StaticInst --[Decode]--> DecodedInst
76  class DecodedInst(implicit p: Parameters) extends XSBundle {
77    def numSrc = backendParams.numSrc
78    // passed from StaticInst
79    val instr           = UInt(32.W)
80    val pc              = UInt(VAddrBits.W)
81    val foldpc          = UInt(MemPredPCWidth.W)
82    val exceptionVec    = ExceptionVec()
83    val isFetchMalAddr  = Bool()
84    val trigger         = TriggerAction()
85    val preDecodeInfo   = new PreDecodeInfo
86    val pred_taken      = Bool()
87    val crossPageIPFFix = Bool()
88    val ftqPtr          = new FtqPtr
89    val ftqOffset       = UInt(log2Up(PredictWidth).W)
90    // decoded
91    val srcType         = Vec(numSrc, SrcType())
92    val lsrc            = Vec(numSrc, UInt(LogicRegsWidth.W))
93    val ldest           = UInt(LogicRegsWidth.W)
94    val fuType          = FuType()
95    val fuOpType        = FuOpType()
96    val rfWen           = Bool()
97    val fpWen           = Bool()
98    val vecWen          = Bool()
99    val v0Wen           = Bool()
100    val vlWen           = Bool()
101    val isXSTrap        = Bool()
102    val waitForward     = Bool() // no speculate execution
103    val blockBackward   = Bool()
104    val flushPipe       = Bool() // This inst will flush all the pipe when commit, like exception but can commit
105    val canRobCompress  = Bool()
106    val selImm          = SelImm()
107    val imm             = UInt(ImmUnion.maxLen.W)
108    val fpu             = new FPUCtrlSignals
109    val vpu             = new VPUCtrlSignals
110    val vlsInstr        = Bool()
111    val wfflags         = Bool()
112    val isMove          = Bool()
113    val uopIdx          = UopIdx()
114    val uopSplitType    = UopSplitType()
115    val isVset          = Bool()
116    val firstUop        = Bool()
117    val lastUop         = Bool()
118    val numUops         = UInt(log2Up(MaxUopSize).W) // rob need this
119    val numWB           = UInt(log2Up(MaxUopSize).W) // rob need this
120    val commitType      = CommitType() // Todo: remove it
121    val needFrm         = new NeedFrmBundle
122
123    val debug_fuType    = OptionWrapper(backendParams.debugEn, FuType())
124    val debug_seqNum    = InstSeqNum()
125
126    private def allSignals = srcType.take(3) ++ Seq(fuType, fuOpType, rfWen, fpWen, vecWen,
127      isXSTrap, waitForward, blockBackward, flushPipe, canRobCompress, uopSplitType, selImm)
128
129    def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]): DecodedInst = {
130      val decoder: Seq[UInt] = ListLookup(
131        inst, XDecode.decodeDefault.map(bitPatToUInt),
132        table.map{ case (pat, pats) => (pat, pats.map(bitPatToUInt)) }.toArray
133      )
134      allSignals zip decoder foreach { case (s, d) => s := d }
135      debug_fuType.foreach(_ := fuType)
136      this
137    }
138
139    def isSoftPrefetch: Bool = {
140      fuType === FuType.alu.U && fuOpType === ALUOpType.or && selImm === SelImm.IMM_I && ldest === 0.U
141    }
142
143    def connectStaticInst(source: StaticInst): Unit = {
144      for ((name, data) <- this.elements) {
145        if (source.elements.contains(name)) {
146          data := source.elements(name)
147        }
148      }
149    }
150  }
151
152  class TrapInstInfo(implicit p: Parameters) extends XSBundle {
153    val instr = UInt(32.W)
154    val ftqPtr = new FtqPtr
155    val ftqOffset = UInt(log2Up(PredictWidth).W)
156
157    def needFlush(ftqPtr: FtqPtr, ftqOffset: UInt): Bool ={
158      val sameFlush = this.ftqPtr === ftqPtr && this.ftqOffset > ftqOffset
159      sameFlush || isAfter(this.ftqPtr, ftqPtr)
160    }
161
162    def fromDecodedInst(decodedInst: DecodedInst): this.type = {
163      this.instr     := decodedInst.instr
164      this.ftqPtr    := decodedInst.ftqPtr
165      this.ftqOffset := decodedInst.ftqOffset
166      this
167    }
168  }
169
170  // DecodedInst --[Rename]--> DynInst
171  class DynInst(implicit p: Parameters) extends XSBundle {
172    def numSrc          = backendParams.numSrc
173    // passed from StaticInst
174    val instr           = UInt(32.W)
175    val pc              = UInt(VAddrBits.W)
176    val foldpc          = UInt(MemPredPCWidth.W)
177    val exceptionVec    = ExceptionVec()
178    val isFetchMalAddr  = Bool()
179    val hasException    = Bool()
180    val trigger         = TriggerAction()
181    val preDecodeInfo   = new PreDecodeInfo
182    val pred_taken      = Bool()
183    val crossPageIPFFix = Bool()
184    val ftqPtr          = new FtqPtr
185    val ftqOffset       = UInt(log2Up(PredictWidth).W)
186    // passed from DecodedInst
187    val srcType         = Vec(numSrc, SrcType())
188    val ldest           = UInt(LogicRegsWidth.W)
189    val fuType          = FuType()
190    val fuOpType        = FuOpType()
191    val rfWen           = Bool()
192    val fpWen           = Bool()
193    val vecWen          = Bool()
194    val v0Wen           = Bool()
195    val vlWen           = Bool()
196    val isXSTrap        = Bool()
197    val waitForward     = Bool() // no speculate execution
198    val blockBackward   = Bool()
199    val flushPipe       = Bool() // This inst will flush all the pipe when commit, like exception but can commit
200    val canRobCompress  = Bool()
201    val selImm          = SelImm()
202    val imm             = UInt(32.W)
203    val fpu             = new FPUCtrlSignals
204    val vpu             = new VPUCtrlSignals
205    val vlsInstr        = Bool()
206    val wfflags         = Bool()
207    val isMove          = Bool()
208    val isDropAmocasSta = Bool()
209    val uopIdx          = UopIdx()
210    val isVset          = Bool()
211    val firstUop        = Bool()
212    val lastUop         = Bool()
213    val numUops         = UInt(log2Up(MaxUopSize).W) // rob need this
214    val numWB           = UInt(log2Up(MaxUopSize).W) // rob need this
215    val commitType      = CommitType()
216    // rename
217    val srcState        = Vec(numSrc, SrcState())
218    val srcLoadDependency  = Vec(numSrc, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W)))
219    val psrc            = Vec(numSrc, UInt(PhyRegIdxWidth.W))
220    val pdest           = UInt(PhyRegIdxWidth.W)
221    // reg cache
222    val useRegCache     = Vec(backendParams.numIntRegSrc, Bool())
223    val regCacheIdx     = Vec(backendParams.numIntRegSrc, UInt(RegCacheIdxWidth.W))
224    val robIdx          = new RobPtr
225    val instrSize       = UInt(log2Ceil(RenameWidth + 1).W)
226    val dirtyFs         = Bool()
227    val dirtyVs         = Bool()
228    val traceBlockInPipe = new TracePipe(IretireWidthInPipe)
229
230    val eliminatedMove  = Bool()
231    // Take snapshot at this CFI inst
232    val snapshot        = Bool()
233    val debugInfo       = new PerfDebugInfo
234    val debug_seqNum    = InstSeqNum()
235    val storeSetHit     = Bool() // inst has been allocated an store set
236    val waitForRobIdx   = new RobPtr // store set predicted previous store robIdx
237    // Load wait is needed
238    // load inst will not be executed until former store (predicted by mdp) addr calcuated
239    val loadWaitBit     = Bool()
240    // If (loadWaitBit && loadWaitStrict), strict load wait is needed
241    // load inst will not be executed until ALL former store addr calcuated
242    val loadWaitStrict  = Bool()
243    val ssid            = UInt(SSIDWidth.W)
244    // Todo
245    val lqIdx = new LqPtr
246    val sqIdx = new SqPtr
247    // debug module
248    val singleStep      = Bool()
249    // schedule
250    val replayInst      = Bool()
251
252    val debug_fuType    = OptionWrapper(backendParams.debugEn, FuType())
253
254    val numLsElem       = NumLsElem()
255
256    def getDebugFuType: UInt = debug_fuType.getOrElse(fuType)
257
258    def isLUI: Bool = this.fuType === FuType.alu.U && (this.selImm === SelImm.IMM_U || this.selImm === SelImm.IMM_LUI32)
259    def isLUI32: Bool = this.selImm === SelImm.IMM_LUI32
260    def isWFI: Bool = this.fuType === FuType.csr.U && fuOpType === CSROpType.wfi
261
262    def isSvinvalBegin(flush: Bool) = FuType.isFence(fuType) && fuOpType === FenceOpType.nofence && !flush
263    def isSvinval(flush: Bool) = FuType.isFence(fuType) &&
264      Cat(Seq(FenceOpType.sfence, FenceOpType.hfence_v, FenceOpType.hfence_g).map(_ === fuOpType)).orR && !flush
265    def isSvinvalEnd(flush: Bool) = FuType.isFence(fuType) && fuOpType === FenceOpType.nofence && flush
266    def isNotSvinval = !FuType.isFence(fuType)
267
268    def isHls: Bool = {
269      fuType === FuType.ldu.U && LSUOpType.isHlv(fuOpType) || fuType === FuType.stu.U && LSUOpType.isHsv(fuOpType)
270    }
271
272    def isAMOCAS: Bool = FuType.isAMO(fuType) && LSUOpType.isAMOCAS(fuOpType)
273
274    def srcIsReady: Vec[Bool] = {
275      VecInit(this.srcType.zip(this.srcState).map {
276        case (t, s) => SrcType.isNotReg(t) || SrcState.isReady(s)
277      })
278    }
279
280    def clearExceptions(
281      exceptionBits: Seq[Int] = Seq(),
282      flushPipe    : Boolean = false,
283      replayInst   : Boolean = false
284    ): DynInst = {
285      this.exceptionVec.zipWithIndex.filterNot(x => exceptionBits.contains(x._2)).foreach(_._1 := false.B)
286      if (!flushPipe) { this.flushPipe := false.B }
287      if (!replayInst) { this.replayInst := false.B }
288      this
289    }
290
291    def needWriteRf: Bool = rfWen || fpWen || vecWen || v0Wen || vlWen
292  }
293
294  trait BundleSource {
295    var wakeupSource = "undefined"
296    var idx = 0
297  }
298
299  /**
300    *
301    * @param pregIdxWidth index width of preg
302    * @param exuIndices exu indices of wakeup bundle
303    */
304  sealed abstract class IssueQueueWakeUpBaseBundle(pregIdxWidth: Int, val exuIndices: Seq[Int])(implicit p: Parameters) extends XSBundle {
305    val rfWen = Bool()
306    val fpWen = Bool()
307    val vecWen = Bool()
308    val v0Wen = Bool()
309    val vlWen = Bool()
310    val pdest = UInt(pregIdxWidth.W)
311
312    /**
313      * @param successor Seq[(psrc, srcType)]
314      * @return Seq[if wakeup psrc]
315      */
316    def wakeUp(successor: Seq[(UInt, UInt)], valid: Bool): Seq[Bool] = {
317      successor.map { case (thatPsrc, srcType) =>
318        val pdestMatch = pdest === thatPsrc
319        pdestMatch && (
320          SrcType.isFp(srcType) && this.fpWen ||
321            SrcType.isXp(srcType) && this.rfWen ||
322            SrcType.isVp(srcType) && this.vecWen
323          ) && valid
324      }
325    }
326    def wakeUpV0(successor: (UInt, UInt), valid: Bool): Bool = {
327      val (thatPsrc, srcType) = successor
328      val pdestMatch = pdest === thatPsrc
329      pdestMatch && (
330        SrcType.isV0(srcType) && this.v0Wen
331      ) && valid
332    }
333    def wakeUpVl(successor: (UInt, UInt), valid: Bool): Bool = {
334      val (thatPsrc, srcType) = successor
335      val pdestMatch = pdest === thatPsrc
336      pdestMatch && (
337        SrcType.isVp(srcType) && this.vlWen
338      ) && valid
339    }
340    def wakeUpFromIQ(successor: Seq[(UInt, UInt)]): Seq[Bool] = {
341      successor.map { case (thatPsrc, srcType) =>
342        val pdestMatch = pdest === thatPsrc
343        pdestMatch && (
344          SrcType.isFp(srcType) && this.fpWen ||
345            SrcType.isXp(srcType) && this.rfWen ||
346            SrcType.isVp(srcType) && this.vecWen
347          )
348      }
349    }
350    def wakeUpV0FromIQ(successor: (UInt, UInt)): Bool = {
351      val (thatPsrc, srcType) = successor
352      val pdestMatch = pdest === thatPsrc
353      pdestMatch && (
354        SrcType.isV0(srcType) && this.v0Wen
355      )
356    }
357    def wakeUpVlFromIQ(successor: (UInt, UInt)): Bool = {
358      val (thatPsrc, srcType) = successor
359      val pdestMatch = pdest === thatPsrc
360      pdestMatch && (
361        SrcType.isVp(srcType) && this.vlWen
362      )
363    }
364
365    def hasOnlyOneSource: Boolean = exuIndices.size == 1
366
367    def hasMultiSources: Boolean = exuIndices.size > 1
368
369    def isWBWakeUp = this.isInstanceOf[IssueQueueWBWakeUpBundle]
370
371    def isIQWakeUp = this.isInstanceOf[IssueQueueIQWakeUpBundle]
372
373    def exuIdx: Int = {
374      require(hasOnlyOneSource)
375      this.exuIndices.head
376    }
377  }
378
379  class IssueQueueWBWakeUpBundle(exuIndices: Seq[Int], backendParams: BackendParams)(implicit p: Parameters) extends IssueQueueWakeUpBaseBundle(backendParams.pregIdxWidth, exuIndices) {
380
381  }
382
383  class IssueQueueIQWakeUpBundle(
384    exuIdx: Int,
385    backendParams: BackendParams,
386    copyWakeupOut: Boolean = false,
387    copyNum: Int = 0
388  )(implicit p: Parameters) extends IssueQueueWakeUpBaseBundle(backendParams.pregIdxWidth, Seq(exuIdx)) {
389    val loadDependency = Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W))
390    val is0Lat = Bool()
391    val params = backendParams.allExuParams.filter(_.exuIdx == exuIdx).head
392    val rcDest = OptionWrapper(params.needWriteRegCache, UInt(RegCacheIdxWidth.W))
393    val pdestCopy  = OptionWrapper(copyWakeupOut, Vec(copyNum, UInt(params.wbPregIdxWidth.W)))
394    val rfWenCopy  = OptionWrapper(copyWakeupOut && params.needIntWen, Vec(copyNum, Bool()))
395    val fpWenCopy  = OptionWrapper(copyWakeupOut && params.needFpWen, Vec(copyNum, Bool()))
396    val vecWenCopy = OptionWrapper(copyWakeupOut && params.needVecWen, Vec(copyNum, Bool()))
397    val v0WenCopy = OptionWrapper(copyWakeupOut && params.needV0Wen, Vec(copyNum, Bool()))
398    val vlWenCopy = OptionWrapper(copyWakeupOut && params.needVlWen, Vec(copyNum, Bool()))
399    val loadDependencyCopy = OptionWrapper(copyWakeupOut && params.isIQWakeUpSink, Vec(copyNum, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W))))
400
401    def fromExuInput(exuInput: ExuInput): Unit = {
402      this.rfWen := exuInput.rfWen.getOrElse(false.B)
403      this.fpWen := exuInput.fpWen.getOrElse(false.B)
404      this.vecWen := exuInput.vecWen.getOrElse(false.B)
405      this.v0Wen := exuInput.v0Wen.getOrElse(false.B)
406      this.vlWen := exuInput.vlWen.getOrElse(false.B)
407      this.pdest := exuInput.pdest
408    }
409  }
410
411  class VPUCtrlSignals(implicit p: Parameters) extends XSBundle {
412    // vtype
413    val vill      = Bool()
414    val vma       = Bool()    // 1: agnostic, 0: undisturbed
415    val vta       = Bool()    // 1: agnostic, 0: undisturbed
416    val vsew      = VSew()
417    val vlmul     = VLmul()   // 1/8~8      --> -3~3
418
419    // spec vtype
420    val specVill  = Bool()
421    val specVma   = Bool()    // 1: agnostic, 0: undisturbed
422    val specVta   = Bool()    // 1: agnostic, 0: undisturbed
423    val specVsew  = VSew()
424    val specVlmul = VLmul()   // 1/8~8      --> -3~3
425
426    val vm        = Bool()    // 0: need v0.t
427    val vstart    = Vl()
428
429    // float rounding mode
430    val frm       = Frm()
431    // scalar float instr and vector float reduction
432    val fpu       = Fpu()
433    // vector fix int rounding mode
434    val vxrm      = Vxrm()
435    // vector uop index, exclude other non-vector uop
436    val vuopIdx   = UopIdx()
437    val lastUop   = Bool()
438    // maybe used if data dependancy
439    val vmask     = UInt(V0Data().dataWidth.W)
440    val vl        = Vl()
441
442    // vector load/store
443    val nf        = Nf()
444    val veew      = VEew()
445
446    val isReverse = Bool() // vrsub, vrdiv
447    val isExt     = Bool()
448    val isNarrow  = Bool()
449    val isDstMask = Bool() // vvm, vvvm, mmm
450    val isOpMask  = Bool() // vmand, vmnand
451    val isMove    = Bool() // vmv.s.x, vmv.v.v, vmv.v.x, vmv.v.i
452
453    val isDependOldVd = Bool() // some instruction's computation depends on oldvd
454    val isWritePartVd = Bool() // some instruction's computation writes part of vd, such as vredsum
455
456    val isVleff = Bool() // vleff
457
458    def vtype: VType = {
459      val res = Wire(VType())
460      res.illegal := this.vill
461      res.vma     := this.vma
462      res.vta     := this.vta
463      res.vsew    := this.vsew
464      res.vlmul   := this.vlmul
465      res
466    }
467
468    def specVType: VType = {
469      val res = Wire(VType())
470      res.illegal := this.specVill
471      res.vma     := this.specVma
472      res.vta     := this.specVta
473      res.vsew    := this.specVsew
474      res.vlmul   := this.specVlmul
475      res
476    }
477
478    def vconfig: VConfig = {
479      val res = Wire(VConfig())
480      res.vtype := this.vtype
481      res.vl    := this.vl
482      res
483    }
484
485    def connectVType(source: VType): Unit = {
486      this.vill  := source.illegal
487      this.vma   := source.vma
488      this.vta   := source.vta
489      this.vsew  := source.vsew
490      this.vlmul := source.vlmul
491    }
492  }
493
494  class NeedFrmBundle(implicit p: Parameters) extends XSBundle {
495    val scalaNeedFrm = Bool()
496    val vectorNeedFrm = Bool()
497  }
498
499  // DynInst --[IssueQueue]--> DataPath
500  class IssueQueueIssueBundle(
501    iqParams: IssueBlockParams,
502    val exuParams: ExeUnitParams,
503  )(implicit
504    p: Parameters
505  ) extends XSBundle {
506    private val rfReadDataCfgSet: Seq[Set[DataConfig]] = exuParams.getRfReadDataCfgSet
507
508    val rf: MixedVec[MixedVec[RfReadPortWithConfig]] = Flipped(MixedVec(
509      rfReadDataCfgSet.map((set: Set[DataConfig]) =>
510        MixedVec(set.map((x: DataConfig) => new RfReadPortWithConfig(x, exuParams.rdPregIdxWidth)).toSeq)
511      )
512    ))
513
514    val srcType = Vec(exuParams.numRegSrc, SrcType()) // used to select imm or reg data
515    val rcIdx = OptionWrapper(exuParams.needReadRegCache, Vec(exuParams.numRegSrc, UInt(RegCacheIdxWidth.W))) // used to select regcache data
516    val immType = SelImm()                         // used to select imm extractor
517    val common = new ExuInput(exuParams)
518    val addrOH = UInt(iqParams.numEntries.W)
519
520    def exuIdx = exuParams.exuIdx
521    def getSource: SchedulerType = exuParams.getWBSource
522
523    def getRfReadValidBundle(issueValid: Bool): Seq[ValidIO[RfReadPortWithConfig]] = {
524      rf.zip(srcType).map {
525        case (rfRd: MixedVec[RfReadPortWithConfig], t: UInt) =>
526          makeValid(issueValid, rfRd.head)
527      }.toSeq
528    }
529  }
530
531  class OGRespBundle(implicit p:Parameters, params: IssueBlockParams) extends XSBundle {
532    val issueQueueParams = this.params
533    val og0resp = Valid(new EntryDeqRespBundle)
534    val og1resp = Valid(new EntryDeqRespBundle)
535  }
536
537  class WbFuBusyTableWriteBundle(val params: ExeUnitParams)(implicit p: Parameters) extends XSBundle {
538    private val intCertainLat = params.intLatencyCertain
539    private val fpCertainLat = params.fpLatencyCertain
540    private val vfCertainLat = params.vfLatencyCertain
541    private val v0CertainLat = params.v0LatencyCertain
542    private val vlCertainLat = params.vlLatencyCertain
543    private val intLat = params.intLatencyValMax
544    private val fpLat = params.fpLatencyValMax
545    private val vfLat = params.vfLatencyValMax
546    private val v0Lat = params.v0LatencyValMax
547    private val vlLat = params.vlLatencyValMax
548
549    val intWbBusyTable = OptionWrapper(intCertainLat, UInt((intLat + 1).W))
550    val fpWbBusyTable = OptionWrapper(fpCertainLat, UInt((fpLat + 1).W))
551    val vfWbBusyTable = OptionWrapper(vfCertainLat, UInt((vfLat + 1).W))
552    val v0WbBusyTable = OptionWrapper(v0CertainLat, UInt((v0Lat + 1).W))
553    val vlWbBusyTable = OptionWrapper(vlCertainLat, UInt((vlLat + 1).W))
554    val intDeqRespSet = OptionWrapper(intCertainLat, UInt((intLat + 1).W))
555    val fpDeqRespSet = OptionWrapper(fpCertainLat, UInt((fpLat + 1).W))
556    val vfDeqRespSet = OptionWrapper(vfCertainLat, UInt((vfLat + 1).W))
557    val v0DeqRespSet = OptionWrapper(v0CertainLat, UInt((v0Lat + 1).W))
558    val vlDeqRespSet = OptionWrapper(vlCertainLat, UInt((vlLat + 1).W))
559  }
560
561  class WbFuBusyTableReadBundle(val params: ExeUnitParams)(implicit p: Parameters) extends XSBundle {
562    private val intCertainLat = params.intLatencyCertain
563    private val fpCertainLat = params.fpLatencyCertain
564    private val vfCertainLat = params.vfLatencyCertain
565    private val v0CertainLat = params.v0LatencyCertain
566    private val vlCertainLat = params.vlLatencyCertain
567    private val intLat = params.intLatencyValMax
568    private val fpLat = params.fpLatencyValMax
569    private val vfLat = params.vfLatencyValMax
570    private val v0Lat = params.v0LatencyValMax
571    private val vlLat = params.vlLatencyValMax
572
573    val intWbBusyTable = OptionWrapper(intCertainLat, UInt((intLat + 1).W))
574    val fpWbBusyTable = OptionWrapper(fpCertainLat, UInt((fpLat + 1).W))
575    val vfWbBusyTable = OptionWrapper(vfCertainLat, UInt((vfLat + 1).W))
576    val v0WbBusyTable = OptionWrapper(v0CertainLat, UInt((v0Lat + 1).W))
577    val vlWbBusyTable = OptionWrapper(vlCertainLat, UInt((vlLat + 1).W))
578  }
579
580  class WbConflictBundle(val params: ExeUnitParams)(implicit p: Parameters) extends XSBundle {
581    private val intCertainLat = params.intLatencyCertain
582    private val fpCertainLat = params.fpLatencyCertain
583    private val vfCertainLat = params.vfLatencyCertain
584    private val v0CertainLat = params.v0LatencyCertain
585    private val vlCertainLat = params.vlLatencyCertain
586
587    val intConflict = OptionWrapper(intCertainLat, Bool())
588    val fpConflict = OptionWrapper(fpCertainLat, Bool())
589    val vfConflict = OptionWrapper(vfCertainLat, Bool())
590    val v0Conflict = OptionWrapper(v0CertainLat, Bool())
591    val vlConflict = OptionWrapper(vlCertainLat, Bool())
592  }
593
594  class ImmInfo extends Bundle {
595    val imm = UInt(32.W)
596    val immType = SelImm()
597  }
598
599  // DataPath --[ExuInput]--> Exu
600  class ExuInput(val params: ExeUnitParams, copyWakeupOut:Boolean = false, copyNum:Int = 0, hasCopySrc: Boolean = false)(implicit p: Parameters) extends XSBundle {
601    val fuType        = FuType()
602    val fuOpType      = FuOpType()
603    val src           = Vec(params.numRegSrc, UInt(params.srcDataBitsMax.W))
604    val copySrc       = if(hasCopySrc) Some(Vec(params.numCopySrc, Vec(if(params.numRegSrc < 2) 1 else 2, UInt(params.srcDataBitsMax.W)))) else None
605    val imm           = UInt(64.W)
606    val nextPcOffset  = OptionWrapper(params.hasBrhFu, UInt((log2Up(PredictWidth) + 1).W))
607    val robIdx        = new RobPtr
608    val iqIdx         = UInt(log2Up(MemIQSizeMax).W)// Only used by store yet
609    val isFirstIssue  = Bool()                      // Only used by store yet
610    val pdestCopy  = OptionWrapper(copyWakeupOut, Vec(copyNum, UInt(params.wbPregIdxWidth.W)))
611    val rfWenCopy  = OptionWrapper(copyWakeupOut && params.needIntWen, Vec(copyNum, Bool()))
612    val fpWenCopy  = OptionWrapper(copyWakeupOut && params.needFpWen, Vec(copyNum, Bool()))
613    val vecWenCopy = OptionWrapper(copyWakeupOut && params.needVecWen, Vec(copyNum, Bool()))
614    val v0WenCopy  = OptionWrapper(copyWakeupOut && params.needV0Wen, Vec(copyNum, Bool()))
615    val vlWenCopy  = OptionWrapper(copyWakeupOut && params.needVlWen, Vec(copyNum, Bool()))
616    val loadDependencyCopy = OptionWrapper(copyWakeupOut && params.isIQWakeUpSink, Vec(copyNum, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W))))
617    val pdest         = UInt(params.wbPregIdxWidth.W)
618    val rfWen         = if (params.needIntWen)    Some(Bool())                        else None
619    val fpWen         = if (params.needFpWen)     Some(Bool())                        else None
620    val vecWen        = if (params.needVecWen)    Some(Bool())                        else None
621    val v0Wen         = if (params.needV0Wen)     Some(Bool())                        else None
622    val vlWen         = if (params.needVlWen)     Some(Bool())                        else None
623    val fpu           = if (params.writeFflags)   Some(new FPUCtrlSignals)            else None
624    val vpu           = if (params.needVPUCtrl)   Some(new VPUCtrlSignals)            else None
625    val flushPipe     = if (params.flushPipe)     Some(Bool())                        else None
626    val pc            = if (params.needPc)        Some(UInt(VAddrData().dataWidth.W)) else None
627    val preDecode     = if (params.hasPredecode)  Some(new PreDecodeInfo)             else None
628    val ftqIdx        = if (params.needPc || params.replayInst || params.hasStoreAddrFu || params.hasCSR)
629                                                  Some(new FtqPtr)                    else None
630    val ftqOffset     = if (params.needPc || params.replayInst || params.hasStoreAddrFu || params.hasCSR)
631                                                  Some(UInt(log2Up(PredictWidth).W))  else None
632    val predictInfo   = if (params.needPdInfo)  Some(new Bundle {
633      val target = UInt(VAddrData().dataWidth.W)
634      val taken = Bool()
635    }) else None
636    val loadWaitBit    = OptionWrapper(params.hasLoadExu, Bool())
637    val waitForRobIdx  = OptionWrapper(params.hasLoadExu, new RobPtr) // store set predicted previous store robIdx
638    val storeSetHit    = OptionWrapper(params.hasLoadExu, Bool()) // inst has been allocated an store set
639    val loadWaitStrict = OptionWrapper(params.hasLoadExu, Bool()) // load inst will not be executed until ALL former store addr calcuated
640    val ssid           = OptionWrapper(params.hasLoadExu, UInt(SSIDWidth.W))
641    // only vector load store need
642    val numLsElem      = OptionWrapper(params.hasVecLsFu, NumLsElem())
643
644    val sqIdx = if (params.hasMemAddrFu || params.hasStdFu) Some(new SqPtr) else None
645    val lqIdx = if (params.hasMemAddrFu) Some(new LqPtr) else None
646    val dataSources = Vec(params.numRegSrc, DataSource())
647    val exuSources = OptionWrapper(params.isIQWakeUpSink, Vec(params.numRegSrc, ExuSource(params)))
648    val srcTimer = OptionWrapper(params.isIQWakeUpSink, Vec(params.numRegSrc, UInt(3.W)))
649    val loadDependency = OptionWrapper(params.needLoadDependency, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W)))
650
651    val perfDebugInfo = new PerfDebugInfo()
652    val debug_seqNum = InstSeqNum()
653
654    def exuIdx = this.params.exuIdx
655
656    def fromIssueBundle(source: IssueQueueIssueBundle): Unit = {
657      // src is assigned to rfReadData
658      this.fuType        := source.common.fuType
659      this.fuOpType      := source.common.fuOpType
660      this.imm           := source.common.imm
661      this.robIdx        := source.common.robIdx
662      this.pdest         := source.common.pdest
663      this.isFirstIssue  := source.common.isFirstIssue // Only used by mem debug log
664      this.iqIdx         := source.common.iqIdx        // Only used by mem feedback
665      this.dataSources   := source.common.dataSources
666      this.debug_seqNum  := source.common.debug_seqNum
667      this.exuSources    .foreach(_ := source.common.exuSources.get)
668      this.rfWen         .foreach(_ := source.common.rfWen.get)
669      this.fpWen         .foreach(_ := source.common.fpWen.get)
670      this.vecWen        .foreach(_ := source.common.vecWen.get)
671      this.v0Wen         .foreach(_ := source.common.v0Wen.get)
672      this.vlWen         .foreach(_ := source.common.vlWen.get)
673      this.fpu           .foreach(_ := source.common.fpu.get)
674      this.vpu           .foreach(_ := source.common.vpu.get)
675      this.flushPipe     .foreach(_ := source.common.flushPipe.get)
676      this.pc            .foreach(_ := source.common.pc.get)
677      this.preDecode     .foreach(_ := source.common.preDecode.get)
678      this.nextPcOffset  .foreach(_ := source.common.nextPcOffset.get)
679      this.ftqIdx        .foreach(_ := source.common.ftqIdx.get)
680      this.ftqOffset     .foreach(_ := source.common.ftqOffset.get)
681      this.predictInfo   .foreach(_ := source.common.predictInfo.get)
682      this.loadWaitBit   .foreach(_ := source.common.loadWaitBit.get)
683      this.waitForRobIdx .foreach(_ := source.common.waitForRobIdx.get)
684      this.storeSetHit   .foreach(_ := source.common.storeSetHit.get)
685      this.loadWaitStrict.foreach(_ := source.common.loadWaitStrict.get)
686      this.ssid          .foreach(_ := source.common.ssid.get)
687      this.lqIdx         .foreach(_ := source.common.lqIdx.get)
688      this.sqIdx         .foreach(_ := source.common.sqIdx.get)
689      this.numLsElem     .foreach(_ := source.common.numLsElem.get)
690      this.srcTimer      .foreach(_ := source.common.srcTimer.get)
691      this.loadDependency.foreach(_ := source.common.loadDependency.get.map(_ << 1))
692    }
693  }
694
695  // ExuInput --[FuncUnit]--> ExuOutput
696  class ExuOutput(
697    val params: ExeUnitParams,
698  )(implicit
699    val p: Parameters
700  ) extends Bundle with BundleSource with HasXSParameter {
701    val data         = Vec(params.wbPathNum, UInt(params.destDataBitsMax.W))
702    val pdest        = UInt(params.wbPregIdxWidth.W)
703    val robIdx       = new RobPtr
704    val intWen       = if (params.needIntWen)   Some(Bool())                  else None
705    val fpWen        = if (params.needFpWen)    Some(Bool())                  else None
706    val vecWen       = if (params.needVecWen)   Some(Bool())                  else None
707    val v0Wen        = if (params.needV0Wen)    Some(Bool())                  else None
708    val vlWen        = if (params.needVlWen)    Some(Bool())                  else None
709    val redirect     = if (params.hasRedirect)  Some(ValidIO(new Redirect))   else None
710    val fflags       = if (params.writeFflags)  Some(UInt(5.W))               else None
711    val wflags       = if (params.writeFflags)  Some(Bool())                  else None
712    val vxsat        = if (params.writeVxsat)   Some(Bool())                  else None
713    val exceptionVec = if (params.exceptionOut.nonEmpty) Some(ExceptionVec()) else None
714    val flushPipe    = if (params.flushPipe)    Some(Bool())                  else None
715    val replay       = if (params.replayInst)   Some(Bool())                  else None
716    val lqIdx        = if (params.hasLoadFu)    Some(new LqPtr())             else None
717    val sqIdx        = if (params.hasStoreAddrFu || params.hasStdFu)
718                                                Some(new SqPtr())             else None
719    val trigger      = if (params.trigger)      Some(TriggerAction())           else None
720    // uop info
721    val predecodeInfo = if(params.hasPredecode) Some(new PreDecodeInfo) else None
722    // vldu used only
723    val vls = OptionWrapper(params.hasVLoadFu, new Bundle {
724      val vpu = new VPUCtrlSignals
725      val oldVdPsrc = UInt(PhyRegIdxWidth.W)
726      val vdIdx = UInt(3.W)
727      val vdIdxInField = UInt(3.W)
728      val isIndexed = Bool()
729      val isMasked = Bool()
730      val isStrided = Bool()
731      val isWhole = Bool()
732      val isVecLoad = Bool()
733      val isVlm = Bool()
734    })
735    val debug = new DebugBundle
736    val debugInfo = new PerfDebugInfo
737    val debug_seqNum = InstSeqNum()
738  }
739
740  // ExuOutput + DynInst --> WriteBackBundle
741  class WriteBackBundle(val params: PregWB, backendParams: BackendParams)(implicit p: Parameters) extends Bundle with BundleSource {
742    val rfWen = Bool()
743    val fpWen = Bool()
744    val vecWen = Bool()
745    val v0Wen = Bool()
746    val vlWen = Bool()
747    val pdest = UInt(params.pregIdxWidth(backendParams).W)
748    val data = UInt(params.dataWidth.W)
749    val robIdx = new RobPtr()(p)
750    val flushPipe = Bool()
751    val replayInst = Bool()
752    val redirect = ValidIO(new Redirect)
753    val fflags = UInt(5.W)
754    val vxsat = Bool()
755    val exceptionVec = ExceptionVec()
756    val debug = new DebugBundle
757    val debugInfo = new PerfDebugInfo
758    val debug_seqNum = InstSeqNum()
759
760    this.wakeupSource = s"WB(${params.toString})"
761
762    def fromExuOutput(source: ExuOutput, wbType: String) = {
763      val typeMap = Map("int" -> 0, "fp" -> 1, "vf" -> 2, "v0" -> 3, "vl" -> 4)
764      this.rfWen  := source.intWen.getOrElse(false.B)
765      this.fpWen  := source.fpWen.getOrElse(false.B)
766      this.vecWen := source.vecWen.getOrElse(false.B)
767      this.v0Wen  := source.v0Wen.getOrElse(false.B)
768      this.vlWen  := source.vlWen.getOrElse(false.B)
769      this.pdest  := source.pdest
770      this.data   := source.data(source.params.wbIndex(typeMap(wbType)))
771      this.robIdx := source.robIdx
772      this.flushPipe := source.flushPipe.getOrElse(false.B)
773      this.replayInst := source.replay.getOrElse(false.B)
774      this.redirect := source.redirect.getOrElse(0.U.asTypeOf(this.redirect))
775      this.fflags := source.fflags.getOrElse(0.U.asTypeOf(this.fflags))
776      this.vxsat := source.vxsat.getOrElse(0.U.asTypeOf(this.vxsat))
777      this.exceptionVec := source.exceptionVec.getOrElse(0.U.asTypeOf(this.exceptionVec))
778      this.debug := source.debug
779      this.debugInfo := source.debugInfo
780      this.debug_seqNum := source.debug_seqNum
781    }
782
783    def asIntRfWriteBundle(fire: Bool): RfWritePortWithConfig = {
784      val rfWrite = Wire(Output(new RfWritePortWithConfig(this.params.dataCfg, backendParams.getPregParams(IntData()).addrWidth)))
785      rfWrite.wen := this.rfWen && fire
786      rfWrite.addr := this.pdest
787      rfWrite.data := this.data
788      rfWrite.intWen := this.rfWen
789      rfWrite.fpWen := false.B
790      rfWrite.vecWen := false.B
791      rfWrite.v0Wen := false.B
792      rfWrite.vlWen := false.B
793      rfWrite
794    }
795
796    def asFpRfWriteBundle(fire: Bool): RfWritePortWithConfig = {
797      val rfWrite = Wire(Output(new RfWritePortWithConfig(this.params.dataCfg, backendParams.getPregParams(FpData()).addrWidth)))
798      rfWrite.wen := this.fpWen && fire
799      rfWrite.addr := this.pdest
800      rfWrite.data := this.data
801      rfWrite.intWen := false.B
802      rfWrite.fpWen := this.fpWen
803      rfWrite.vecWen := false.B
804      rfWrite.v0Wen := false.B
805      rfWrite.vlWen := false.B
806      rfWrite
807    }
808
809    def asVfRfWriteBundle(fire: Bool): RfWritePortWithConfig = {
810      val rfWrite = Wire(Output(new RfWritePortWithConfig(this.params.dataCfg, backendParams.getPregParams(VecData()).addrWidth)))
811      rfWrite.wen := this.vecWen && fire
812      rfWrite.addr := this.pdest
813      rfWrite.data := this.data
814      rfWrite.intWen := false.B
815      rfWrite.fpWen := false.B
816      rfWrite.vecWen := this.vecWen
817      rfWrite.v0Wen := false.B
818      rfWrite.vlWen := false.B
819      rfWrite
820    }
821
822    def asV0RfWriteBundle(fire: Bool): RfWritePortWithConfig = {
823      val rfWrite = Wire(Output(new RfWritePortWithConfig(this.params.dataCfg, backendParams.getPregParams(V0Data()).addrWidth)))
824      rfWrite.wen := this.v0Wen && fire
825      rfWrite.addr := this.pdest
826      rfWrite.data := this.data
827      rfWrite.intWen := false.B
828      rfWrite.fpWen := false.B
829      rfWrite.vecWen := false.B
830      rfWrite.v0Wen := this.v0Wen
831      rfWrite.vlWen := false.B
832      rfWrite
833    }
834
835    def asVlRfWriteBundle(fire: Bool): RfWritePortWithConfig = {
836      val rfWrite = Wire(Output(new RfWritePortWithConfig(this.params.dataCfg, backendParams.getPregParams(VlData()).addrWidth)))
837      rfWrite.wen := this.vlWen && fire
838      rfWrite.addr := this.pdest
839      rfWrite.data := this.data
840      rfWrite.intWen := false.B
841      rfWrite.fpWen := false.B
842      rfWrite.vecWen := false.B
843      rfWrite.v0Wen := false.B
844      rfWrite.vlWen := this.vlWen
845      rfWrite
846    }
847  }
848
849  // ExuOutput --> ExuBypassBundle --[DataPath]-->ExuInput
850  //                                /
851  //     [IssueQueue]--> ExuInput --
852  class ExuBypassBundle(
853    val params: ExeUnitParams,
854  )(implicit p: Parameters) extends XSBundle {
855    val intWen = Bool()
856    val data   = UInt(params.destDataBitsMax.W)
857    val pdest  = UInt(params.wbPregIdxWidth.W)
858  }
859
860  class ExceptionInfo(implicit p: Parameters) extends XSBundle {
861    val pc = UInt(VAddrData().dataWidth.W)
862    val instr = UInt(32.W)
863    val commitType = CommitType()
864    val exceptionVec = ExceptionVec()
865    val isPcBkpt = Bool()
866    val isFetchMalAddr = Bool()
867    val gpaddr = UInt(XLEN.W)
868    val singleStep = Bool()
869    val crossPageIPFFix = Bool()
870    val isInterrupt = Bool()
871    val isHls = Bool()
872    val vls = Bool()
873    val trigger = TriggerAction()
874    val isForVSnonLeafPTE = Bool()
875  }
876
877  object UopIdx {
878    def apply()(implicit p: Parameters): UInt = UInt(log2Up(p(XSCoreParamsKey).MaxUopSize + 1).W)
879  }
880
881  object FuLatency {
882    def apply(): UInt = UInt(width.W)
883
884    def width = 4 // 0~15 // Todo: assosiate it with FuConfig
885  }
886
887  class ExuSource(exuNum: Int)(implicit p: Parameters) extends XSBundle {
888    val value = UInt(log2Ceil(exuNum + 1).W)
889
890    val allExuNum = p(XSCoreParamsKey).backendParams.numExu
891
892    def toExuOH(num: Int, filter: Seq[Int]): Vec[Bool] = {
893      require(num == filter.size)
894      val encodedExuOH = UIntToOH(this.value)(num, 1)
895      val ext = Module(new UIntExtractor(allExuNum, filter))
896      ext.io.in := encodedExuOH
897      VecInit(ext.io.out.asBools.zipWithIndex.map{ case(out, idx) =>
898        if (filter.contains(idx)) out
899        else false.B
900      })
901    }
902
903    def toExuOH(exuParams: ExeUnitParams): Vec[Bool] = {
904      toExuOH(exuParams.numWakeupFromIQ, exuParams.iqWakeUpSinkPairs.map(x => x.source.getExuParam(p(XSCoreParamsKey).backendParams.allExuParams).exuIdx))
905    }
906
907    def toExuOH(iqParams: IssueBlockParams): Vec[Bool] = {
908      toExuOH(iqParams.numWakeupFromIQ, iqParams.wakeUpSourceExuIdx)
909    }
910
911    def fromExuOH(iqParams: IssueBlockParams, exuOH: UInt): UInt = {
912      val comp = Module(new UIntCompressor(allExuNum, iqParams.wakeUpSourceExuIdx))
913      comp.io.in := exuOH
914      OHToUInt(Cat(comp.io.out, 0.U(1.W)))
915    }
916  }
917
918  object ExuSource {
919    def apply(exuNum: Int)(implicit p: Parameters) = new ExuSource(exuNum)
920
921    def apply(params: ExeUnitParams)(implicit p: Parameters) = new ExuSource(params.numWakeupFromIQ)
922
923    def apply()(implicit p: Parameters, params: IssueBlockParams) = new ExuSource(params.numWakeupFromIQ)
924  }
925
926  object ExuVec {
927    def apply(exuNum: Int): Vec[Bool] = Vec(exuNum, Bool())
928
929    def apply()(implicit p: Parameters): Vec[Bool] = Vec(width, Bool())
930
931    def width(implicit p: Parameters): Int = p(XSCoreParamsKey).backendParams.numExu
932  }
933
934  class CancelSignal(implicit p: Parameters) extends XSBundle {
935    val rfWen = Bool()
936    val fpWen = Bool()
937    val vecWen = Bool()
938    val v0Wen = Bool()
939    val vlWen = Bool()
940    val pdest = UInt(PhyRegIdxWidth.W)
941  }
942
943  class MemExuInput(isVector: Boolean = false)(implicit p: Parameters) extends XSBundle {
944    val uop = new DynInst
945    val src = if (isVector) Vec(5, UInt(VLEN.W)) else Vec(3, UInt(XLEN.W))
946    val iqIdx = UInt(log2Up(MemIQSizeMax).W)
947    val isFirstIssue = Bool()
948    val flowNum      = OptionWrapper(isVector, NumLsElem())
949
950    def src_rs1 = src(0)
951    def src_rs2 = src(1)
952    def src_stride = src(1)
953    def src_vs3 = src(2)
954    def src_mask = if (isVector) src(3) else 0.U
955    def src_vl = if (isVector) src(4) else 0.U
956  }
957
958  class MemExuOutput(isVector: Boolean = false)(implicit p: Parameters) extends XSBundle {
959    val uop = new DynInst
960    val data = if (isVector) UInt(VLEN.W) else UInt(XLEN.W)
961    val mask = if (isVector) Some(UInt(VLEN.W)) else None
962    val vdIdx = if (isVector) Some(UInt(3.W)) else None // TODO: parameterize width
963    val vdIdxInField = if (isVector) Some(UInt(3.W)) else None
964    val isFromLoadUnit = Bool()
965    val debug = new DebugBundle
966
967    def isVls = FuType.isVls(uop.fuType)
968  }
969
970  class MemMicroOpRbExt(implicit p: Parameters) extends XSBundle {
971    val uop = new DynInst
972    val flag = UInt(1.W)
973  }
974
975  object LoadShouldCancel {
976    def apply(loadDependency: Option[Seq[UInt]], ldCancel: Seq[LoadCancelIO]): Bool = {
977      val ld1Cancel = loadDependency.map(_.zip(ldCancel.map(_.ld1Cancel)).map { case (dep, cancel) => cancel && dep(0)}.reduce(_ || _))
978      val ld2Cancel = loadDependency.map(_.zip(ldCancel.map(_.ld2Cancel)).map { case (dep, cancel) => cancel && dep(1)}.reduce(_ || _))
979      ld1Cancel.map(_ || ld2Cancel.get).getOrElse(false.B)
980    }
981  }
982}
983