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