xref: /XiangShan/src/main/scala/xiangshan/mem/MemCommon.scala (revision 92b88f30156d46e844042eea94f7121557fd09a1)
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
19
20import chipsalliance.rocketchip.config.Parameters
21import chisel3._
22import chisel3.util._
23import utility._
24import utils._
25import xiangshan._
26import xiangshan.backend.Bundles.{DynInst, MemExuInput}
27import xiangshan.backend.rob.RobPtr
28import xiangshan.cache._
29import xiangshan.cache.dcache.ReplayCarry
30
31object genWmask {
32  def apply(addr: UInt, sizeEncode: UInt): UInt = {
33    (LookupTree(sizeEncode, List(
34      "b00".U -> 0x1.U, //0001 << addr(2:0)
35      "b01".U -> 0x3.U, //0011
36      "b10".U -> 0xf.U, //1111
37      "b11".U -> 0xff.U //11111111
38    )) << addr(2, 0)).asUInt()
39  }
40}
41
42object genWdata {
43  def apply(data: UInt, sizeEncode: UInt): UInt = {
44    LookupTree(sizeEncode, List(
45      "b00".U -> Fill(8, data(7, 0)),
46      "b01".U -> Fill(4, data(15, 0)),
47      "b10".U -> Fill(2, data(31, 0)),
48      "b11".U -> data
49    ))
50  }
51}
52
53class LsPipelineBundle(implicit val p: Parameters) extends Bundle with HasXSParameter with HasDCacheParameters{
54  val uop = new DynInst
55  val vaddr = UInt(VAddrBits.W)
56  val paddr = UInt(PAddrBits.W)
57  // val func = UInt(6.W)
58  val mask = UInt(8.W)
59  val data = UInt((XLEN+1).W)
60  val wlineflag = Bool() // store write the whole cache line
61
62  val miss = Bool()
63  val tlbMiss = Bool()
64  val ptwBack = Bool()
65  val mmio = Bool()
66  val atomic = Bool()
67  val rsIdx = UInt(log2Up(MemIQSizeMax).W)
68
69  val forwardMask = Vec(8, Bool())
70  val forwardData = Vec(8, UInt(8.W))
71
72  // prefetch
73  val isPrefetch = Bool()
74  val isHWPrefetch = Bool()
75  def isSWPrefetch = isPrefetch && !isHWPrefetch
76
77  // For debug usage
78  val isFirstIssue = Bool()
79
80  // For load replay
81  val isLoadReplay = Bool()
82  val replayCarry = new ReplayCarry
83
84  // For dcache miss load
85  val mshrid = UInt(log2Up(cfg.nMissEntries).W)
86
87  val forward_tlDchannel = Bool()
88  val dcacheRequireReplay = Bool()
89
90  // loadQueueReplay index.
91  val sleepIndex = UInt(log2Up(LoadQueueReplaySize).W)
92}
93
94class LdPrefetchTrainBundle(implicit p: Parameters) extends LsPipelineBundle {
95  val meta_prefetch = Bool()
96  val meta_access = Bool()
97
98  def fromLsPipelineBundle(input: LsPipelineBundle) = {
99    vaddr := input.vaddr
100    paddr := input.paddr
101    mask := input.mask
102    data := input.data
103    uop := input.uop
104    wlineflag := input.wlineflag
105    miss := input.miss
106    tlbMiss := input.tlbMiss
107    ptwBack := input.ptwBack
108    mmio := input.mmio
109    rsIdx := input.rsIdx
110    forwardMask := input.forwardMask
111    forwardData := input.forwardData
112    isPrefetch := input.isPrefetch
113    isHWPrefetch := input.isHWPrefetch
114    isFirstIssue := input.isFirstIssue
115    dcacheRequireReplay := input.dcacheRequireReplay
116    sleepIndex := input.sleepIndex
117
118    meta_prefetch := DontCare
119    meta_access := DontCare
120    forward_tlDchannel := DontCare
121    mshrid := DontCare
122    replayCarry := DontCare
123    atomic := DontCare
124    isLoadReplay := DontCare
125  }
126}
127
128class LqWriteBundle(implicit p: Parameters) extends LsPipelineBundle {
129  // load inst replay informations
130  val replayInfo = new LoadToLsqReplayIO
131  // queue entry data, except flag bits, will be updated if writeQueue is true,
132  // valid bit in LqWriteBundle will be ignored
133  val lqDataWenDup = Vec(6, Bool()) // dirty reg dup
134
135
136  def fromLsPipelineBundle(input: LsPipelineBundle) = {
137    vaddr := input.vaddr
138    paddr := input.paddr
139    mask := input.mask
140    data := input.data
141    uop := input.uop
142    wlineflag := input.wlineflag
143    miss := input.miss
144    tlbMiss := input.tlbMiss
145    ptwBack := input.ptwBack
146    mmio := input.mmio
147    atomic := input.atomic
148    rsIdx := input.rsIdx
149    forwardMask := input.forwardMask
150    forwardData := input.forwardData
151    isPrefetch := input.isPrefetch
152    isHWPrefetch := input.isHWPrefetch
153    isFirstIssue := input.isFirstIssue
154    isLoadReplay := input.isLoadReplay
155    mshrid := input.mshrid
156    forward_tlDchannel := input.forward_tlDchannel
157    replayCarry := input.replayCarry
158    dcacheRequireReplay := input.dcacheRequireReplay
159    sleepIndex := input.sleepIndex
160
161    replayInfo := DontCare
162    lqDataWenDup := DontCare
163  }
164}
165
166class LoadForwardQueryIO(implicit p: Parameters) extends XSBundle {
167  val vaddr = Output(UInt(VAddrBits.W))
168  val paddr = Output(UInt(PAddrBits.W))
169  val mask = Output(UInt(8.W))
170  val uop = Output(new DynInst) // for replay
171  val pc = Output(UInt(VAddrBits.W)) //for debug
172  val valid = Output(Bool())
173
174  val forwardMaskFast = Input(Vec(8, Bool())) // resp to load_s1
175  val forwardMask = Input(Vec(8, Bool())) // resp to load_s2
176  val forwardData = Input(Vec(8, UInt(8.W))) // resp to load_s2
177
178  // val lqIdx = Output(UInt(LoadQueueIdxWidth.W))
179  val sqIdx = Output(new SqPtr)
180
181  // dataInvalid suggests store to load forward found forward should happen,
182  // but data is not available for now. If dataInvalid, load inst should
183  // be replayed from RS. Feedback type should be RSFeedbackType.dataInvalid
184  val dataInvalid = Input(Bool()) // Addr match, but data is not valid for now
185
186  // matchInvalid suggests in store to load forward logic, paddr cam result does
187  // to equal to vaddr cam result. If matchInvalid, a microarchitectural exception
188  // should be raised to flush SQ and committed sbuffer.
189  val matchInvalid = Input(Bool()) // resp to load_s2
190
191  // addrInvalid suggests store to load forward found forward should happen,
192  // but address (SSID) is not available for now. If addrInvalid, load inst should
193  // be replayed from RS. Feedback type should be RSFeedbackType.addrInvalid
194  val addrInvalid = Input(Bool())
195}
196
197// LoadForwardQueryIO used in load pipeline
198//
199// Difference between PipeLoadForwardQueryIO and LoadForwardQueryIO:
200// PipeIO use predecoded sqIdxMask for better forward timing
201class PipeLoadForwardQueryIO(implicit p: Parameters) extends LoadForwardQueryIO {
202  // val sqIdx = Output(new SqPtr) // for debug, should not be used in pipeline for timing reasons
203  // sqIdxMask is calcuated in earlier stage for better timing
204  val sqIdxMask = Output(UInt(StoreQueueSize.W))
205
206  // dataInvalid: addr match, but data is not valid for now
207  val dataInvalidFast = Input(Bool()) // resp to load_s1
208  // val dataInvalid = Input(Bool()) // resp to load_s2
209  val dataInvalidSqIdx = Input(new SqPtr) // resp to load_s2, sqIdx
210  val addrInvalidSqIdx = Input(new SqPtr) // resp to load_s2, sqIdx
211}
212
213// Query load queue for ld-ld violation
214//
215// Req should be send in load_s1
216// Resp will be generated 1 cycle later
217//
218// Note that query req may be !ready, as dcache is releasing a block
219// If it happens, a replay from rs is needed.
220
221class LoadViolationQueryReq(implicit p: Parameters) extends XSBundle { // provide lqIdx
222  val uop = new DynInst
223  // mask: load's data mask.
224  val mask = UInt(8.W)
225
226  // paddr: load's paddr.
227  val paddr = UInt(PAddrBits.W)
228
229  // dataInvalid: load data is invalid.
230  val datavalid = Bool()
231}
232
233class LoadViolationQueryResp(implicit p: Parameters) extends XSBundle {
234  // replayFromFetch: ld-ld violation check success, replay from fetch.
235  val replayFromFetch = Bool()
236}
237
238class LoadViolationQueryIO(implicit p: Parameters) extends XSBundle {
239  val req = Decoupled(new LoadViolationQueryReq)
240  val resp = Flipped(Valid(new LoadViolationQueryResp))
241  val preReq = Output(Bool())
242  val release = Output(Bool())
243}
244
245class LoadReExecuteQueryIO(implicit p: Parameters) extends XSBundle {
246  //  robIdx: Requestor's (a store instruction) rob index for match logic.
247  val robIdx = new RobPtr
248
249  //  paddr: requestor's (a store instruction) physical address for match logic.
250  val paddr = UInt(PAddrBits.W)
251
252  //  mask: requestor's (a store instruction) data width mask for match logic.
253  val mask = UInt(8.W)
254}
255
256// Store byte valid mask write bundle
257//
258// Store byte valid mask write to SQ takes 2 cycles
259class StoreMaskBundle(implicit p: Parameters) extends XSBundle {
260  val sqIdx = new SqPtr
261  val mask = UInt(8.W)
262}
263
264class LoadDataFromDcacheBundle(implicit p: Parameters) extends DCacheBundle {
265  // old dcache: optimize data sram read fanout
266  // val bankedDcacheData = Vec(DCacheBanks, UInt(64.W))
267  // val bank_oh = UInt(DCacheBanks.W)
268
269  // new dcache
270  val respDcacheData = UInt(XLEN.W)
271  val forwardMask = Vec(8, Bool())
272  val forwardData = Vec(8, UInt(8.W))
273  val uop = new DynInst // for data selection, only fwen and fuOpType are used
274  val addrOffset = UInt(3.W) // for data selection
275
276  // forward tilelink D channel
277  val forward_D = Input(Bool())
278  val forwardData_D = Input(Vec(8, UInt(8.W)))
279
280  // forward mshr data
281  val forward_mshr = Input(Bool())
282  val forwardData_mshr = Input(Vec(8, UInt(8.W)))
283
284  val forward_result_valid = Input(Bool())
285
286  def dcacheData(): UInt = {
287    // old dcache
288    // val dcache_data = Mux1H(bank_oh, bankedDcacheData)
289    // new dcache
290    val dcache_data = respDcacheData
291    val use_D = forward_D && forward_result_valid
292    val use_mshr = forward_mshr && forward_result_valid
293    Mux(use_D, forwardData_D.asUInt, Mux(use_mshr, forwardData_mshr.asUInt, dcache_data))
294  }
295
296  def mergedData(): UInt = {
297    val rdataVec = VecInit((0 until XLEN / 8).map(j =>
298      Mux(forwardMask(j), forwardData(j), dcacheData()(8*(j+1)-1, 8*j))
299    ))
300    rdataVec.asUInt
301  }
302}
303
304// Load writeback data from load queue (refill)
305class LoadDataFromLQBundle(implicit p: Parameters) extends XSBundle {
306  val lqData = UInt(64.W) // load queue has merged data
307  val uop = new DynInst // for data selection, only fwen and fuOpType are used
308  val addrOffset = UInt(3.W) // for data selection
309
310  def mergedData(): UInt = {
311    lqData
312  }
313}
314
315// Bundle for load / store wait waking up
316class MemWaitUpdateReq(implicit p: Parameters) extends XSBundle {
317  val staIssue = Vec(backendParams.StaCnt, ValidIO(new MemExuInput))
318  val stdIssue = Vec(backendParams.StdCnt, ValidIO(new MemExuInput))
319}
320
321object AddPipelineReg {
322  class PipelineRegModule[T <: Data](gen: T) extends Module {
323    val io = IO(new Bundle() {
324      val in = Flipped(DecoupledIO(gen.cloneType))
325      val out = DecoupledIO(gen.cloneType)
326      val isFlush = Input(Bool())
327    })
328
329    val valid = RegInit(false.B)
330    valid.suggestName("pipeline_reg_valid")
331    when (io.out.fire()) { valid := false.B }
332    when (io.in.fire()) { valid := true.B }
333    when (io.isFlush) { valid := false.B }
334
335    io.in.ready := !valid || io.out.ready
336    io.out.bits := RegEnable(io.in.bits, io.in.fire())
337    io.out.valid := valid //&& !isFlush
338  }
339
340  def apply[T <: Data]
341  (left: DecoupledIO[T], right: DecoupledIO[T], isFlush: Bool,
342   moduleName: Option[String] = None
343  ){
344    val pipelineReg = Module(new PipelineRegModule[T](left.bits.cloneType))
345    if(moduleName.nonEmpty) pipelineReg.suggestName(moduleName.get)
346    pipelineReg.io.in <> left
347    right <> pipelineReg.io.out
348    pipelineReg.io.isFlush := isFlush
349  }
350}
351