xref: /XiangShan/src/main/scala/xiangshan/mem/vector/VMergeBuffer.scala (revision fd490615892783f3d997c6c4d5827fd793ddf832)
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 freechips.rocketchip.diplomacy.BufferParams
30
31class MBufferBundle(implicit p: Parameters) extends VLSUBundle{
32  val data             = UInt(VLEN.W)
33  val mask             = UInt(VLENB.W)
34  val flowNum          = UInt(flowIdxBits.W)
35  val exceptionVec     = ExceptionVec()
36  val uop              = new DynInst
37  // val vdOffset         = UInt(vOffsetBits.W)
38  val sourceType       = VSFQFeedbackType()
39  val flushState       = Bool()
40
41  def allReady(): Bool = (flowNum === 0.U)
42}
43
44abstract class BaseVMergeBuffer(isVStore: Boolean=false)(implicit p: Parameters) extends VLSUModule{
45  val io = IO(new VMergeBufferIO(isVStore))
46
47  def EnqConnect(source: MergeBufferReq): MBufferBundle = {
48    val sink           = WireInit(0.U.asTypeOf(new MBufferBundle))
49    sink.data         := source.data
50    sink.mask         := source.mask
51    sink.flowNum      := source.flowNum
52    sink.exceptionVec := 0.U.asTypeOf(ExceptionVec())
53    sink.uop          := source.uop
54    sink.sourceType   := 0.U.asTypeOf(VSFQFeedbackType())
55    sink.flushState   := false.B
56    sink
57    // sink.vdOffset     := source.vdOffset
58  }
59  def DeqConnect(source: MBufferBundle): MemExuOutput = {
60    val sink               = WireInit(0.U.asTypeOf(new MemExuOutput(isVector = true)))
61    sink.data             := source.data
62    sink.mask.get         := source.mask
63    sink.uop.exceptionVec := source.exceptionVec
64    sink.uop              := source.uop
65    sink.debug            := 0.U.asTypeOf(new DebugBundle)
66    sink.vdIdxInField.get := 0.U
67    sink.vdIdx.get        := 0.U
68    sink
69  }
70  def ToLsqConnect(source: MBufferBundle): FeedbackToLsqIO = {
71    val sink                                 = WireInit(0.U.asTypeOf(new FeedbackToLsqIO))
72    sink.robidx                             := source.uop.robIdx
73    sink.uopidx                             := source.uop.uopIdx
74    sink.feedback(VecFeedbacks.COMMIT)      := true.B // TODO:
75    sink.feedback(VecFeedbacks.FLUSH)       := false.B
76    sink.feedback(VecFeedbacks.LAST)        := true.B
77    sink.vaddr                              := 0.U // TODO: used when exception
78    sink
79  }
80  // freeliset: store valid entries index.
81  // +---+---+--------------+-----+-----+
82  // | 0 | 1 |      ......  | n-2 | n-1 |
83  // +---+---+--------------+-----+-----+
84  val freeList: FreeList
85  val uopSize: Int
86  val enqWidth = io.fromSplit.length
87  val deqWidth = io.uopWriteback.length
88
89  val entries      = Reg(Vec(uopSize, new MBufferBundle))
90  val needCancel   = WireInit(VecInit(Seq.fill(uopSize)(false.B)))
91  val allocated    = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
92  val freeMaskVec  = WireInit(VecInit(Seq.fill(uopSize)(false.B)))
93  val uopFinish    = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
94  val needRSReplay = RegInit(VecInit(Seq.fill(uopSize)(false.B)))
95  // enq, from splitPipeline
96  // val allowEnqueue =
97  val cancelEnq    = io.fromSplit.map(_.req.bits.uop.robIdx.needFlush(io.redirect))
98  val canEnqueue   = io.fromSplit.map(_.req.valid)
99  val needEnqueue  = (0 until enqWidth).map{i =>
100    canEnqueue(i) && !cancelEnq(i)
101  }
102
103  for ((enq, i) <- io.fromSplit.zipWithIndex){
104    freeList.io.doAllocate(i) := false.B
105
106    freeList.io.allocateReq(i) := true.B
107
108    val offset    = PopCount(needEnqueue.take(i))
109    val canAccept = freeList.io.canAllocate(offset)
110    val enqIndex  = freeList.io.allocateSlot(offset)
111    enq.req.ready := canAccept
112
113    when(needEnqueue(i) && enq.req.ready){
114      freeList.io.doAllocate(i) := true.B
115      // enqueue
116      allocated(enqIndex)       := true.B
117      uopFinish(enqIndex)       := false.B
118      needRSReplay(enqIndex)    := false.B
119
120      entries(enqIndex) := EnqConnect(enq.req.bits)// initial entry
121    }
122
123    enq.resp.bits.mBIndex := enqIndex
124    enq.resp.bits.fail    := false.B
125    enq.resp.valid        := canAccept //resp in 1 cycle
126  }
127
128  //redirect
129  for (i <- 0 until uopSize){
130    needCancel(i) := entries(i).uop.robIdx.needFlush(io.redirect) && allocated(i)
131    when (needCancel(i)) {
132      allocated(i)   := false.B
133      freeMaskVec(i) := true.B
134      uopFinish(i)   := false.B
135      needRSReplay(i):= false.B
136    }
137  }
138  freeList.io.free := freeMaskVec.asUInt
139  //pipelineWriteback
140  for((pipewb) <- io.fromPipeline){
141    val wbIndex = pipewb.bits.mBIndex
142    val flowNumNext = Mux(pipewb.bits.usSecondInv, entries(wbIndex).flowNum - 2.U, entries(wbIndex).flowNum - 1.U)
143    val sourceTypeNext   = entries(wbIndex).sourceType | pipewb.bits.sourceType
144    val hasExp           = pipewb.bits.exceptionVec.asUInt.orR
145    val exceptionVecNext = Mux(hasExp, pipewb.bits.exceptionVec, entries(wbIndex).exceptionVec)
146    when(pipewb.valid){
147      entries(wbIndex).flowNum := flowNumNext
148      entries(wbIndex).sourceType   := sourceTypeNext
149      entries(wbIndex).exceptionVec := exceptionVecNext
150      entries(wbIndex).flushState   := pipewb.bits.flushState
151    }
152    when(pipewb.valid && !pipewb.bits.hit){
153      needRSReplay(wbIndex) := true.B
154    }
155    pipewb.ready := true.B
156    XSError((flowNumNext > entries(wbIndex).flowNum) && pipewb.valid, "FlowWriteback overflow!!\n")
157    XSError(!allocated(wbIndex) && pipewb.valid, "Writeback error flow!!\n")
158  }
159  // for inorder mem asscess
160  io.toSplit := DontCare
161
162  //uopwriteback(deq)
163  for (i <- 0 until uopSize){
164    when(allocated(i) && entries(i).allReady()){
165      uopFinish(i) := true.B
166    }
167  }
168   val selPolicy = SelectOne("circ", uopFinish, deqWidth) // select one entry to deq
169   for(((port, lsqport), i) <- (io.uopWriteback zip io.toLsq).zipWithIndex){
170    val (selValid, selOHVec) = selPolicy.getNthOH(i + 1)
171    val entryIdx = OHToUInt(selOHVec)
172    val selEntry = entries(entryIdx)
173    when(selValid){
174      freeMaskVec(entryIdx) := true.B
175      allocated(entryIdx)   := false.B
176      uopFinish(entryIdx)   := false.B
177      needRSReplay(entryIdx):= false.B
178    }
179    //writeback connect
180    port.valid   := selValid && allocated(entryIdx) && !needRSReplay(entryIdx)
181    port.bits    := DeqConnect(selEntry)
182    //to lsq
183    lsqport.bits := ToLsqConnect(selEntry) // when uopwriteback, free MBuffer entry, write to lsq
184    lsqport.valid:= selValid && allocated(entryIdx) && !needRSReplay(entryIdx)
185    //to RS
186    io.feedback(i).valid                 := selValid && allocated(entryIdx) && needRSReplay(entryIdx)
187    io.feedback(i).bits.hit              := !needRSReplay(entryIdx)
188    io.feedback(i).bits.robIdx           := selEntry.uop.robIdx
189    io.feedback(i).bits.sourceType       := selEntry.sourceType
190    io.feedback(i).bits.flushState       := selEntry.flushState
191    io.feedback(i).bits.dataInvalidSqIdx := DontCare
192    io.feedback(i).bits.uopIdx.get       := selEntry.uop.uopIdx
193   }
194}
195
196class VLMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=false){
197  override lazy val uopSize = VlMergeBufferSize
198  println(s"VLMergeBuffer Size: ${VlMergeBufferSize}")
199  override lazy val freeList = Module(new FreeList(
200    size = uopSize,
201    allocWidth = VecLoadPipelineWidth,
202    freeWidth = deqWidth,
203    enablePreAlloc = false,
204    moduleName = "VLoad MergeBuffer freelist"
205  ))
206
207  //merge data
208  val flowWbElemIdx = Wire(Vec(LoadPipelineWidth, UInt(elemIdxBits.W)))
209  val flowWbElemIdxInVd = Wire(Vec(LoadPipelineWidth, UInt(elemIdxBits.W)))
210
211  for((pipewb, i) <- io.fromPipeline.zipWithIndex){
212    val wbIndex = pipewb.bits.mBIndex
213    val alignedType = pipewb.bits.alignedType.get
214    val elemIdxInsideVd = pipewb.bits.elemIdxInsideVd
215    flowWbElemIdx(i) := pipewb.bits.elemIdx.get
216    flowWbElemIdxInVd(i) := elemIdxInsideVd.get
217    // handle the situation where multiple ports are going to write the same uop queue entry
218    val mergedByPrevPort = (i != 0).B && Cat((0 until i).map(j =>
219      io.fromPipeline(j).bits.mBIndex === pipewb.bits.mBIndex &&
220      io.fromPipeline(j).valid)).orR
221    val mergePortVec = (0 until LoadPipelineWidth).map(j => (j == i).B ||
222      (j > i).B &&
223      io.fromPipeline(j).bits.mBIndex === pipewb.bits.mBIndex &&
224      io.fromPipeline(j).valid)
225    val mergeExpPortVec = (0 until LoadPipelineWidth).map(j => mergePortVec(j))
226    val mergedData = mergeDataWithElemIdx(
227      oldData = entries(wbIndex).data,
228      newData = io.fromPipeline.map(_.bits.vecdata.get),
229      alignedType = alignedType(1,0),
230      elemIdx = flowWbElemIdxInVd,
231      valids = mergeExpPortVec
232    )
233    val usMergeData = mergeDataByoffset(
234      oldData = entries(wbIndex).data,
235      newData = io.fromPipeline.map(_.bits.vecdata.get),
236      mask    = io.fromPipeline.map(_.bits.mask.get),
237      offset  = io.fromPipeline.map(_.bits.reg_offset.get),
238      valids  = mergeExpPortVec
239    )
240    when(pipewb.valid && !mergedByPrevPort){
241      entries(wbIndex).data := Mux(alignedType(2), usMergeData, mergedData) // if aligned(2) == 1, is Unit-Stride inst
242    }
243  }
244}
245
246class VSMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=true){
247  override lazy val uopSize = VsMergeBufferSize
248  println(s"VSMergeBuffer Size: ${VsMergeBufferSize}")
249  override lazy val freeList = Module(new FreeList(
250    size = uopSize,
251    allocWidth = VecStorePipelineWidth,
252    freeWidth = deqWidth,
253    enablePreAlloc = false,
254    moduleName = "VStore MergeBuffer freelist"
255  ))
256  override def DeqConnect(source: MBufferBundle): MemExuOutput = {
257    val sink               = Wire(new MemExuOutput(isVector = true))
258    sink.data             := source.data
259    sink.mask.get         := source.mask
260    sink.uop.exceptionVec := source.exceptionVec
261    sink.uop              := source.uop
262    sink.debug            := 0.U.asTypeOf(new DebugBundle)
263    sink.vdIdxInField.get := 0.U
264    sink.vdIdx.get        := 0.U
265    sink
266  }
267}
268