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