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