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