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