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