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