xref: /XiangShan/src/main/scala/xiangshan/mem/mdp/StoreSet.scala (revision 039cdc35f5f3b68b6295ec5ace90f22a77322e02)
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.mdp
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import utils._
24import utility._
25import xiangshan.backend.rob.RobPtr
26import xiangshan.backend.Bundles.DynInst
27
28// store set load violation predictor
29// See "Memory Dependence Prediction using Store Sets" for details
30
31// Store Set Identifier Table Entry
32class SSITEntry(implicit p: Parameters) extends XSBundle {
33  val valid = Bool()
34  val ssid = UInt(SSIDWidth.W) // store set identifier
35  val strict = Bool() // strict load wait is needed
36}
37
38// Store Set Identifier Table Entry
39class SSITDataEntry(implicit p: Parameters) extends XSBundle {
40  val ssid = UInt(SSIDWidth.W) // store set identifier
41  val strict = Bool() // strict load wait is needed
42}
43
44// Store Set Identifier Table
45class SSIT(implicit p: Parameters) extends XSModule {
46  val io = IO(new Bundle {
47    // to decode
48    val ren = Vec(DecodeWidth, Input(Bool()))
49    val raddr = Vec(DecodeWidth, Input(UInt(MemPredPCWidth.W))) // xor hashed decode pc(VaddrBits-1, 1)
50    // to rename
51    val rdata = Vec(RenameWidth, Output(new SSITEntry))
52    // misc
53    val update = Input(new MemPredUpdateReq) // RegNext should be added outside
54    val csrCtrl = Input(new CustomCSRCtrlIO)
55  })
56
57  // raddrs are sent to ssit in decode
58  // rdata will be send to rename
59  require(DecodeWidth == RenameWidth)
60
61  // data sram read port allocate
62  //
63  // SSIT update logic will reuse decode ssit read port.
64  // If io.update.valid, a redirect will be send to frontend,
65  // then decode will not need to read SSIT
66  val SSIT_DECODE_READ_PORT_BASE = 0
67  val SSIT_UPDATE_LOAD_READ_PORT = 0
68  val SSIT_UPDATE_STORE_READ_PORT = 1
69  val SSIT_READ_PORT_NUM = DecodeWidth
70
71  // data sram write port allocate
72  // load update and flush uses the same write port
73  val SSIT_MISC_WRITE_PORT = 0
74  val SSIT_UPDATE_LOAD_WRITE_PORT = 0
75  val SSIT_UPDATE_STORE_WRITE_PORT = 1
76  val SSIT_WRITE_PORT_NUM = 2
77
78  private def hasRen: Boolean = true
79  val valid_array = Module(new SyncDataModuleTemplate(
80    Bool(),
81    SSITSize,
82    SSIT_READ_PORT_NUM,
83    SSIT_WRITE_PORT_NUM,
84    hasRen = hasRen,
85  ))
86
87  val data_array = Module(new SyncDataModuleTemplate(
88    new SSITDataEntry,
89    SSITSize,
90    SSIT_READ_PORT_NUM,
91    SSIT_WRITE_PORT_NUM,
92    hasRen = hasRen,
93  ))
94
95  // TODO: use SRAM or not?
96  (0 until SSIT_WRITE_PORT_NUM).map(i => {
97    valid_array.io.wen(i) := false.B
98    valid_array.io.waddr(i) := 0.U
99    valid_array.io.wdata(i) := false.B
100    data_array.io.wen(i) := false.B
101    data_array.io.waddr(i) := 0.U
102    data_array.io.wdata(i) := 0.U.asTypeOf(new SSITDataEntry)
103  })
104
105  val debug_valid = RegInit(VecInit(Seq.fill(SSITSize)(false.B)))
106  val debug_ssid = Reg(Vec(SSITSize, UInt(SSIDWidth.W)))
107  val debug_strict = Reg(Vec(SSITSize, Bool()))
108  if(!env.FPGAPlatform){
109    dontTouch(debug_valid)
110    dontTouch(debug_ssid)
111    dontTouch(debug_strict)
112  }
113
114  val resetCounter = RegInit(0.U(ResetTimeMax2Pow.W))
115  resetCounter := resetCounter + 1.U
116
117  for (i <- 0 until DecodeWidth) {
118    // io.rdata(i).valid := RegNext(valid(io.raddr(i)))
119    // io.rdata(i).ssid := RegNext(ssid(io.raddr(i)))
120    // io.rdata(i).strict := RegNext(strict(io.raddr(i)) && valid(io.raddr(i)))
121
122    // read SSIT in decode stage
123    valid_array.io.ren.get(i) := io.ren(i)
124    data_array.io.ren.get(i) := io.ren(i)
125    valid_array.io.raddr(i) := io.raddr(i)
126    data_array.io.raddr(i) := io.raddr(i)
127
128    // gen result in rename stage
129    io.rdata(i).valid := valid_array.io.rdata(i)
130    io.rdata(i).ssid := data_array.io.rdata(i).ssid
131    io.rdata(i).strict := data_array.io.rdata(i).strict
132  }
133
134  // flush SSIT
135  // reset period: ResetTimeMax2Pow
136  val resetStepCounter = RegInit(0.U(log2Up(SSITSize + 1).W))
137  val s_idle :: s_flush :: Nil = Enum(2)
138  val state = RegInit(s_flush)
139
140  switch (state) {
141    is(s_idle) {
142      when(resetCounter(ResetTimeMax2Pow - 1, ResetTimeMin2Pow)(RegNext(io.csrCtrl.lvpred_timeout))) {
143        state := s_flush
144        resetCounter := 0.U
145      }
146    }
147    is(s_flush) {
148      when(resetStepCounter === (SSITSize - 1).U) {
149        state := s_idle // reset finished
150        resetStepCounter := 0.U
151      }.otherwise{
152        resetStepCounter := resetStepCounter + 1.U
153      }
154      valid_array.io.wen(SSIT_MISC_WRITE_PORT) := true.B
155      valid_array.io.waddr(SSIT_MISC_WRITE_PORT) := resetStepCounter
156      valid_array.io.wdata(SSIT_MISC_WRITE_PORT) := false.B
157      debug_valid(resetStepCounter) := false.B
158    }
159  }
160  XSPerfAccumulate("reset_timeout", state === s_flush && resetCounter === 0.U)
161
162  // update SSIT if load violation redirect is detected
163
164  // update stage 0: read ssit
165  val s1_mempred_update_req_valid = RegNext(io.update.valid)
166  val s1_mempred_update_req = RegEnable(io.update, io.update.valid)
167
168  // when io.update.valid, take over ssit read port
169  when (io.update.valid) {
170    valid_array.io.raddr(SSIT_UPDATE_LOAD_READ_PORT) := io.update.ldpc
171    valid_array.io.raddr(SSIT_UPDATE_STORE_READ_PORT) := io.update.stpc
172    data_array.io.raddr(SSIT_UPDATE_LOAD_READ_PORT) := io.update.ldpc
173    data_array.io.raddr(SSIT_UPDATE_STORE_READ_PORT) := io.update.stpc
174  }
175
176  // update stage 1: get ssit read result
177
178  // Read result
179  // load has already been assigned with a store set
180  val s1_loadAssigned = valid_array.io.rdata(SSIT_UPDATE_LOAD_READ_PORT)
181  val s1_loadOldSSID = data_array.io.rdata(SSIT_UPDATE_LOAD_READ_PORT).ssid
182  val s1_loadStrict = data_array.io.rdata(SSIT_UPDATE_LOAD_READ_PORT).strict
183  // store has already been assigned with a store set
184  val s1_storeAssigned = valid_array.io.rdata(SSIT_UPDATE_STORE_READ_PORT)
185  val s1_storeOldSSID = data_array.io.rdata(SSIT_UPDATE_STORE_READ_PORT).ssid
186  val s1_storeStrict = data_array.io.rdata(SSIT_UPDATE_STORE_READ_PORT).strict
187  // val s1_ssidIsSame = s1_loadOldSSID === s1_storeOldSSID
188
189  // update stage 2, update ssit data_array
190  val s2_mempred_update_req_valid = RegNext(s1_mempred_update_req_valid)
191  val s2_mempred_update_req = RegEnable(s1_mempred_update_req, s1_mempred_update_req_valid)
192  val s2_loadAssigned = RegEnable(s1_loadAssigned, s1_mempred_update_req_valid)
193  val s2_storeAssigned = RegEnable(s1_storeAssigned, s1_mempred_update_req_valid)
194  val s2_loadOldSSID = RegEnable(s1_loadOldSSID, s1_mempred_update_req_valid)
195  val s2_storeOldSSID = RegEnable(s1_storeOldSSID, s1_mempred_update_req_valid)
196  val s2_loadStrict = RegEnable(s1_loadStrict, s1_mempred_update_req_valid)
197
198  val s2_ssidIsSame = s2_loadOldSSID === s2_storeOldSSID
199  // for now we just use lowest bits of ldpc as store set id
200  val s2_ldSsidAllocate = XORFold(s2_mempred_update_req.ldpc, SSIDWidth)
201  val s2_stSsidAllocate = XORFold(s2_mempred_update_req.stpc, SSIDWidth)
202  // both the load and the store have already been assigned store sets
203  // but load's store set ID is smaller
204  val s2_winnerSSID = Mux(s2_loadOldSSID < s2_storeOldSSID, s2_loadOldSSID, s2_storeOldSSID)
205
206  def update_ld_ssit_entry(pc: UInt, valid: Bool, ssid: UInt, strict: Bool) = {
207    valid_array.io.wen(SSIT_UPDATE_LOAD_WRITE_PORT) := true.B
208    valid_array.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) := pc
209    valid_array.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT) := valid
210    data_array.io.wen(SSIT_UPDATE_LOAD_WRITE_PORT) := true.B
211    data_array.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) := pc
212    data_array.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT).ssid := ssid
213    data_array.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT).strict := strict
214    debug_valid(pc) := valid
215    debug_ssid(pc) := ssid
216    debug_strict(pc) := strict
217  }
218
219  def update_st_ssit_entry(pc: UInt, valid: Bool, ssid: UInt, strict: Bool) = {
220    valid_array.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := true.B
221    valid_array.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT) := pc
222    valid_array.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT):= valid
223    data_array.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := true.B
224    data_array.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT) := pc
225    data_array.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT).ssid := ssid
226    data_array.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT).strict := strict
227    debug_valid(pc) := valid
228    debug_ssid(pc) := ssid
229    debug_strict(pc) := strict
230  }
231
232  when(s2_mempred_update_req_valid){
233    switch (Cat(s2_loadAssigned, s2_storeAssigned)) {
234      // 1. "If neither the load nor the store has been assigned a store set,
235      // two are allocated and assigned to each instruction."
236      is ("b00".U(2.W)) {
237        update_ld_ssit_entry(
238          pc = s2_mempred_update_req.ldpc,
239          valid = true.B,
240          ssid = s2_ldSsidAllocate,
241          strict = false.B
242        )
243        update_st_ssit_entry(
244          pc = s2_mempred_update_req.stpc,
245          valid = true.B,
246          ssid = s2_stSsidAllocate,
247          strict = false.B
248        )
249      }
250      // 2. "If the load has been assigned a store set, but the store has not,
251      // one is allocated and assigned to the store instructions."
252      is ("b10".U(2.W)) {
253        update_st_ssit_entry(
254          pc = s2_mempred_update_req.stpc,
255          valid = true.B,
256          ssid = s2_stSsidAllocate,
257          strict = false.B
258        )
259      }
260      // 3. "If the store has been assigned a store set, but the load has not,
261      // one is allocated and assigned to the load instructions."
262      is ("b01".U(2.W)) {
263        update_ld_ssit_entry(
264          pc = s2_mempred_update_req.ldpc,
265          valid = true.B,
266          ssid = s2_ldSsidAllocate,
267          strict = false.B
268        )
269      }
270      // 4. "If both the load and the store have already been assigned store sets,
271      // one of the two store sets is declared the "winner".
272      // The instruction belonging to the loser’s store set is assigned the winner’s store set."
273      is ("b11".U(2.W)) {
274        update_ld_ssit_entry(
275          pc = s2_mempred_update_req.ldpc,
276          valid = true.B,
277          ssid = s2_winnerSSID,
278          strict = false.B
279        )
280        update_st_ssit_entry(
281          pc = s2_mempred_update_req.stpc,
282          valid = true.B,
283          ssid = s2_winnerSSID,
284          strict = false.B
285        )
286        when(s2_ssidIsSame){
287          data_array.io.wdata(SSIT_UPDATE_LOAD_READ_PORT).strict := true.B
288          debug_strict(s2_mempred_update_req.ldpc) := true.B
289        }
290      }
291    }
292  }
293
294  // make SyncDataModuleTemplate happy
295  when(valid_array.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) === valid_array.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT)){
296    valid_array.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
297  }
298
299  when(data_array.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) === data_array.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT)){
300    data_array.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
301  }
302
303  XSPerfAccumulate("ssit_update_lxsx", s2_mempred_update_req_valid && !s2_loadAssigned && !s2_storeAssigned)
304  XSPerfAccumulate("ssit_update_lysx", s2_mempred_update_req_valid && s2_loadAssigned && !s2_storeAssigned)
305  XSPerfAccumulate("ssit_update_lxsy", s2_mempred_update_req_valid && !s2_loadAssigned && s2_storeAssigned)
306  XSPerfAccumulate("ssit_update_lysy", s2_mempred_update_req_valid && s2_loadAssigned && s2_storeAssigned)
307  XSPerfAccumulate("ssit_update_should_strict", s2_mempred_update_req_valid && s2_ssidIsSame && s2_loadAssigned && s2_storeAssigned)
308  XSPerfAccumulate("ssit_update_strict_failed",
309    s2_mempred_update_req_valid && s2_ssidIsSame && s2_loadStrict && s2_loadAssigned && s2_storeAssigned
310  ) // should be zero
311
312  // debug
313  when (s2_mempred_update_req.valid) {
314    XSDebug("%d: SSIT update: load pc %x store pc %x\n", GTimer(), s2_mempred_update_req.ldpc, s2_mempred_update_req.stpc)
315    XSDebug("%d: SSIT update: load valid %b ssid %x  store valid %b ssid %x\n", GTimer(), s2_loadAssigned, s2_loadOldSSID, s2_storeAssigned, s2_storeOldSSID)
316  }
317}
318
319
320// Last Fetched Store Table Entry
321class LFSTEntry(implicit p: Parameters) extends XSBundle  {
322  val valid = Bool()
323  val robIdx = new RobPtr
324}
325
326class LFSTReq(implicit p: Parameters) extends XSBundle {
327  val isstore = Bool()
328  val ssid = UInt(SSIDWidth.W) // use ssid to lookup LFST
329  val robIdx = new RobPtr
330}
331
332class LFSTResp(implicit p: Parameters) extends XSBundle {
333  val shouldWait = Bool()
334  val robIdx = new RobPtr
335}
336
337class DispatchLFSTIO(implicit p: Parameters) extends XSBundle {
338  val req = Vec(RenameWidth, Valid(new LFSTReq))
339  val resp = Vec(RenameWidth, Flipped(Valid(new LFSTResp)))
340}
341
342// Last Fetched Store Table
343class LFST(implicit p: Parameters) extends XSModule {
344  val io = IO(new Bundle {
345    // when redirect, mark canceled store as invalid
346    val redirect = Input(Valid(new Redirect))
347    val dispatch = Flipped(new DispatchLFSTIO)
348    // when store issued, mark store as invalid
349    val storeIssue = Vec(backendParams.StaExuCnt, Flipped(Valid(new DynInst)))
350    val csrCtrl = Input(new CustomCSRCtrlIO)
351  })
352
353  val validVec = RegInit(VecInit(Seq.fill(LFSTSize)(VecInit(Seq.fill(LFSTWidth)(false.B)))))
354  val robIdxVec = Reg(Vec(LFSTSize, Vec(LFSTWidth, new RobPtr)))
355  val allocPtr = RegInit(VecInit(Seq.fill(LFSTSize)(0.U(log2Up(LFSTWidth).W))))
356  val valid = Wire(Vec(LFSTSize, Bool()))
357  (0 until LFSTSize).map(i => {
358    valid(i) := validVec(i).asUInt.orR
359  })
360
361  // read LFST in rename stage
362  for (i <- 0 until RenameWidth) {
363    io.dispatch.resp(i).valid := io.dispatch.req(i).valid
364
365    // If store-load pair is in the same dispatch bundle, loadWaitBit should also be set for load
366    val hitInDispatchBundleVec = if(i > 0){
367      WireInit(VecInit((0 until i).map(j =>
368        io.dispatch.req(j).valid &&
369        io.dispatch.req(j).bits.isstore &&
370        io.dispatch.req(j).bits.ssid === io.dispatch.req(i).bits.ssid
371      )))
372    } else {
373      WireInit(VecInit(Seq(false.B))) // DontCare
374    }
375    val hitInDispatchBundle = hitInDispatchBundleVec.asUInt.orR
376    // Check if store set is valid in LFST
377    io.dispatch.resp(i).bits.shouldWait := (
378        (valid(io.dispatch.req(i).bits.ssid) || hitInDispatchBundle) &&
379        io.dispatch.req(i).valid &&
380        (!io.dispatch.req(i).bits.isstore || io.csrCtrl.storeset_wait_store)
381      ) && !io.csrCtrl.lvpred_disable || io.csrCtrl.no_spec_load
382    io.dispatch.resp(i).bits.robIdx := robIdxVec(io.dispatch.req(i).bits.ssid)(allocPtr(io.dispatch.req(i).bits.ssid)-1.U)
383    if(i > 0){
384      (0 until i).map(j =>
385        when(hitInDispatchBundleVec(j)){
386          io.dispatch.resp(i).bits.robIdx := io.dispatch.req(j).bits.robIdx
387        }
388      )
389    }
390  }
391
392  // when store is issued, mark it as invalid
393  (0 until backendParams.StaExuCnt).map(i => {
394    // TODO: opt timing
395    (0 until LFSTWidth).map(j => {
396      when(io.storeIssue(i).valid && io.storeIssue(i).bits.storeSetHit && io.storeIssue(i).bits.robIdx.value === robIdxVec(io.storeIssue(i).bits.ssid)(j).value){
397        validVec(io.storeIssue(i).bits.ssid)(j) := false.B
398      }
399    })
400  })
401
402  // when store is dispatched, mark it as valid
403  (0 until RenameWidth).map(i => {
404    when(io.dispatch.req(i).valid && io.dispatch.req(i).bits.isstore){
405      val waddr = io.dispatch.req(i).bits.ssid
406      val wptr = allocPtr(waddr)
407      allocPtr(waddr) := allocPtr(waddr) + 1.U
408      validVec(waddr)(wptr) := true.B
409      robIdxVec(waddr)(wptr) := io.dispatch.req(i).bits.robIdx
410    }
411  })
412
413  // when redirect, cancel store influenced
414  (0 until LFSTSize).map(i => {
415    (0 until LFSTWidth).map(j => {
416      when(validVec(i)(j) && robIdxVec(i)(j).needFlush(io.redirect)){
417        validVec(i)(j) := false.B
418      }
419    })
420  })
421
422  // recover robIdx after squash
423  // behavior model, to be refactored later
424  when(RegNext(io.redirect.fire)) {
425    (0 until LFSTSize).map(i => {
426      (0 until LFSTWidth).map(j => {
427        val check_position = WireInit(allocPtr(i) + (j+1).U)
428        when(!validVec(i)(check_position)){
429          allocPtr(i) := check_position
430        }
431      })
432    })
433  }
434}
435