xref: /XiangShan/src/main/scala/xiangshan/mem/vector/VMergeBuffer.scala (revision bb2f3f51dd67f6e16e0cc1ffe43368c9fc7e4aef)
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.mem
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import utility._
24import xiangshan._
25import xiangshan.backend.rob.RobPtr
26import xiangshan.backend.Bundles._
27import xiangshan.mem._
28import xiangshan.backend.fu.FuType
29import xiangshan.backend.fu.FuConfig._
30import xiangshan.backend.datapath.NewPipelineConnect
31import freechips.rocketchip.diplomacy.BufferParams
32
33class MBufferBundle(implicit p: Parameters) extends VLSUBundle{
34  val data             = UInt(VLEN.W)
35  val mask             = UInt(VLENB.W)
36  val flowNum          = UInt(flowIdxBits.W)
37  val exceptionVec     = ExceptionVec()
38  val uop              = new DynInst
39  // val vdOffset         = UInt(vOffsetBits.W)
40  val sourceType       = VSFQFeedbackType()
41  val flushState       = Bool()
42  val vdIdx            = UInt(3.W)
43  // for exception
44  val vstart           = UInt(elemIdxBits.W)
45  val vl               = UInt(elemIdxBits.W)
46  val vaddr            = UInt(VAddrBits.W)
47  val fof              = Bool()
48  val vlmax            = UInt(elemIdxBits.W)
49
50  def allReady(): Bool = (flowNum === 0.U)
51}
52
53abstract class BaseVMergeBuffer(isVStore: Boolean=false)(implicit p: Parameters) extends VLSUModule{
54  val io = IO(new VMergeBufferIO(isVStore))
55
56  // freeliset: store valid entries index.
57  // +---+---+--------------+-----+-----+
58  // | 0 | 1 |      ......  | n-2 | n-1 |
59  // +---+---+--------------+-----+-----+
60  val freeList: FreeList
61  val uopSize: Int
62  val enqWidth = io.fromSplit.length
63  val deqWidth = io.uopWriteback.length
64  val pipeWidth = io.fromPipeline.length
65  lazy val fuCfg = if (isVStore) VstuCfg else VlduCfg
66
67  def EnqConnect(source: MergeBufferReq, sink: MBufferBundle) = {
68    sink.data         := source.data
69    sink.mask         := source.mask
70    sink.flowNum      := source.flowNum
71    sink.exceptionVec := ExceptionNO.selectByFu(0.U.asTypeOf(ExceptionVec()), fuCfg)
72    sink.uop          := source.uop
73    sink.sourceType   := 0.U.asTypeOf(VSFQFeedbackType())
74    sink.flushState   := false.B
75    sink.vdIdx        := source.vdIdx
76    sink.fof          := source.fof
77    sink.vlmax        := source.vlmax
78    sink.vl           := source.uop.vpu.vl
79    sink.vstart       := 0.U
80  }
81  def DeqConnect(source: MBufferBundle): MemExuOutput = {
82    val sink               = WireInit(0.U.asTypeOf(new MemExuOutput(isVector = true)))
83    sink.data             := source.data
84    sink.mask.get         := source.mask
85    sink.uop              := source.uop
86    sink.uop.exceptionVec := ExceptionNO.selectByFu(source.exceptionVec, fuCfg)
87    sink.uop.vpu.vmask    := source.mask
88    sink.debug            := 0.U.asTypeOf(new DebugBundle)
89    sink.vdIdxInField.get := source.vdIdx // Mgu needs to use this.
90    sink.vdIdx.get        := source.vdIdx
91    sink.uop.vpu.vstart   := source.vstart
92    sink.uop.vpu.vl       := source.vl
93    sink
94  }
95  def ToLsqConnect(source: MBufferBundle): FeedbackToLsqIO = {
96    val sink                                 = WireInit(0.U.asTypeOf(new FeedbackToLsqIO))
97    val hasExp                               = ExceptionNO.selectByFu(source.exceptionVec, fuCfg).asUInt.orR
98    sink.robidx                             := source.uop.robIdx
99    sink.uopidx                             := source.uop.uopIdx
100    sink.feedback(VecFeedbacks.COMMIT)      := !hasExp
101    sink.feedback(VecFeedbacks.FLUSH)       := hasExp
102    sink.feedback(VecFeedbacks.LAST)        := true.B
103    sink.vstart                             := source.vstart // TODO: if lsq need vl for fof?
104    sink.vaddr                              := source.vaddr
105    sink.vl                                 := source.vl
106    sink.exceptionVec                       := ExceptionNO.selectByFu(source.exceptionVec, fuCfg)
107    sink
108  }
109
110
111  val entries      = Reg(Vec(uopSize, new MBufferBundle))
112  val needCancel   = WireInit(VecInit(Seq.fill(uopSize)(false.B)))
113  val allocated    = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
114  val freeMaskVec  = WireInit(VecInit(Seq.fill(uopSize)(false.B)))
115  val uopFinish    = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
116  val needRSReplay = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
117  // enq, from splitPipeline
118  // val allowEnqueue =
119  val cancelEnq    = io.fromSplit.map(_.req.bits.uop.robIdx.needFlush(io.redirect))
120  val canEnqueue   = io.fromSplit.map(_.req.valid)
121  val needEnqueue  = (0 until enqWidth).map{i =>
122    canEnqueue(i) && !cancelEnq(i)
123  }
124
125  val freeCount    = uopSize.U - freeList.io.validCount
126
127  for ((enq, i) <- io.fromSplit.zipWithIndex){
128    freeList.io.doAllocate(i) := false.B
129
130    freeList.io.allocateReq(i) := true.B
131
132    val offset    = PopCount(needEnqueue.take(i))
133    val canAccept = freeList.io.canAllocate(offset)
134    val enqIndex  = freeList.io.allocateSlot(offset)
135    enq.req.ready := freeCount >= (i + 1).U // for better timing
136
137    when(needEnqueue(i) && enq.req.ready){
138      freeList.io.doAllocate(i) := true.B
139      // enqueue
140      allocated(enqIndex)       := true.B
141      uopFinish(enqIndex)       := false.B
142      needRSReplay(enqIndex)    := false.B
143
144      EnqConnect(enq.req.bits, entries(enqIndex))// initial entry
145    }
146
147    enq.resp.bits.mBIndex := enqIndex
148    enq.resp.bits.fail    := false.B
149    enq.resp.valid        := freeCount >= (i + 1).U // for better timing
150  }
151
152  //redirect
153  for (i <- 0 until uopSize){
154    needCancel(i) := entries(i).uop.robIdx.needFlush(io.redirect) && allocated(i)
155    when (needCancel(i)) {
156      allocated(i)   := false.B
157      freeMaskVec(i) := true.B
158      uopFinish(i)   := false.B
159      needRSReplay(i):= false.B
160    }
161  }
162  freeList.io.free := freeMaskVec.asUInt
163  //pipelineWriteback
164  // handle the situation where multiple ports are going to write the same uop queue entry
165  val mergePortMatrix        = Wire(Vec(pipeWidth, Vec(pipeWidth, Bool())))
166  val mergedByPrevPortVec    = Wire(Vec(pipeWidth, Bool()))
167  (0 until pipeWidth).map{case i => (0 until pipeWidth).map{case j =>
168    mergePortMatrix(i)(j) := (j == i).B ||
169      (j > i).B &&
170      io.fromPipeline(j).bits.mBIndex === io.fromPipeline(i).bits.mBIndex &&
171      io.fromPipeline(j).valid
172  }}
173  (0 until pipeWidth).map{case i =>
174    mergedByPrevPortVec(i) := (i != 0).B && Cat((0 until i).map(j =>
175      io.fromPipeline(j).bits.mBIndex === io.fromPipeline(i).bits.mBIndex &&
176      io.fromPipeline(j).valid)).orR
177  }
178  dontTouch(mergePortMatrix)
179  dontTouch(mergedByPrevPortVec)
180
181  // for exception, select exception, when multi port writeback exception, we need select oldest one
182  def selectOldest[T <: VecPipelineFeedbackIO](valid: Seq[Bool], bits: Seq[T], sel: Seq[UInt]): (Seq[Bool], Seq[T], Seq[UInt]) = {
183    assert(valid.length == bits.length)
184    assert(valid.length == sel.length)
185    if (valid.length == 0 || valid.length == 1) {
186      (valid, bits, sel)
187    } else if (valid.length == 2) {
188      val res = Seq.fill(2)(Wire(ValidIO(chiselTypeOf(bits(0)))))
189      for (i <- res.indices) {
190        res(i).valid := valid(i)
191        res(i).bits := bits(i)
192      }
193      val oldest = Mux(valid(0) && valid(1),
194        Mux(sel(0) < sel(1),
195            res(0), res(1)),
196        Mux(valid(0) && !valid(1), res(0), res(1)))
197      (Seq(oldest.valid), Seq(oldest.bits), Seq(0.U))
198    } else {
199      val left  = selectOldest(valid.take(valid.length / 2), bits.take(bits.length / 2), sel.take(sel.length / 2))
200      val right = selectOldest(valid.takeRight(valid.length - (valid.length / 2)), bits.takeRight(bits.length - (bits.length / 2)), sel.takeRight(sel.length - (sel.length / 2)))
201      selectOldest(left._1 ++ right._1, left._2 ++ right._2, left._3 ++ right._3)
202    }
203  }
204
205  val pipeValid        = io.fromPipeline.map(_.valid)
206  val pipeBits         = io.fromPipeline.map(x => x.bits)
207  val wbElemIdx        = pipeBits.map(_.elemIdx)
208  val wbMbIndex        = pipeBits.map(_.mBIndex)
209  val wbElemIdxInField = wbElemIdx.zip(wbMbIndex).map(x => x._1 & (entries(x._2).vlmax - 1.U))
210
211  val portHasExcp       = pipeBits.zip(mergePortMatrix).map{case (port, v) =>
212    (0 until pipeWidth).map{case i =>
213      val pipeHasExcep = ExceptionNO.selectByFu(io.fromPipeline(i).bits.exceptionVec, fuCfg).asUInt.orR
214      (v(i) && pipeHasExcep && io.fromPipeline(i).bits.mask.orR) // this port have exception or merged port have exception
215    }.reduce(_ || _)
216  }
217
218  for((pipewb, i) <- io.fromPipeline.zipWithIndex){
219    val entry               = entries(wbMbIndex(i))
220    val entryVeew           = entry.uop.vpu.veew
221    val entryIsUS           = LSUOpType.isUStride(entry.uop.fuOpType)
222    val entryHasException   = ExceptionNO.selectByFu(entry.exceptionVec, fuCfg).asUInt.orR
223    val entryExcp           = entryHasException && entry.mask.orR
224
225    val sel                    = selectOldest(mergePortMatrix(i), pipeBits, wbElemIdxInField)
226    val selPort                = sel._2
227    val selElemInfield         = selPort(0).elemIdx & (entries(wbMbIndex(i)).vlmax - 1.U)
228    val selExceptionVec        = selPort(0).exceptionVec
229
230    val isUSFirstUop           = !selPort(0).elemIdx.orR
231    // Only the first unaligned uop of unit-stride needs to be offset.
232    // When unaligned, the lowest bit of mask is 0.
233    //  example: 16'b1111_1111_1111_0000
234    val vaddrOffset            = Mux(entryIsUS && isUSFirstUop, genVFirstUnmask(selPort(0).mask).asUInt, 0.U)
235    val vaddr                  = selPort(0).vaddr +  vaddrOffset
236
237    // select oldest port to raise exception
238    when((((entries(wbMbIndex(i)).vstart >= selElemInfield) && entryExcp && portHasExcp(i)) || (!entryExcp && portHasExcp(i))) && pipewb.valid && !mergedByPrevPortVec(i)){
239      when(!entries(wbMbIndex(i)).fof || selElemInfield === 0.U){
240        // For fof loads, if element 0 raises an exception, vl is not modified, and the trap is taken.
241        entries(wbMbIndex(i)).vstart       := selElemInfield
242        entries(wbMbIndex(i)).exceptionVec := ExceptionNO.selectByFu(selExceptionVec, fuCfg)
243        entries(wbMbIndex(i)).vaddr        := vaddr
244      }.otherwise{
245        entries(wbMbIndex(i)).vl           := selElemInfield
246      }
247    }
248  }
249
250  // for pipeline writeback
251  for((pipewb, i) <- io.fromPipeline.zipWithIndex){
252    val wbIndex          = pipewb.bits.mBIndex
253    val flowNumOffset    = Mux(pipewb.bits.usSecondInv,
254                               2.U,
255                               PopCount(mergePortMatrix(i)))
256    val sourceTypeNext   = entries(wbIndex).sourceType | pipewb.bits.sourceType
257    val hasExp           = ExceptionNO.selectByFu(pipewb.bits.exceptionVec, fuCfg).asUInt.orR
258
259    // if is VLoad, need latch 1 cycle to merge data. only flowNum and wbIndex need to latch
260    val latchWbValid     = if(isVStore) pipewb.valid else RegNext(pipewb.valid)
261    val latchWbIndex     = if(isVStore) wbIndex      else RegEnable(wbIndex, pipewb.valid)
262    val latchFlowNum     = if(isVStore) flowNumOffset else RegEnable(flowNumOffset, pipewb.valid)
263    val latchMergeByPre  = if(isVStore) mergedByPrevPortVec(i) else RegEnable(mergedByPrevPortVec(i), pipewb.valid)
264    when(latchWbValid && !latchMergeByPre){
265      entries(latchWbIndex).flowNum := entries(latchWbIndex).flowNum - latchFlowNum
266    }
267
268    when(pipewb.valid){
269      entries(wbIndex).sourceType   := sourceTypeNext
270      entries(wbIndex).flushState   := pipewb.bits.flushState
271    }
272    when(pipewb.valid && !pipewb.bits.hit){
273      needRSReplay(wbIndex) := true.B
274    }
275    pipewb.ready := true.B
276    XSError((entries(latchWbIndex).flowNum - latchFlowNum > entries(latchWbIndex).flowNum) && latchWbValid && !latchMergeByPre, "FlowWriteback overflow!!\n")
277    XSError(!allocated(latchWbIndex) && latchWbValid, "Writeback error flow!!\n")
278  }
279  // for inorder mem asscess
280  io.toSplit := DontCare
281
282  //uopwriteback(deq)
283  for (i <- 0 until uopSize){
284    when(allocated(i) && entries(i).allReady()){
285      uopFinish(i) := true.B
286    }
287  }
288   val selPolicy = SelectOne("circ", uopFinish, deqWidth) // select one entry to deq
289   private val pipelineOut              = Wire(Vec(deqWidth, DecoupledIO(new MemExuOutput(isVector = true))))
290   private val writeBackOut             = Wire(Vec(deqWidth, DecoupledIO(new MemExuOutput(isVector = true))))
291   private val writeBackOutExceptionVec = writeBackOut.map(_.bits.uop.exceptionVec)
292   for(((port, lsqport), i) <- (pipelineOut zip io.toLsq).zipWithIndex){
293    val canGo    = port.ready
294    val (selValid, selOHVec) = selPolicy.getNthOH(i + 1)
295    val entryIdx = OHToUInt(selOHVec)
296    val selEntry = entries(entryIdx)
297    val selAllocated = allocated(entryIdx)
298    val selFire  = selValid && canGo
299    when(selFire){
300      freeMaskVec(entryIdx) := selAllocated
301      allocated(entryIdx)   := false.B
302      uopFinish(entryIdx)   := false.B
303      needRSReplay(entryIdx):= false.B
304    }
305    //writeback connect
306    port.valid   := selFire && selAllocated && !needRSReplay(entryIdx) && !selEntry.uop.robIdx.needFlush(io.redirect)
307    port.bits    := DeqConnect(selEntry)
308    //to lsq
309    lsqport.bits := ToLsqConnect(selEntry) // when uopwriteback, free MBuffer entry, write to lsq
310    lsqport.valid:= selFire && selAllocated && !needRSReplay(entryIdx)
311    //to RS
312    io.feedback(i).valid                 := selFire && selAllocated
313    io.feedback(i).bits.hit              := !needRSReplay(entryIdx)
314    io.feedback(i).bits.robIdx           := selEntry.uop.robIdx
315    io.feedback(i).bits.sourceType       := selEntry.sourceType
316    io.feedback(i).bits.flushState       := selEntry.flushState
317    io.feedback(i).bits.dataInvalidSqIdx := DontCare
318    io.feedback(i).bits.sqIdx            := selEntry.uop.sqIdx
319    io.feedback(i).bits.lqIdx            := selEntry.uop.lqIdx
320    // pipeline connect
321    NewPipelineConnect(
322      port, writeBackOut(i), writeBackOut(i).fire,
323      Mux(port.fire,
324        selEntry.uop.robIdx.needFlush(io.redirect),
325        writeBackOut(i).bits.uop.robIdx.needFlush(io.redirect)),
326      Option(s"VMergebufferPipelineConnect${i}")
327    )
328     io.uopWriteback(i)                  <> writeBackOut(i)
329     io.uopWriteback(i).bits.uop.exceptionVec := ExceptionNO.selectByFu(writeBackOutExceptionVec(i), fuCfg)
330   }
331
332  QueuePerf(uopSize, freeList.io.validCount, freeList.io.validCount === 0.U)
333}
334
335class VLMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=false){
336  override lazy val uopSize = VlMergeBufferSize
337  println(s"VLMergeBuffer Size: ${VlMergeBufferSize}")
338  override lazy val freeList = Module(new FreeList(
339    size = uopSize,
340    allocWidth = VecLoadPipelineWidth,
341    freeWidth = deqWidth,
342    enablePreAlloc = false,
343    moduleName = "VLoad MergeBuffer freelist"
344  ))
345
346  //merge data
347  val flowWbElemIdx     = Wire(Vec(pipeWidth, UInt(elemIdxBits.W)))
348  val flowWbElemIdxInVd = Wire(Vec(pipeWidth, UInt(elemIdxBits.W)))
349  val pipewbValidReg    = Wire(Vec(pipeWidth, Bool()))
350  val wbIndexReg        = Wire(Vec(pipeWidth, UInt(vlmBindexBits.W)))
351  val mergeDataReg      = Wire(Vec(pipeWidth, UInt(VLEN.W)))
352
353  for((pipewb, i) <- io.fromPipeline.zipWithIndex){
354    /** step0 **/
355    val wbIndex = pipewb.bits.mBIndex
356    val alignedType = pipewb.bits.alignedType
357    val elemIdxInsideVd = pipewb.bits.elemIdxInsideVd
358    flowWbElemIdx(i) := pipewb.bits.elemIdx
359    flowWbElemIdxInVd(i) := elemIdxInsideVd.get
360
361    val oldData = PriorityMux(Seq(
362      (pipewbValidReg(0) && (wbIndexReg(0) === wbIndex)) -> mergeDataReg(0),
363      (pipewbValidReg(1) && (wbIndexReg(1) === wbIndex)) -> mergeDataReg(1),
364      (pipewbValidReg(2) && (wbIndexReg(2) === wbIndex)) -> mergeDataReg(2),
365      true.B                                             -> entries(wbIndex).data // default use entries_data
366    ))
367    val mergedData = mergeDataWithElemIdx(
368      oldData = oldData,
369      newData = io.fromPipeline.map(_.bits.vecdata.get),
370      alignedType = alignedType(1,0),
371      elemIdx = flowWbElemIdxInVd,
372      valids = mergePortMatrix(i)
373    )
374    /* this only for unit-stride load data merge
375     * cycle0: broden 128-bits to 256-bits (max 6 to 1)
376     * cycle1: select 128-bits data from 256-bits (16 to 1)
377     */
378    val (brodenMergeData, brodenMergeMask)     = mergeDataByIndex(
379      data    = io.fromPipeline.map(_.bits.vecdata.get).drop(i),
380      mask    = io.fromPipeline.map(_.bits.mask).drop(i),
381      index   = io.fromPipeline(i).bits.elemIdxInsideVd.get,
382      valids  = mergePortMatrix(i).drop(i)
383    )
384    /** step1 **/
385    pipewbValidReg(i)      := RegNext(pipewb.valid)
386    wbIndexReg(i)          := RegEnable(wbIndex, pipewb.valid)
387    mergeDataReg(i)        := RegEnable(mergedData, pipewb.valid) // for not Unit-stride
388    val brodenMergeDataReg  = RegEnable(brodenMergeData, pipewb.valid) // only for Unit-stride
389    val brodenMergeMaskReg  = RegEnable(brodenMergeMask, pipewb.valid)
390    val mergedByPrevPortReg = RegEnable(mergedByPrevPortVec(i), pipewb.valid)
391    val regOffsetReg        = RegEnable(pipewb.bits.reg_offset.get, pipewb.valid) // only for Unit-stride
392    val isusMerge           = RegEnable(alignedType(2), pipewb.valid)
393
394    val usSelData           = Mux1H(UIntToOH(regOffsetReg), (0 until VLENB).map{case i => getNoAlignedSlice(brodenMergeDataReg, i, 128)})
395    val usSelMask           = Mux1H(UIntToOH(regOffsetReg), (0 until VLENB).map{case i => brodenMergeMaskReg(16 + i - 1, i)})
396    val usMergeData         = mergeDataByByte(entries(wbIndexReg(i)).data, usSelData, usSelMask)
397    when(pipewbValidReg(i) && !mergedByPrevPortReg){
398      entries(wbIndexReg(i)).data := Mux(isusMerge, usMergeData, mergeDataReg(i)) // if aligned(2) == 1, is Unit-Stride inst
399    }
400  }
401}
402
403class VSMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=true){
404  override lazy val uopSize = VsMergeBufferSize
405  println(s"VSMergeBuffer Size: ${VsMergeBufferSize}")
406  override lazy val freeList = Module(new FreeList(
407    size = uopSize,
408    allocWidth = VecStorePipelineWidth,
409    freeWidth = deqWidth,
410    enablePreAlloc = false,
411    moduleName = "VStore MergeBuffer freelist"
412  ))
413  override def DeqConnect(source: MBufferBundle): MemExuOutput = {
414    val sink               = Wire(new MemExuOutput(isVector = true))
415    sink.data             := DontCare
416    sink.mask.get         := DontCare
417    sink.uop              := source.uop
418    sink.uop.exceptionVec := source.exceptionVec
419    sink.debug            := 0.U.asTypeOf(new DebugBundle)
420    sink.vdIdxInField.get := DontCare
421    sink.vdIdx.get        := DontCare
422    sink.uop.vpu.vstart   := source.vstart
423    sink
424  }
425}
426