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