xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/StoreQueueData.scala (revision ca18a0b47b0e4089fd0dd1c085091cb90bf98f25)
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
29
30// Data module define
31// These data modules are like SyncDataModuleTemplate, but support cam-like ops
32class SQAddrModule(dataWidth: Int, numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters {
33  val io = IO(new Bundle {
34    val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W)))
35    val rdata = Output(Vec(numRead, UInt(dataWidth.W)))
36    val rlineflag = Output(Vec(numRead, Bool()))
37    val wen   = Input(Vec(numWrite, Bool()))
38    val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W)))
39    val wdata = Input(Vec(numWrite, UInt(dataWidth.W)))
40    val wlineflag = Input(Vec(numWrite, Bool()))
41    val forwardMdata = Input(Vec(numForward, UInt(dataWidth.W)))
42    val forwardMmask = Output(Vec(numForward, Vec(numEntries, Bool())))
43    val debug_data = Output(Vec(numEntries, UInt(dataWidth.W)))
44  })
45
46  val data = Reg(Vec(numEntries, UInt(dataWidth.W)))
47  val lineflag = Reg(Vec(numEntries, Bool())) // cache line match flag
48  // if lineflag == true, this address points to a whole cacheline
49  io.debug_data := data
50
51  // read ports
52  for (i <- 0 until numRead) {
53    io.rdata(i) := data(RegNext(io.raddr(i)))
54    io.rlineflag(i) := lineflag(RegNext(io.raddr(i)))
55  }
56
57  // below is the write ports (with priorities)
58  for (i <- 0 until numWrite) {
59    when (io.wen(i)) {
60      data(io.waddr(i)) := io.wdata(i)
61      lineflag(io.waddr(i)) := io.wlineflag(i)
62    }
63  }
64
65  // content addressed match
66  for (i <- 0 until numForward) {
67    for (j <- 0 until numEntries) {
68      // io.forwardMmask(i)(j) := io.forwardMdata(i)(dataWidth-1, 3) === data(j)(dataWidth-1, 3)
69      val linehit = io.forwardMdata(i)(dataWidth-1, DCacheLineOffset) === data(j)(dataWidth-1, DCacheLineOffset)
70      val wordhit = io.forwardMdata(i)(DCacheLineOffset-1, DCacheWordOffset) === data(j)(DCacheLineOffset-1, DCacheWordOffset)
71      io.forwardMmask(i)(j) := linehit && (wordhit || lineflag(j))
72    }
73  }
74
75  // DataModuleTemplate should not be used when there're any write conflicts
76  for (i <- 0 until numWrite) {
77    for (j <- i+1 until numWrite) {
78      assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
79    }
80  }
81}
82
83class SQData8Entry(implicit p: Parameters) extends XSBundle {
84  // val paddr = UInt(PAddrBits.W)
85  val valid = Bool()
86  val data = UInt((XLEN/8).W)
87}
88
89class SQData8Module(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
90  val io = IO(new Bundle() {
91    val raddr = Vec(numRead,  Input(UInt(log2Up(numEntries).W)))
92    val rdata = Vec(numRead,  Output(new SQData8Entry))
93    val data = new Bundle() {
94      val wen   = Vec(numWrite, Input(Bool()))
95      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
96      val wdata = Vec(numWrite, Input(UInt((XLEN/8).W)))
97    }
98    val mask = new Bundle() {
99      val wen   = Vec(numWrite, Input(Bool()))
100      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
101      val wdata = Vec(numWrite, Input(Bool()))
102    }
103
104    val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W))))
105    val forwardValidFast = Vec(numForward, Output(Bool()))
106    val forwardValid = Vec(numForward, Output(Bool()))
107    val forwardData = Vec(numForward, Output(UInt(8.W)))
108  })
109
110  io := DontCare
111
112  val data = Reg(Vec(numEntries, new SQData8Entry))
113
114  // writeback to sq
115  (0 until numWrite).map(i => {
116    when(io.data.wen(i)){
117      data(io.data.waddr(i)).data := io.data.wdata(i)
118    }
119  })
120  (0 until numWrite).map(i => {
121    when(io.mask.wen(i)){
122      data(io.mask.waddr(i)).valid := io.mask.wdata(i)
123    }
124  })
125
126  // destorequeue read data
127  (0 until numRead).map(i => {
128      io.rdata(i) := data(RegNext(io.raddr(i)))
129  })
130
131  // DataModuleTemplate should not be used when there're any write conflicts
132  for (i <- 0 until numWrite) {
133    for (j <- i+1 until numWrite) {
134      assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j)))
135    }
136  }
137  for (i <- 0 until numWrite) {
138    for (j <- i+1 until numWrite) {
139      assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j)))
140    }
141  }
142
143  // forwarding
144  // Compare ringBufferTail (deqPtr) and forward.sqIdx, we have two cases:
145  // (1) if they have the same flag, we need to check range(tail, sqIdx)
146  // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx)
147  // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize))
148  // Forward2: Mux(same_flag, 0.U,                   range(0, sqIdx)    )
149  // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise
150
151  // entry with larger index should have higher priority since it's data is younger
152
153  (0 until numForward).map(i => {
154    // parallel fwd logic
155    val matchResultVec = Wire(Vec(numEntries * 2, new FwdEntry))
156
157    def parallelFwd(xs: Seq[Data]): Data = {
158      ParallelOperation(xs, (a: Data, b: Data) => {
159        val l = a.asTypeOf(new FwdEntry)
160        val r = b.asTypeOf(new FwdEntry)
161        val res = Wire(new FwdEntry)
162        res.validFast := l.validFast || r.validFast
163        res.valid := l.valid || r.valid
164        // res.valid := RegNext(res.validFast)
165        res.data := Mux(r.valid, r.data, l.data)
166        res
167      })
168    }
169
170    for (j <- 0 until numEntries) {
171      val needCheck0 = io.needForward(i)(0)(j)
172      val needCheck1 = io.needForward(i)(1)(j)
173      val needCheck0Reg = RegNext(needCheck0)
174      val needCheck1Reg = RegNext(needCheck1)
175      (0 until XLEN / 8).foreach(k => {
176        matchResultVec(j).validFast := needCheck0 && data(j).valid
177        matchResultVec(j).valid := needCheck0Reg && data(j).valid
178        matchResultVec(j).data := data(j).data
179        matchResultVec(numEntries + j).validFast := needCheck1 && data(j).valid
180        matchResultVec(numEntries + j).valid := needCheck1Reg && data(j).valid
181        matchResultVec(numEntries + j).data := data(j).data
182      })
183    }
184
185    val parallelFwdResult = parallelFwd(matchResultVec).asTypeOf(new FwdEntry)
186
187    // validFast is generated the same cycle with query
188    io.forwardValidFast(i) := parallelFwdResult.validFast
189    // valid is generated 1 cycle after query request
190    io.forwardValid(i) := parallelFwdResult.valid
191    // data is generated 1 cycle after query request
192    io.forwardData(i) := parallelFwdResult.data
193
194  })
195}
196
197class SQDataEntry(implicit p: Parameters) extends XSBundle {
198  // val paddr = UInt(PAddrBits.W)
199  val mask = UInt(8.W)
200  val data = UInt(XLEN.W)
201}
202
203class SQDataModule(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
204  val io = IO(new Bundle() {
205    val raddr = Vec(numRead,  Input(UInt(log2Up(numEntries).W)))
206    val rdata = Vec(numRead,  Output(new SQDataEntry))
207    val data = new Bundle() {
208      val wen   = Vec(numWrite, Input(Bool()))
209      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
210      val wdata = Vec(numWrite, Input(UInt(XLEN.W)))
211    }
212    val mask = new Bundle() {
213      val wen   = Vec(numWrite, Input(Bool()))
214      val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
215      val wdata = Vec(numWrite, Input(UInt(8.W)))
216    }
217
218    val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W))))
219    val forwardMaskFast = Vec(numForward, Output(Vec(8, Bool())))
220    val forwardMask = Vec(numForward, Output(Vec(8, Bool())))
221    val forwardData = Vec(numForward, Output(Vec(8, UInt(8.W))))
222  })
223
224  val data8 = Seq.fill(8)(Module(new SQData8Module(numEntries, numRead, numWrite, numForward)))
225
226  // writeback to lq/sq
227  for (i <- 0 until numWrite) {
228    // write to data8
229    for (j <- 0 until 8) {
230      data8(j).io.mask.waddr(i) := io.mask.waddr(i)
231      data8(j).io.mask.wdata(i) := io.mask.wdata(i)(j)
232      data8(j).io.mask.wen(i)   := io.mask.wen(i)
233      data8(j).io.data.waddr(i) := io.data.waddr(i)
234      data8(j).io.data.wdata(i) := io.data.wdata(i)(8*(j+1)-1, 8*j)
235      data8(j).io.data.wen(i)   := io.data.wen(i)
236    }
237  }
238
239  // destorequeue read data
240  for (i <- 0 until numRead) {
241    for (j <- 0 until 8) {
242      data8(j).io.raddr(i) := io.raddr(i)
243    }
244    io.rdata(i).mask := VecInit((0 until 8).map(j => data8(j).io.rdata(i).valid)).asUInt
245    io.rdata(i).data := VecInit((0 until 8).map(j => data8(j).io.rdata(i).data)).asUInt
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.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j)))
252    }
253  }
254  for (i <- 0 until numWrite) {
255    for (j <- i+1 until numWrite) {
256      assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j)))
257    }
258  }
259
260  (0 until numForward).map(i => {
261    // parallel fwd logic
262    for (j <- 0 until 8) {
263      data8(j).io.needForward(i) <> io.needForward(i)
264      io.forwardMaskFast(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValidFast(i)))
265      io.forwardMask(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValid(i)))
266      io.forwardData(i) := VecInit((0 until 8).map(j => data8(j).io.forwardData(i)))
267    }
268  })
269}
270