xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/StoreQueueData.scala (revision 708ceed4afe43fb0ea3a52407e46b2794c573634)
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 chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import xiangshan._
24import xiangshan.cache._
25import xiangshan.cache.{DCacheWordIO, DCacheLineIO, MemoryOpConstants}
26import xiangshan.mem._
27import xiangshan.backend.roq.RoqPtr
28
29
30// Data module define
31// These data modules are like SyncDataModuleTemplate, but support cam-like ops
32class SQAddrModule(dataWidth: Int, numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
33  val io = IO(new Bundle {
34    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
35    val rdata = Output(Vec(numRead, UInt(dataWidth.W)))
36    val wen   = Input(Vec(numWrite, Bool()))
37    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
38    val wdata = Input(Vec(numWrite, UInt(dataWidth.W)))
39    val forwardMdata = Input(Vec(numForward, UInt(dataWidth.W)))
40    val forwardMmask = Output(Vec(numForward, Vec(numEntries, Bool())))
41    val debug_data = Output(Vec(numEntries, UInt(dataWidth.W)))
42  })
43
44  val data = Reg(Vec(numEntries, UInt(dataWidth.W)))
45  io.debug_data := data
46
47  // read ports
48  for (i <- 0 until numRead) {
49    io.rdata(i) := data(RegNext(io.raddr(i)))
50  }
51
52  // below is the write ports (with priorities)
53  for (i <- 0 until numWrite) {
54    when (io.wen(i)) {
55      data(io.waddr(i)) := io.wdata(i)
56    }
57  }
58
59  // content addressed match
60  for (i <- 0 until numForward) {
61    for (j <- 0 until numEntries) {
62      io.forwardMmask(i)(j) := io.forwardMdata(i)(dataWidth-1, 3) === data(j)(dataWidth-1, 3)
63    }
64  }
65
66  // DataModuleTemplate should not be used when there're any write conflicts
67  for (i <- 0 until numWrite) {
68    for (j <- i+1 until numWrite) {
69      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
70    }
71  }
72}
73
74class SQData8Entry(implicit p: Parameters) extends XSBundle {
75  // val paddr = UInt(PAddrBits.W)
76  val valid = Bool()
77  val data = UInt((XLEN/8).W)
78}
79
80class SQData8Module(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
81  val io = IO(new Bundle() {
82    val raddr = Vec(numRead,  Input(UInt(log2Up(numEntries).W)))
83    val rdata = Vec(numRead,  Output(new SQData8Entry))
84    val data = new Bundle() {
85      val wen   = Vec(numWrite, Input(Bool()))
86      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
87      val wdata = Vec(numWrite, Input(UInt((XLEN/8).W)))
88    }
89    val mask = new Bundle() {
90      val wen   = Vec(numWrite, Input(Bool()))
91      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
92      val wdata = Vec(numWrite, Input(Bool()))
93    }
94
95    val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W))))
96    val forwardValidFast = Vec(numForward, Output(Bool()))
97    val forwardValid = Vec(numForward, Output(Bool()))
98    val forwardData = Vec(numForward, Output(UInt(8.W)))
99  })
100
101  io := DontCare
102
103  val data = Reg(Vec(numEntries, new SQData8Entry))
104
105  // writeback to sq
106  (0 until numWrite).map(i => {
107    when(io.data.wen(i)){
108      data(io.data.waddr(i)).data := io.data.wdata(i)
109    }
110  })
111  (0 until numWrite).map(i => {
112    when(io.mask.wen(i)){
113      data(io.mask.waddr(i)).valid := io.mask.wdata(i)
114    }
115  })
116
117  // destorequeue read data
118  (0 until numRead).map(i => {
119      io.rdata(i) := data(RegNext(io.raddr(i)))
120  })
121
122  // DataModuleTemplate should not be used when there're any write conflicts
123  for (i <- 0 until numWrite) {
124    for (j <- i+1 until numWrite) {
125      assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j)))
126    }
127  }
128  for (i <- 0 until numWrite) {
129    for (j <- i+1 until numWrite) {
130      assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j)))
131    }
132  }
133
134  // forwarding
135  // Compare ringBufferTail (deqPtr) and forward.sqIdx, we have two cases:
136  // (1) if they have the same flag, we need to check range(tail, sqIdx)
137  // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx)
138  // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize))
139  // Forward2: Mux(same_flag, 0.U,                   range(0, sqIdx)    )
140  // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise
141
142  // entry with larger index should have higher priority since it's data is younger
143
144  (0 until numForward).map(i => {
145    // parallel fwd logic
146    val matchResultVec = Wire(Vec(numEntries * 2, new FwdEntry))
147
148    def parallelFwd(xs: Seq[Data]): Data = {
149      ParallelOperation(xs, (a: Data, b: Data) => {
150        val l = a.asTypeOf(new FwdEntry)
151        val r = b.asTypeOf(new FwdEntry)
152        val res = Wire(new FwdEntry)
153        res.validFast := l.validFast || r.validFast
154        res.valid := l.valid || r.valid
155        // res.valid := RegNext(res.validFast)
156        res.data := Mux(r.valid, r.data, l.data)
157        res
158      })
159    }
160
161    for (j <- 0 until numEntries) {
162      val needCheck0 = io.needForward(i)(0)(j)
163      val needCheck1 = io.needForward(i)(1)(j)
164      val needCheck0Reg = RegNext(needCheck0)
165      val needCheck1Reg = RegNext(needCheck1)
166      (0 until XLEN / 8).foreach(k => {
167        matchResultVec(j).validFast := needCheck0 && data(j).valid
168        matchResultVec(j).valid := needCheck0Reg && data(j).valid
169        matchResultVec(j).data := data(j).data
170        matchResultVec(numEntries + j).validFast := needCheck1 && data(j).valid
171        matchResultVec(numEntries + j).valid := needCheck1Reg && data(j).valid
172        matchResultVec(numEntries + j).data := data(j).data
173      })
174    }
175
176    val parallelFwdResult = parallelFwd(matchResultVec).asTypeOf(new FwdEntry)
177
178    // validFast is generated the same cycle with query
179    io.forwardValidFast(i) := parallelFwdResult.validFast
180    // valid is generated 1 cycle after query request
181    io.forwardValid(i) := parallelFwdResult.valid
182    // data is generated 1 cycle after query request
183    io.forwardData(i) := parallelFwdResult.data
184
185  })
186}
187
188class SQDataEntry(implicit p: Parameters) extends XSBundle {
189  // val paddr = UInt(PAddrBits.W)
190  val mask = UInt(8.W)
191  val data = UInt(XLEN.W)
192}
193
194class SQDataModule(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
195  val io = IO(new Bundle() {
196    val raddr = Vec(numRead,  Input(UInt(log2Up(numEntries).W)))
197    val rdata = Vec(numRead,  Output(new SQDataEntry))
198    val data = new Bundle() {
199      val wen   = Vec(numWrite, Input(Bool()))
200      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
201      val wdata = Vec(numWrite, Input(UInt(XLEN.W)))
202    }
203    val mask = new Bundle() {
204      val wen   = Vec(numWrite, Input(Bool()))
205      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
206      val wdata = Vec(numWrite, Input(UInt(8.W)))
207    }
208
209    val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W))))
210    val forwardMaskFast = Vec(numForward, Output(Vec(8, Bool())))
211    val forwardMask = Vec(numForward, Output(Vec(8, Bool())))
212    val forwardData = Vec(numForward, Output(Vec(8, UInt(8.W))))
213  })
214
215  val data8 = Seq.fill(8)(Module(new SQData8Module(numEntries, numRead, numWrite, numForward)))
216
217  // writeback to lq/sq
218  for (i <- 0 until numWrite) {
219    // write to data8
220    for (j <- 0 until 8) {
221      data8(j).io.mask.waddr(i) := io.mask.waddr(i)
222      data8(j).io.mask.wdata(i) := io.mask.wdata(i)(j)
223      data8(j).io.mask.wen(i)   := io.mask.wen(i)
224      data8(j).io.data.waddr(i) := io.data.waddr(i)
225      data8(j).io.data.wdata(i) := io.data.wdata(i)(8*(j+1)-1, 8*j)
226      data8(j).io.data.wen(i)   := io.data.wen(i)
227    }
228  }
229
230  // destorequeue read data
231  for (i <- 0 until numRead) {
232    for (j <- 0 until 8) {
233      data8(j).io.raddr(i) := io.raddr(i)
234    }
235    io.rdata(i).mask := VecInit((0 until 8).map(j => data8(j).io.rdata(i).valid)).asUInt
236    io.rdata(i).data := VecInit((0 until 8).map(j => data8(j).io.rdata(i).data)).asUInt
237  }
238
239  // DataModuleTemplate should not be used when there're any write conflicts
240  for (i <- 0 until numWrite) {
241    for (j <- i+1 until numWrite) {
242      assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j)))
243    }
244  }
245  for (i <- 0 until numWrite) {
246    for (j <- i+1 until numWrite) {
247      assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j)))
248    }
249  }
250
251  (0 until numForward).map(i => {
252    // parallel fwd logic
253    for (j <- 0 until 8) {
254      data8(j).io.needForward(i) <> io.needForward(i)
255      io.forwardMaskFast(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValidFast(i)))
256      io.forwardMask(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValid(i)))
257      io.forwardData(i) := VecInit((0 until 8).map(j => data8(j).io.forwardData(i)))
258    }
259  })
260}
261