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