xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueData.scala (revision 3c808de005aba6d7539d33be9962c44375b97e6d)
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 chisel3._
20import chisel3.util._
21import org.chipsalliance.cde.config.Parameters
22import xiangshan._
23import xiangshan.cache._
24import xiangshan.cache.{DCacheWordIO, DCacheLineIO, MemoryOpConstants}
25import xiangshan.mem._
26import xiangshan.backend.rob.RobPtr
27import utils._
28import utility._
29
30// Data module define
31// These raw data modules are like SyncDataModuleTemplate, but support cam-like ops
32abstract class LqRawDataModule[T <: Data] (
33  gen: T,
34  numEntries: Int,
35  numRead: Int,
36  numWrite: Int,
37  numWBank: Int,
38  numWDelay: Int,
39  numCamPort: Int = 0,
40  enableCacheLineCheck: Boolean = false
41)(implicit p: Parameters) extends XSModule {
42  val io = IO(new Bundle() {
43    val ren   = Input(Vec(numRead, Bool()))
44    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
45    val rdata = Output(Vec(numRead, gen))
46    val wen   = Input(Vec(numWrite, Bool()))
47    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
48    val wdata = Input(Vec(numWrite, gen))
49    // violation cam: hit if addr is in the same cacheline
50    val violationMdata = Input(Vec(numCamPort, gen)) // addr
51    // This `store` writes the whole `cacheline`.(cbo zero).
52    val violationCheckLine = OptionWrapper(enableCacheLineCheck, Input(Vec(numCamPort, Bool())))
53    val violationMmask = Output(Vec(numCamPort, Vec(numEntries, Bool()))) // cam result mask
54    // refill cam: hit if addr is in the same cacheline
55    val releaseMdata = Input(Vec(numCamPort, gen))
56    val releaseMmask = Output(Vec(numCamPort, Vec(numEntries, Bool())))  // cam result mask
57    // release violation cam: hit if addr is in the same cacheline
58    val releaseViolationMdata = Input(Vec(numCamPort, gen))
59    val releaseViolationMmask = Output(Vec(numCamPort, Vec(numEntries, Bool()))) // cam result mask result
60  })
61
62  require(isPow2(numWBank), "write bank must be a power of two!")
63  require(numWBank >= 2, "write bank must be greater than or equal to two!")
64  require(numWDelay >= 1, "write delay must be greater than or equal to one!")
65  require(numCamPort >= 0, "camport must be greater than or equal to zero!")
66  require((numEntries % numWBank == 0), "numEntries must be divided by numWBank!")
67
68  val numEntryPerBank = numEntries / numWBank
69  val dataWidth = gen.getWidth
70
71  val data = Reg(Vec(numEntries, gen))
72  // read ports
73  for (i <- 0 until numRead) {
74    io.rdata(i) := RegEnable(data(io.raddr(i)), io.ren(i))
75  }
76
77  // write ports
78  val writeAddrDec = io.waddr.map(a => UIntToOH(a))
79  def selectBankMask(in: UInt, bank: Int): UInt = {
80    in((bank + 1) * numEntryPerBank - 1, bank * numEntryPerBank)
81  }
82  for (bank <- 0 until numWBank) {
83    // write ports
84    // s0: write to bank level buffer
85    val s0_bankWriteAddrDec = writeAddrDec.map(a => selectBankMask(a, bank))
86    val s0_bankWriteEn = io.wen.zip(s0_bankWriteAddrDec).map(w => w._1 && w._2.orR)
87    s0_bankWriteAddrDec.zipWithIndex.map(a =>
88      a._1.suggestName("s0_bankWriteAddrDec" + bank + "_" + a._2)
89    )
90    s0_bankWriteEn.zipWithIndex.map(a =>
91      a._1.suggestName("s0_bankWriteEn" + bank + "_" + a._2)
92    )
93    // sx: write data to entries
94    val sx_bankWriteAddrDec_resp = (0 until numWrite).map(w => DelayNWithValid(s0_bankWriteAddrDec(w), io.wen(w), numWDelay - 1))
95    val sx_bankWriteAddrDec = (0 until numWrite).map(w => sx_bankWriteAddrDec_resp(w)._2)
96    val sx_bankWriteEn = s0_bankWriteEn.map(w => DelayN(w, numWDelay - 1))
97     val sx_writeData_resp = (0 until numWrite).map(w => DelayNWithValid(io.wdata(w), io.wen(w), numWDelay - 1))
98     val sx_writeData =  (0 until numWrite).map(w => sx_writeData_resp(w)._2)
99
100    sx_bankWriteAddrDec.zipWithIndex.map(a =>
101      a._1.suggestName("sx_bankWriteAddrDec" + bank + "_" + a._2)
102    )
103    sx_bankWriteEn.zipWithIndex.map(a =>
104      a._1.suggestName("sx_bankWriteEn" + bank + "_" + a._2)
105    )
106    sx_writeData.zipWithIndex.map(a =>
107      a._1.suggestName("sx_writeData" + bank + "_" + a._2)
108    )
109
110    // entry write
111    for (entry <- 0 until numEntryPerBank) {
112      // write ports
113      val sx_entryWriteEnVec = sx_bankWriteEn.zip(sx_bankWriteAddrDec).map(w => w._1 && w._2(entry))
114      val sx_entryWriteEn = VecInit(sx_entryWriteEnVec).asUInt.orR
115      val sx_entryWriteData = Mux1H(sx_entryWriteEnVec, sx_writeData)
116      when (sx_entryWriteEn) {
117        data(bank * numEntryPerBank + entry) := sx_entryWriteData
118      }
119      sx_entryWriteEnVec.zipWithIndex.map(a =>
120        a._1.suggestName("sx_entryWriteEnVec" + bank + "_" + entry + "_" + a._2)
121      )
122      sx_entryWriteEn.suggestName("sx_entryWriteEn" + bank + "_" + entry)
123      sx_entryWriteData.suggestName("sx_entryWriteData" + bank + "_" + entry)
124    }
125  }
126
127  // DataModuleTemplate should not be used when there're any write conflicts
128  for (i <- 0 until numWrite) {
129    for (j <- i+1 until numWrite) {
130      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
131    }
132  }
133}
134
135// Load queue physical address module
136class LqPAddrModule[T <: UInt](
137  gen: T,
138  numEntries: Int,
139  numRead: Int,
140  numWrite: Int,
141  numWBank: Int,
142  numWDelay: Int = 1,
143  numCamPort: Int = 1,
144  enableCacheLineCheck: Boolean = false, // Check the entire cacheline. when enabled, set `paddrOffset` correctly.
145  paddrOffset: Int // The least significant `paddrOffset` bits of paddr are neglected.
146)(implicit p: Parameters) extends LqRawDataModule(gen, numEntries, numRead, numWrite, numWBank, numWDelay, numCamPort, enableCacheLineCheck)
147  with HasDCacheParameters
148{
149  // content addressed match
150  // 128-bits aligned
151  val needCacheLineCheck = enableCacheLineCheck && DCacheLineOffset > paddrOffset
152  for (i <- 0 until numCamPort) {
153    for (j <- 0 until numEntries) {
154      if (needCacheLineCheck) {
155        val cacheLineOffset = DCacheLineOffset - paddrOffset
156        val cacheLineHit    = io.violationMdata(i)(dataWidth - 1, cacheLineOffset) === data(j)(dataWidth - 1, cacheLineOffset)
157        val lowAddrHit      = io.violationMdata(i)(cacheLineOffset - 1, 0) === data(j)(cacheLineOffset - 1, 0)
158        io.violationMmask(i)(j) := cacheLineHit && (io.violationCheckLine.get(i) || lowAddrHit)
159      } else {
160        io.violationMmask(i)(j) := io.violationMdata(i) === data(j)
161      }
162
163    }
164  }
165
166  // content addressed match
167  // cacheline aligned
168  for (i <- 0 until numCamPort) {
169    for (j <- 0 until numEntries) {
170      io.releaseViolationMmask(i)(j) := io.releaseViolationMdata(i) === data(j)
171    }
172  }
173
174  // content addressed match
175  // cacheline aligned
176  for (i <- 0 until numCamPort) {
177    for (j <- 0 until numEntries) {
178      io.releaseMmask(i)(j) := io.releaseMdata(i) === data(j)
179    }
180  }
181}
182
183// Load queue data module
184class LqVAddrModule[T <: UInt](
185  gen: T,
186  numEntries: Int,
187  numRead: Int,
188  numWrite: Int,
189  numWBank: Int,
190  numWDelay: Int = 1,
191  numCamPort: Int = 1)(implicit p: Parameters) extends LqRawDataModule(gen, numEntries, numRead, numWrite, numWBank, numWDelay, numCamPort)
192  with HasDCacheParameters
193{
194  // content addressed match
195  for (i <- 0 until numCamPort) {
196    for (j <- 0 until numEntries) {
197      io.violationMmask(i)(j) := io.violationMdata(i)(VAddrBits-1, DCacheVWordOffset) === data(j)(VAddrBits-1, DCacheVWordOffset)
198    }
199  }
200
201  // content addressed match
202  for (i <- 0 until numCamPort) {
203    for (j <- 0 until numEntries) {
204      io.releaseMmask(i)(j) := io.releaseMdata(i)(VAddrBits-1, DCacheLineOffset) === data(j)(VAddrBits-1, DCacheLineOffset)
205    }
206  }
207}
208
209// Load queue mask module
210class LqMaskModule[T <: UInt](
211  gen: T,
212  numEntries: Int,
213  numRead: Int,
214  numWrite: Int,
215  numWBank: Int,
216  numWDelay: Int = 1,
217  numCamPort: Int = 1)(implicit p: Parameters) extends LqRawDataModule(gen, numEntries, numRead, numWrite, numWBank, numWDelay, numCamPort)
218  with HasDCacheParameters
219{
220  // content addressed match
221  for (i <- 0 until numCamPort) {
222    for (j <- 0 until numEntries) {
223      io.violationMmask(i)(j) := (io.violationMdata(i) & data(j)).orR
224    }
225  }
226  // content addressed match
227  // cacheline aligned
228  for (i <- 0 until numCamPort) {
229    for (j <- 0 until numEntries) {
230      io.releaseViolationMmask(i)(j) := (io.releaseViolationMdata(i) & data(j)).orR
231    }
232  }
233
234  // content addressed match
235  for (i <- 0 until numCamPort) {
236    for (j <- 0 until numEntries) {
237      io.releaseMmask(i)(j) := (io.releaseMdata(i) & data(j)).orR
238    }
239  }
240}
241