xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueData.scala (revision c6d439803a044ea209139672b25e35fe8d7f4aa0)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*
4* XiangShan is licensed under Mulan PSL v2.
5* You can use this software according to the terms and conditions of the Mulan PSL v2.
6* You may obtain a copy of Mulan PSL v2 at:
7*          http://license.coscl.org.cn/MulanPSL2
8*
9* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
10* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
11* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
12*
13* See the Mulan PSL v2 for more details.
14***************************************************************************************/
15
16package xiangshan.mem
17
18import chipsalliance.rocketchip.config.Parameters
19import chisel3._
20import chisel3.util._
21import utils._
22import xiangshan._
23import xiangshan.cache._
24import xiangshan.cache.{DCacheWordIO, DCacheLineIO, TlbRequestIO, MemoryOpConstants}
25import xiangshan.mem._
26import xiangshan.backend.roq.RoqPtr
27
28class LQDataEntry(implicit p: Parameters) extends XSBundle {
29  // val vaddr = UInt(VAddrBits.W)
30  val paddr = UInt(PAddrBits.W)
31  val mask = UInt(8.W)
32  val data = UInt(XLEN.W)
33  val fwdMask = Vec(8, Bool())
34}
35
36// Data module define
37// These data modules are like SyncDataModuleTemplate, but support cam-like ops
38class LQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
39  val io = IO(new Bundle {
40    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
41    val rdata = Output(Vec(numRead, UInt((PAddrBits).W)))
42    val wen   = Input(Vec(numWrite, Bool()))
43    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
44    val wdata = Input(Vec(numWrite, UInt((PAddrBits).W)))
45    val violationMdata = Input(Vec(2, UInt((PAddrBits).W)))
46    val violationMmask = Output(Vec(2, Vec(numEntries, Bool())))
47    val refillMdata = Input(UInt((PAddrBits).W))
48    val refillMmask = Output(Vec(numEntries, Bool()))
49  })
50
51  val data = Reg(Vec(numEntries, UInt((PAddrBits).W)))
52
53  // read ports
54  for (i <- 0 until numRead) {
55    io.rdata(i) := data(RegNext(io.raddr(i)))
56  }
57
58  // below is the write ports (with priorities)
59  for (i <- 0 until numWrite) {
60    when (io.wen(i)) {
61      data(io.waddr(i)) := io.wdata(i)
62    }
63  }
64
65  // content addressed match
66  for (i <- 0 until 2) {
67    for (j <- 0 until numEntries) {
68      io.violationMmask(i)(j) := io.violationMdata(i)(PAddrBits-1, 3) === data(j)(PAddrBits-1, 3)
69    }
70  }
71
72  for (j <- 0 until numEntries) {
73    io.refillMmask(j) := get_block_addr(io.refillMdata) === get_block_addr(data(j))
74  }
75
76  // DataModuleTemplate should not be used when there're any write conflicts
77  for (i <- 0 until numWrite) {
78    for (j <- i+1 until numWrite) {
79      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
80    }
81  }
82}
83
84class MaskModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule {
85  val io = IO(new Bundle {
86    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
87    val rdata = Output(Vec(numRead, UInt(8.W)))
88    val wen   = Input(Vec(numWrite, Bool()))
89    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
90    val wdata = Input(Vec(numWrite, UInt(8.W)))
91    val violationMdata = Input(Vec(2, UInt((PAddrBits).W)))
92    val violationMmask = Output(Vec(2, Vec(numEntries, Bool())))
93  })
94
95  val data = Reg(Vec(numEntries, UInt(8.W)))
96
97  // read ports
98  for (i <- 0 until numRead) {
99    io.rdata(i) := data(RegNext(io.raddr(i)))
100  }
101
102  // below is the write ports (with priorities)
103  for (i <- 0 until numWrite) {
104    when (io.wen(i)) {
105      data(io.waddr(i)) := io.wdata(i)
106    }
107  }
108
109  // content addressed match
110  for (i <- 0 until 2) {
111    for (j <- 0 until numEntries) {
112      io.violationMmask(i)(j) := (io.violationMdata(i) & data(j)).orR
113    }
114  }
115
116  // DataModuleTemplate should not be used when there're any write conflicts
117  for (i <- 0 until numWrite) {
118    for (j <- i+1 until numWrite) {
119      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
120    }
121  }
122}
123
124// class LQData8Module(numEntries: Int, numRead: Int, numWrite: Int) extends XSModule with HasDCacheParameters {
125//   val io = IO(new Bundle {
126//     // read
127//     val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
128//     val rdata = Output(Vec(numRead, UInt(8.W)))
129//     // address indexed write
130//     val wen   = Input(Vec(numWrite, Bool()))
131//     val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
132//     val wdata = Input(Vec(numWrite, UInt(8.W)))
133//     // masked write
134//     val mwmask = Input(Vec(blockWords, Vec(numEntries, Bool())))
135//     val mwdata = Input(Vec(blockWords, UInt(8.W)))
136//   })
137
138//   val data = Reg(Vec(numEntries, UInt(8.W)))
139
140//   // read ports
141//   for (i <- 0 until numRead) {
142//     io.rdata(i) := data(RegNext(io.raddr(i)))
143//   }
144
145//   // below is the write ports (with priorities)
146//   for (i <- 0 until numWrite) {
147//     when (io.wen(i)) {
148//       data(io.waddr(i)) := io.wdata(i)
149//     }
150//   }
151
152//   // masked write
153//   for (j <- 0 until numEntries) {
154//     val wen = VecInit((0 until blockWords).map(i => io.mwmask(i)(j))).asUInt.orR
155//     when (wen) {
156//       data(j) := VecInit((0 until blockWords).map(i => {
157//         Mux(io.mwmask(i)(j), io.mwdata(i), 0.U)
158//       })).reduce(_ | _)
159//     }
160//   }
161
162//   // DataModuleTemplate should not be used when there're any write conflicts
163//   for (i <- 0 until numWrite) {
164//     for (j <- i+1 until numWrite) {
165//       assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
166//     }
167//   }
168// }
169
170class CoredataModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
171  val io = IO(new Bundle {
172    // data io
173    // read
174    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
175    val rdata = Output(Vec(numRead, UInt(XLEN.W)))
176    // address indexed write
177    val wen   = Input(Vec(numWrite, Bool()))
178    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
179    val wdata = Input(Vec(numWrite, UInt(XLEN.W)))
180    // masked write
181    val mwmask = Input(Vec(numEntries, Bool()))
182    val refillData = Input(UInt((cfg.blockBytes * 8).W))
183
184    // fwdMask io
185    val fwdMaskWdata = Input(Vec(numWrite, UInt(8.W)))
186    val fwdMaskWen = Input(Vec(numWrite, Bool()))
187    // fwdMaskWaddr = waddr
188
189    // paddr io
190    // 3 bits in paddr need to be stored in CoredataModule for refilling
191    val paddrWdata = Input(Vec(numWrite, UInt((PAddrBits).W)))
192    val paddrWen = Input(Vec(numWrite, Bool()))
193  })
194
195  val data8 = Seq.fill(8)(Module(new MaskedSyncDataModuleTemplate(UInt(8.W), numEntries, numRead, numWrite, numMWrite = blockWords)))
196  val fwdMask = Reg(Vec(numEntries, UInt(8.W)))
197  val wordIndex = Reg(Vec(numEntries, UInt((blockOffBits - wordOffBits).W)))
198
199  // read ports
200  for (i <- 0 until numRead) {
201    for (j <- 0 until 8) {
202      data8(j).io.raddr(i) := io.raddr(i)
203    }
204    io.rdata(i) := VecInit((0 until 8).map(j => data8(j).io.rdata(i))).asUInt
205  }
206
207  // below is the write ports (with priorities)
208  for (i <- 0 until numWrite) {
209    // write to data8
210    for (j <- 0 until 8) {
211      data8(j).io.waddr(i) := io.waddr(i)
212      data8(j).io.wdata(i) := io.wdata(i)(8*(j+1)-1, 8*j)
213      data8(j).io.wen(i) := io.wen(i)
214    }
215
216    // write ctrl info
217    when (io.fwdMaskWen(i)) {
218      fwdMask(io.waddr(i)) := io.fwdMaskWdata(i)
219    }
220    when (io.paddrWen(i)) {
221      wordIndex(io.waddr(i)) := get_word(io.paddrWdata(i))
222    }
223  }
224
225  // write refilled data to data8
226
227  // select refill data
228  // split dcache result into words
229  val words = VecInit((0 until blockWords) map { i => io.refillData(DataBits * (i + 1) - 1, DataBits * i)})
230  // select refill data according to wordIndex (paddr)
231  for (i <- 0 until 8) {
232    for (j <- 0 until blockWords) {
233      data8(i).io.mwdata(j) := words(j)(8*(i+1)-1, 8*i)
234    }
235  }
236
237  // gen refill wmask
238  for (j <- 0 until blockWords) {
239    for (k <- 0 until numEntries) {
240      val wordMatch = wordIndex(k) === j.U
241      for (i <- 0 until 8) {
242        data8(i).io.mwmask(j)(k) := wordMatch && io.mwmask(k) && !fwdMask(k)(i)
243      }
244    }
245  }
246
247  // DataModuleTemplate should not be used when there're any write conflicts
248  for (i <- 0 until numWrite) {
249    for (j <- i+1 until numWrite) {
250      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
251    }
252  }
253}
254
255class LoadQueueData(size: Int, wbNumRead: Int, wbNumWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
256  val io = IO(new Bundle() {
257    val wb = new Bundle() {
258      val wen = Vec(wbNumWrite, Input(Bool()))
259      val waddr = Input(Vec(wbNumWrite, UInt(log2Up(size).W)))
260      val wdata = Input(Vec(wbNumWrite, new LQDataEntry))
261      val raddr = Input(Vec(wbNumRead, UInt(log2Up(size).W)))
262      val rdata = Output(Vec(wbNumRead, new LQDataEntry))
263    }
264    val uncache = new Bundle() {
265      val wen = Input(Bool())
266      val waddr = Input(UInt(log2Up(size).W))
267      val wdata = Input(UInt(XLEN.W)) // only write back uncache data
268      val raddr = Input(UInt(log2Up(size).W))
269      val rdata = Output(new LQDataEntry)
270    }
271    val refill = new Bundle() {
272      val valid = Input(Bool())
273      val paddr = Input(UInt(PAddrBits.W))
274      val data = Input(UInt((cfg.blockBytes * 8).W))
275      val refillMask = Input(Vec(size, Bool()))
276      val matchMask = Output(Vec(size, Bool()))
277    }
278    val violation = Vec(StorePipelineWidth, new Bundle() {
279      val paddr = Input(UInt(PAddrBits.W))
280      val mask = Input(UInt(8.W))
281      val violationMask = Output(Vec(size, Bool()))
282    })
283    val debug = Output(Vec(size, new LQDataEntry))
284
285    def wbWrite(channel: Int, waddr: UInt, wdata: LQDataEntry): Unit = {
286      require(channel < wbNumWrite && wbNumWrite >= 0)
287      // need extra "this.wb(channel).wen := true.B"
288      this.wb.waddr(channel) := waddr
289      this.wb.wdata(channel) := wdata
290    }
291
292    def uncacheWrite(waddr: UInt, wdata: UInt): Unit = {
293      // need extra "this.uncache.wen := true.B"
294      this.uncache.waddr := waddr
295      this.uncache.wdata := wdata
296    }
297
298    // def refillWrite(ldIdx: Int): Unit = {
299    // }
300    // use "this.refill.wen(ldIdx) := true.B" instead
301  })
302
303  // val data = Reg(Vec(size, new LQDataEntry))
304  // data module
305  val paddrModule = Module(new LQPaddrModule(size, numRead = 3, numWrite = 2))
306  val maskModule = Module(new MaskModule(size, numRead = 3, numWrite = 2))
307  val coredataModule = Module(new CoredataModule(size, numRead = 3, numWrite = 3))
308
309  // read data
310  // read port 0 -> wbNumRead-1
311  (0 until wbNumRead).map(i => {
312    paddrModule.io.raddr(i) := io.wb.raddr(i)
313    maskModule.io.raddr(i) := io.wb.raddr(i)
314    coredataModule.io.raddr(i) := io.wb.raddr(i)
315
316    io.wb.rdata(i).paddr := paddrModule.io.rdata(i)
317    io.wb.rdata(i).mask := maskModule.io.rdata(i)
318    io.wb.rdata(i).data := coredataModule.io.rdata(i)
319    io.wb.rdata(i).fwdMask := DontCare
320  })
321
322  // read port wbNumRead
323  paddrModule.io.raddr(wbNumRead) := io.uncache.raddr
324  maskModule.io.raddr(wbNumRead) := io.uncache.raddr
325  coredataModule.io.raddr(wbNumRead) := io.uncache.raddr
326
327  io.uncache.rdata.paddr := paddrModule.io.rdata(wbNumRead)
328  io.uncache.rdata.mask := maskModule.io.rdata(wbNumRead)
329  io.uncache.rdata.data := coredataModule.io.rdata(wbNumRead)
330  io.uncache.rdata.fwdMask := DontCare
331
332  // write data
333  // write port 0 -> wbNumWrite-1
334  (0 until wbNumWrite).map(i => {
335    paddrModule.io.wen(i) := false.B
336    maskModule.io.wen(i) := false.B
337    coredataModule.io.wen(i) := false.B
338    coredataModule.io.fwdMaskWen(i) := false.B
339    coredataModule.io.paddrWen(i) := false.B
340
341    paddrModule.io.waddr(i) := io.wb.waddr(i)
342    maskModule.io.waddr(i) := io.wb.waddr(i)
343    coredataModule.io.waddr(i) := io.wb.waddr(i)
344
345    paddrModule.io.wdata(i) := io.wb.wdata(i).paddr
346    maskModule.io.wdata(i) := io.wb.wdata(i).mask
347    coredataModule.io.wdata(i) := io.wb.wdata(i).data
348    coredataModule.io.fwdMaskWdata(i) := io.wb.wdata(i).fwdMask.asUInt
349    coredataModule.io.paddrWdata(i) := io.wb.wdata(i).paddr
350
351    when(io.wb.wen(i)){
352      paddrModule.io.wen(i) := true.B
353      maskModule.io.wen(i) := true.B
354      coredataModule.io.wen(i) := true.B
355      coredataModule.io.fwdMaskWen(i) := true.B
356      coredataModule.io.paddrWen(i) := true.B
357    }
358  })
359
360  // write port wbNumWrite
361  // exceptionModule.io.wen(wbNumWrite) := false.B
362  coredataModule.io.wen(wbNumWrite) := io.uncache.wen
363  coredataModule.io.fwdMaskWen(wbNumWrite) := false.B
364  coredataModule.io.paddrWen(wbNumWrite) := false.B
365
366  coredataModule.io.waddr(wbNumWrite) := io.uncache.waddr
367
368  coredataModule.io.fwdMaskWdata(wbNumWrite) := DontCare
369  coredataModule.io.paddrWdata(wbNumWrite) := DontCare
370  coredataModule.io.wdata(wbNumWrite) := io.uncache.wdata
371
372  // mem access violation check, gen violationMask
373  (0 until StorePipelineWidth).map(i => {
374    paddrModule.io.violationMdata(i) := io.violation(i).paddr
375    maskModule.io.violationMdata(i) := io.violation(i).mask
376    io.violation(i).violationMask := (paddrModule.io.violationMmask(i).asUInt & maskModule.io.violationMmask(i).asUInt).asBools
377    // VecInit((0 until size).map(j => {
378      // val addrMatch = io.violation(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3)
379      // val violationVec = (0 until 8).map(k => data(j).mask(k) && io.violation(i).mask(k))
380      // Cat(violationVec).orR() && addrMatch
381    // }))
382  })
383
384  // refill missed load
385  def mergeRefillData(refill: UInt, fwd: UInt, fwdMask: UInt): UInt = {
386    val res = Wire(Vec(8, UInt(8.W)))
387    (0 until 8).foreach(i => {
388      res(i) := Mux(fwdMask(i), fwd(8 * (i + 1) - 1, 8 * i), refill(8 * (i + 1) - 1, 8 * i))
389    })
390    res.asUInt
391  }
392
393  // gen paddr match mask
394  paddrModule.io.refillMdata := io.refill.paddr
395  (0 until size).map(i => {
396    io.refill.matchMask := paddrModule.io.refillMmask
397    // io.refill.matchMask(i) := get_block_addr(data(i).paddr) === get_block_addr(io.refill.paddr)
398  })
399
400  // refill data according to matchMask, refillMask and refill.valid
401  coredataModule.io.refillData := io.refill.data
402  (0 until size).map(i => {
403    coredataModule.io.mwmask(i) := io.refill.valid && io.refill.matchMask(i) && io.refill.refillMask(i)
404  })
405
406  // debug data read
407  io.debug := DontCare
408}
409