xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueData.scala (revision beabc72d8a9f24321dc471875029b6dea04f6b13)
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.rob.RobPtr
28
29class LQDataEntry(implicit p: Parameters) extends XSBundle {
30  // val vaddr = UInt(VAddrBits.W)
31  val paddr = UInt(PAddrBits.W)
32  val mask = UInt(8.W)
33  val data = UInt(XLEN.W)
34  val fwdMask = Vec(8, Bool())
35}
36
37// Data module define
38// These data modules are like SyncDataModuleTemplate, but support cam-like ops
39class LQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
40  val io = IO(new Bundle {
41    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
42    val rdata = Output(Vec(numRead, UInt((PAddrBits).W)))
43    val wen   = Input(Vec(numWrite, Bool()))
44    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
45    val wdata = Input(Vec(numWrite, UInt((PAddrBits).W)))
46    val violationMdata = Input(Vec(StorePipelineWidth, UInt((PAddrBits).W)))
47    val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool())))
48    val releaseMdata = Input(Vec(LoadPipelineWidth, UInt((PAddrBits).W)))
49    val releaseMmask = Output(Vec(LoadPipelineWidth, Vec(numEntries, Bool())))
50    val refillMdata = Input(UInt((PAddrBits).W))
51    val refillMmask = Output(Vec(numEntries, Bool()))
52  })
53
54  val data = Reg(Vec(numEntries, UInt((PAddrBits).W)))
55
56  // read ports
57  for (i <- 0 until numRead) {
58    io.rdata(i) := data(RegNext(io.raddr(i)))
59  }
60
61  // below is the write ports (with priorities)
62  for (i <- 0 until numWrite) {
63    when (io.wen(i)) {
64      data(io.waddr(i)) := io.wdata(i)
65    }
66  }
67
68  // content addressed match
69  for (i <- 0 until StorePipelineWidth) {
70    for (j <- 0 until numEntries) {
71      io.violationMmask(i)(j) := io.violationMdata(i)(PAddrBits-1, DCacheIndexOffset) === data(j)(PAddrBits-1, DCacheIndexOffset)
72    }
73  }
74  for (i <- 0 until LoadPipelineWidth) {
75    for (j <- 0 until numEntries) {
76      io.releaseMmask(i)(j) := io.releaseMdata(i)(PAddrBits-1, DCacheIndexOffset) === data(j)(PAddrBits-1, DCacheIndexOffset)
77    }
78  }
79
80  for (j <- 0 until numEntries) {
81    io.refillMmask(j) := get_refill_addr(io.refillMdata) === get_refill_addr(data(j))
82  }
83
84  // DataModuleTemplate should not be used when there're any write conflicts
85  for (i <- 0 until numWrite) {
86    for (j <- i+1 until numWrite) {
87      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
88    }
89  }
90}
91
92class MaskModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule {
93  val io = IO(new Bundle {
94    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
95    val rdata = Output(Vec(numRead, UInt(8.W)))
96    val wen   = Input(Vec(numWrite, Bool()))
97    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
98    val wdata = Input(Vec(numWrite, UInt(8.W)))
99    val violationMdata = Input(Vec(StorePipelineWidth, UInt((PAddrBits).W)))
100    val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool())))
101  })
102
103  val data = Reg(Vec(numEntries, UInt(8.W)))
104
105  // read ports
106  for (i <- 0 until numRead) {
107    io.rdata(i) := data(RegNext(io.raddr(i)))
108  }
109
110  // below is the write ports (with priorities)
111  for (i <- 0 until numWrite) {
112    when (io.wen(i)) {
113      data(io.waddr(i)) := io.wdata(i)
114    }
115  }
116
117  // content addressed match
118  for (i <- 0 until StorePipelineWidth) {
119    for (j <- 0 until numEntries) {
120      io.violationMmask(i)(j) := (io.violationMdata(i) & data(j)).orR
121    }
122  }
123
124  // DataModuleTemplate should not be used when there're any write conflicts
125  for (i <- 0 until numWrite) {
126    for (j <- i+1 until numWrite) {
127      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
128    }
129  }
130}
131
132// class LQData8Module(numEntries: Int, numRead: Int, numWrite: Int) extends XSModule with HasDCacheParameters {
133//   val io = IO(new Bundle {
134//     // read
135//     val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
136//     val rdata = Output(Vec(numRead, UInt(8.W)))
137//     // address indexed write
138//     val wen   = Input(Vec(numWrite, Bool()))
139//     val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
140//     val wdata = Input(Vec(numWrite, UInt(8.W)))
141//     // masked write
142//     val mwmask = Input(Vec(blockWords, Vec(numEntries, Bool())))
143//     val mwdata = Input(Vec(blockWords, UInt(8.W)))
144//   })
145
146//   val data = Reg(Vec(numEntries, UInt(8.W)))
147
148//   // read ports
149//   for (i <- 0 until numRead) {
150//     io.rdata(i) := data(RegNext(io.raddr(i)))
151//   }
152
153//   // below is the write ports (with priorities)
154//   for (i <- 0 until numWrite) {
155//     when (io.wen(i)) {
156//       data(io.waddr(i)) := io.wdata(i)
157//     }
158//   }
159
160//   // masked write
161//   for (j <- 0 until numEntries) {
162//     val wen = VecInit((0 until blockWords).map(i => io.mwmask(i)(j))).asUInt.orR
163//     when (wen) {
164//       data(j) := VecInit((0 until blockWords).map(i => {
165//         Mux(io.mwmask(i)(j), io.mwdata(i), 0.U)
166//       })).reduce(_ | _)
167//     }
168//   }
169
170//   // DataModuleTemplate should not be used when there're any write conflicts
171//   for (i <- 0 until numWrite) {
172//     for (j <- i+1 until numWrite) {
173//       assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
174//     }
175//   }
176// }
177
178class CoredataModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
179  val io = IO(new Bundle {
180    // data io
181    // read
182    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
183    val rdata = Output(Vec(numRead, UInt(XLEN.W)))
184    // address indexed write
185    val wen   = Input(Vec(numWrite, Bool()))
186    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
187    val wdata = Input(Vec(numWrite, UInt(XLEN.W)))
188    // masked write
189    val mwmask = Input(Vec(numEntries, Bool()))
190    val refillData = Input(UInt(l1BusDataWidth.W))
191
192    // fwdMask io
193    val fwdMaskWdata = Input(Vec(numWrite, UInt(8.W)))
194    val fwdMaskWen = Input(Vec(numWrite, Bool()))
195    // fwdMaskWaddr = waddr
196
197    // paddr io
198    // refillOffBits - wordOffBits bits in paddr need to be stored in CoredataModule for refilling
199    val paddrWdata = Input(Vec(numWrite, UInt((PAddrBits).W)))
200    val paddrWen = Input(Vec(numWrite, Bool()))
201  })
202
203  val data8 = Seq.fill(8)(Module(new MaskedSyncDataModuleTemplate(UInt(8.W), numEntries, numRead, numWrite, numMWrite = refillWords)))
204  val fwdMask = Reg(Vec(numEntries, UInt(8.W)))
205  val wordIndex = Reg(Vec(numEntries, UInt((refillOffBits - wordOffBits).W)))
206
207  // read ports
208  for (i <- 0 until numRead) {
209    for (j <- 0 until 8) {
210      data8(j).io.raddr(i) := io.raddr(i)
211    }
212    io.rdata(i) := VecInit((0 until 8).map(j => data8(j).io.rdata(i))).asUInt
213  }
214
215  // below is the write ports (with priorities)
216  for (i <- 0 until numWrite) {
217    // write to data8
218    for (j <- 0 until 8) {
219      data8(j).io.waddr(i) := io.waddr(i)
220      data8(j).io.wdata(i) := io.wdata(i)(8*(j+1)-1, 8*j)
221      data8(j).io.wen(i) := io.wen(i)
222    }
223
224    // write ctrl info
225    when (io.fwdMaskWen(i)) {
226      fwdMask(io.waddr(i)) := io.fwdMaskWdata(i)
227    }
228    when (io.paddrWen(i)) {
229      wordIndex(io.waddr(i)) := get_word(io.paddrWdata(i))
230    }
231  }
232
233  // write refilled data to data8
234
235  // select refill data
236  // split dcache result into words
237  val words = VecInit((0 until refillWords) map { i => io.refillData(DataBits * (i + 1) - 1, DataBits * i)})
238  // select refill data according to wordIndex (paddr)
239  for (i <- 0 until 8) {
240    for (j <- 0 until refillWords) {
241      data8(i).io.mwdata(j) := words(j)(8*(i+1)-1, 8*i)
242    }
243  }
244
245  // gen refill wmask
246  for (j <- 0 until refillWords) {
247    for (k <- 0 until numEntries) {
248      val wordMatch = wordIndex(k) === j.U
249      for (i <- 0 until 8) {
250        data8(i).io.mwmask(j)(k) := wordMatch && io.mwmask(k) && !fwdMask(k)(i)
251      }
252    }
253  }
254
255  // DataModuleTemplate should not be used when there're any write conflicts
256  for (i <- 0 until numWrite) {
257    for (j <- i+1 until numWrite) {
258      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
259    }
260  }
261}
262
263class LoadQueueData(size: Int, wbNumRead: Int, wbNumWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
264  val io = IO(new Bundle() {
265    val wb = new Bundle() {
266      val wen = Vec(wbNumWrite, Input(Bool()))
267      val waddr = Input(Vec(wbNumWrite, UInt(log2Up(size).W)))
268      val wdata = Input(Vec(wbNumWrite, new LQDataEntry))
269      val raddr = Input(Vec(wbNumRead, UInt(log2Up(size).W)))
270      val rdata = Output(Vec(wbNumRead, new LQDataEntry))
271    }
272    val uncache = new Bundle() {
273      val wen = Input(Bool())
274      val waddr = Input(UInt(log2Up(size).W))
275      val wdata = Input(UInt(XLEN.W)) // only write back uncache data
276      val raddr = Input(UInt(log2Up(size).W))
277      val rdata = Output(new LQDataEntry)
278    }
279    val refill = new Bundle() {
280      val valid = Input(Bool())
281      val paddr = Input(UInt(PAddrBits.W))
282      val data = Input(UInt(l1BusDataWidth.W))
283      val refillMask = Input(Vec(size, Bool()))
284      val matchMask = Output(Vec(size, Bool()))
285    }
286    // st-ld violation query, word level cam
287    val violation = Vec(StorePipelineWidth, new Bundle() {
288      val paddr = Input(UInt(PAddrBits.W))
289      val mask = Input(UInt(8.W))
290      val violationMask = Output(Vec(size, Bool()))
291    })
292    // ld-ld violation query, cache line level cam
293    val release_violation = Vec(LoadPipelineWidth, new Bundle() {
294      val paddr = Input(UInt(PAddrBits.W))
295      val match_mask = Output(Vec(size, Bool()))
296      // if ld-ld violation does happened, we replay from the elder load
297    })
298    val debug = Output(Vec(size, new LQDataEntry))
299
300    def wbWrite(channel: Int, waddr: UInt, wdata: LQDataEntry): Unit = {
301      require(channel < wbNumWrite && wbNumWrite >= 0)
302      // need extra "this.wb(channel).wen := true.B"
303      this.wb.waddr(channel) := waddr
304      this.wb.wdata(channel) := wdata
305    }
306
307    def uncacheWrite(waddr: UInt, wdata: UInt): Unit = {
308      // need extra "this.uncache.wen := true.B"
309      this.uncache.waddr := waddr
310      this.uncache.wdata := wdata
311    }
312
313    // def refillWrite(ldIdx: Int): Unit = {
314    // }
315    // use "this.refill.wen(ldIdx) := true.B" instead
316  })
317
318  // val data = Reg(Vec(size, new LQDataEntry))
319  // data module
320  val paddrModule = Module(new LQPaddrModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth))
321  val maskModule = Module(new MaskModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth))
322  val coredataModule = Module(new CoredataModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth+1))
323
324  // read data
325  // read port 0 -> wbNumRead-1
326  (0 until wbNumRead).map(i => {
327    paddrModule.io.raddr(i) := io.wb.raddr(i)
328    maskModule.io.raddr(i) := io.wb.raddr(i)
329    coredataModule.io.raddr(i) := io.wb.raddr(i)
330
331    io.wb.rdata(i).paddr := paddrModule.io.rdata(i)
332    io.wb.rdata(i).mask := maskModule.io.rdata(i)
333    io.wb.rdata(i).data := coredataModule.io.rdata(i)
334    io.wb.rdata(i).fwdMask := DontCare
335  })
336
337  // read port wbNumRead
338  paddrModule.io.raddr(wbNumRead) := io.uncache.raddr
339  maskModule.io.raddr(wbNumRead) := io.uncache.raddr
340  coredataModule.io.raddr(wbNumRead) := io.uncache.raddr
341
342  io.uncache.rdata.paddr := paddrModule.io.rdata(wbNumRead)
343  io.uncache.rdata.mask := maskModule.io.rdata(wbNumRead)
344  io.uncache.rdata.data := coredataModule.io.rdata(wbNumRead)
345  io.uncache.rdata.fwdMask := DontCare
346
347  // write data
348  // write port 0 -> wbNumWrite-1
349  (0 until wbNumWrite).map(i => {
350    paddrModule.io.wen(i) := false.B
351    maskModule.io.wen(i) := false.B
352    coredataModule.io.wen(i) := false.B
353    coredataModule.io.fwdMaskWen(i) := false.B
354    coredataModule.io.paddrWen(i) := false.B
355
356    paddrModule.io.waddr(i) := io.wb.waddr(i)
357    maskModule.io.waddr(i) := io.wb.waddr(i)
358    coredataModule.io.waddr(i) := io.wb.waddr(i)
359
360    paddrModule.io.wdata(i) := io.wb.wdata(i).paddr
361    maskModule.io.wdata(i) := io.wb.wdata(i).mask
362    coredataModule.io.wdata(i) := io.wb.wdata(i).data
363    coredataModule.io.fwdMaskWdata(i) := io.wb.wdata(i).fwdMask.asUInt
364    coredataModule.io.paddrWdata(i) := io.wb.wdata(i).paddr
365
366    when(io.wb.wen(i)){
367      paddrModule.io.wen(i) := true.B
368      maskModule.io.wen(i) := true.B
369      coredataModule.io.wen(i) := true.B
370      coredataModule.io.fwdMaskWen(i) := true.B
371      coredataModule.io.paddrWen(i) := true.B
372    }
373  })
374
375  // write port wbNumWrite
376  // exceptionModule.io.wen(wbNumWrite) := false.B
377  coredataModule.io.wen(wbNumWrite) := io.uncache.wen
378  coredataModule.io.fwdMaskWen(wbNumWrite) := false.B
379  coredataModule.io.paddrWen(wbNumWrite) := false.B
380
381  coredataModule.io.waddr(wbNumWrite) := io.uncache.waddr
382
383  coredataModule.io.fwdMaskWdata(wbNumWrite) := DontCare
384  coredataModule.io.paddrWdata(wbNumWrite) := DontCare
385  coredataModule.io.wdata(wbNumWrite) := io.uncache.wdata
386
387  // st-ld mem access violation check, gen violationMask
388  (0 until StorePipelineWidth).map(i => {
389    paddrModule.io.violationMdata(i) := io.violation(i).paddr
390    maskModule.io.violationMdata(i) := io.violation(i).mask
391    io.violation(i).violationMask := (paddrModule.io.violationMmask(i).asUInt & maskModule.io.violationMmask(i).asUInt).asBools
392  })
393
394  // ld-ld mem access violation check, gen violationMask (cam match mask)
395  (0 until LoadPipelineWidth).map(i => {
396    paddrModule.io.releaseMdata(i) := io.release_violation(i).paddr
397    io.release_violation(i).match_mask := paddrModule.io.releaseMmask(i)
398  })
399
400  // refill missed load
401  def mergeRefillData(refill: UInt, fwd: UInt, fwdMask: UInt): UInt = {
402    val res = Wire(Vec(8, UInt(8.W)))
403    (0 until 8).foreach(i => {
404      res(i) := Mux(fwdMask(i), fwd(8 * (i + 1) - 1, 8 * i), refill(8 * (i + 1) - 1, 8 * i))
405    })
406    res.asUInt
407  }
408
409  // gen paddr match mask
410  paddrModule.io.refillMdata := io.refill.paddr
411  (0 until size).map(i => {
412    io.refill.matchMask := paddrModule.io.refillMmask
413    // io.refill.matchMask(i) := get_block_addr(data(i).paddr) === get_block_addr(io.refill.paddr)
414  })
415
416  // refill data according to matchMask, refillMask and refill.valid
417  coredataModule.io.refillData := io.refill.data
418  (0 until size).map(i => {
419    coredataModule.io.mwmask(i) := io.refill.valid && io.refill.matchMask(i) && io.refill.refillMask(i)
420  })
421
422  // debug data read
423  io.debug := DontCare
424}
425