xref: /XiangShan/src/main/scala/xiangshan/mem/mdp/StoreSet.scala (revision dcbc69cb2a7ea07707ede3d8f7c74421ef450202)
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  val SSIT_UPDATE_LOAD_WRITE_PORT = 0
70  val SSIT_UPDATE_STORE_WRITE_PORT = 1
71  val SSIT_MISC_WRITE_PORT = 2
72  val SSIT_WRITE_PORT_NUM = 3
73
74  // TODO: reorg sram size
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  // update SSIT if load violation redirect is detected
126
127  // update stage 0: read ssit
128  val memPredUpdateReqValid = RegNext(io.update.valid)
129  val memPredUpdateReqReg = RegEnable(io.update, enable = io.update.valid)
130
131  // when io.update.valid, take over ssit read port
132  when (io.update.valid) {
133    valid_sram.io.raddr(SSIT_UPDATE_LOAD_READ_PORT) := io.update.ldpc
134    valid_sram.io.raddr(SSIT_UPDATE_STORE_READ_PORT) := io.update.stpc
135    data_sram.io.raddr(SSIT_UPDATE_LOAD_READ_PORT) := io.update.ldpc
136    data_sram.io.raddr(SSIT_UPDATE_STORE_READ_PORT) := io.update.stpc
137  }
138
139  // update stage 1: get ssit read result, update ssit data_sram
140
141  // Read result
142  // load has already been assigned with a store set
143  val loadAssigned = valid_sram.io.rdata(SSIT_UPDATE_LOAD_READ_PORT)
144  val loadOldSSID = data_sram.io.rdata(SSIT_UPDATE_LOAD_READ_PORT).ssid
145  val loadStrict = data_sram.io.rdata(SSIT_UPDATE_LOAD_READ_PORT).strict
146  // store has already been assigned with a store set
147  val storeAssigned = valid_sram.io.rdata(SSIT_UPDATE_STORE_READ_PORT)
148  val storeOldSSID = data_sram.io.rdata(SSIT_UPDATE_STORE_READ_PORT).ssid
149  val storeStrict = data_sram.io.rdata(SSIT_UPDATE_STORE_READ_PORT).strict
150  // both the load and the store have already been assigned store sets
151  // but load's store set ID is smaller
152  val winnerSSID = Mux(loadOldSSID < storeOldSSID, loadOldSSID, storeOldSSID)
153  val ssidIsSame = loadOldSSID === storeOldSSID
154
155  // for now we just use lowest bits of ldpc as store set id
156  val ssidAllocate = memPredUpdateReqReg.ldpc(SSIDWidth-1, 0)
157
158  def update_ld_ssit_entry(pc: UInt, valid: Bool, ssid: UInt, strict: Bool) = {
159    valid_sram.io.wen(SSIT_UPDATE_LOAD_WRITE_PORT) := true.B
160    valid_sram.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) := pc
161    valid_sram.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT) := valid
162    data_sram.io.wen(SSIT_UPDATE_LOAD_WRITE_PORT) := true.B
163    data_sram.io.waddr(SSIT_UPDATE_LOAD_WRITE_PORT) := pc
164    data_sram.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT).ssid := ssid
165    data_sram.io.wdata(SSIT_UPDATE_LOAD_WRITE_PORT).strict := strict
166    debug_valid(pc) := valid
167    debug_ssid(pc) := ssid
168    debug_strict(pc) := strict
169  }
170
171  def update_st_ssit_entry(pc: UInt, valid: Bool, ssid: UInt, strict: Bool) = {
172    valid_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := true.B
173    valid_sram.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT) := pc
174    valid_sram.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT):= valid
175    data_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := true.B
176    data_sram.io.waddr(SSIT_UPDATE_STORE_WRITE_PORT) := pc
177    data_sram.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT).ssid := ssid
178    data_sram.io.wdata(SSIT_UPDATE_STORE_WRITE_PORT).strict := strict
179    debug_valid(pc) := valid
180    debug_ssid(pc) := ssid
181    debug_strict(pc) := strict
182  }
183
184  // update stage 1
185  when(memPredUpdateReqValid){
186    switch (Cat(loadAssigned, storeAssigned)) {
187      // 1. "If neither the load nor the store has been assigned a store set,
188      // one is allocated and assigned to both instructions."
189      is ("b00".U(2.W)) {
190        update_ld_ssit_entry(
191          pc = memPredUpdateReqReg.ldpc,
192          valid = true.B,
193          ssid = ssidAllocate,
194          strict = false.B
195        )
196        update_st_ssit_entry(
197          pc = memPredUpdateReqReg.stpc,
198          valid = true.B,
199          ssid = ssidAllocate,
200          strict = false.B
201        )
202      }
203      // 2. "If the load has been assigned a store set, but the store has not,
204      // the store is assigned the load’s store set."
205      is ("b10".U(2.W)) {
206        update_st_ssit_entry(
207          pc = memPredUpdateReqReg.stpc,
208          valid = true.B,
209          ssid = loadOldSSID,
210          strict = false.B
211        )
212      }
213      // 3. "If the store has been assigned a store set, but the load has not,
214      // the load is assigned the store’s store set."
215      is ("b01".U(2.W)) {
216        update_ld_ssit_entry(
217          pc = memPredUpdateReqReg.ldpc,
218          valid = true.B,
219          ssid = storeOldSSID,
220          strict = false.B
221        )
222      }
223      // 4. "If both the load and the store have already been assigned store sets,
224      // one of the two store sets is declared the "winner".
225      // The instruction belonging to the loser’s store set is assigned the winner’s store set."
226      is ("b11".U(2.W)) {
227        update_ld_ssit_entry(
228          pc = memPredUpdateReqReg.ldpc,
229          valid = true.B,
230          ssid = winnerSSID,
231          strict = false.B
232        )
233        update_st_ssit_entry(
234          pc = memPredUpdateReqReg.stpc,
235          valid = true.B,
236          ssid = winnerSSID,
237          strict = false.B
238        )
239        when(ssidIsSame){
240          data_sram.io.wdata(SSIT_UPDATE_LOAD_READ_PORT).strict := true.B
241          debug_strict(memPredUpdateReqReg.ldpc) := false.B
242        }
243      }
244    }
245  }
246
247  XSPerfAccumulate("ssit_update_lxsx", memPredUpdateReqValid && !loadAssigned && !storeAssigned)
248  XSPerfAccumulate("ssit_update_lysx", memPredUpdateReqValid && loadAssigned && !storeAssigned)
249  XSPerfAccumulate("ssit_update_lxsy", memPredUpdateReqValid && !loadAssigned && storeAssigned)
250  XSPerfAccumulate("ssit_update_lysy", memPredUpdateReqValid && loadAssigned && storeAssigned)
251  XSPerfAccumulate("ssit_update_should_strict", memPredUpdateReqValid && ssidIsSame && loadAssigned && storeAssigned)
252  XSPerfAccumulate("ssit_update_strict_failed",
253    memPredUpdateReqValid && ssidIsSame && loadStrict && loadAssigned && storeAssigned
254  ) // should be zero
255
256  // reset period: ResetTimeMax2Pow
257  val resetStepCounter = RegInit(0.U((log2Up(SSITSize)+1).W))
258  val resetStepCounterFull = resetStepCounter(log2Up(SSITSize))
259  val s_idle :: s_flush :: Nil = Enum(2)
260  val state = RegInit(s_flush)
261
262  switch (state) {
263    is(s_idle) {
264      when(resetCounter(ResetTimeMax2Pow-1, ResetTimeMin2Pow)(RegNext(io.csrCtrl.lvpred_timeout))) {
265        state := s_flush
266        resetCounter := 0.U
267      }
268    }
269    is(s_flush) {
270      when(resetStepCounterFull) {
271        state := s_idle // reset finished
272        resetStepCounter := 0.U
273      }.otherwise{
274        valid_sram.io.wen(SSIT_MISC_WRITE_PORT) := true.B
275        valid_sram.io.waddr(SSIT_MISC_WRITE_PORT) := resetStepCounter
276        valid_sram.io.wdata(SSIT_MISC_WRITE_PORT) := false.B
277        debug_valid(resetStepCounter) := false.B
278        resetStepCounter := resetStepCounter + 1.U
279      }
280    }
281  }
282
283  // debug
284  for (i <- 0 until StorePipelineWidth) {
285    when (memPredUpdateReqReg.valid) {
286      XSDebug("%d: SSIT update: load pc %x store pc %x\n", GTimer(), memPredUpdateReqReg.ldpc, memPredUpdateReqReg.stpc)
287      XSDebug("%d: SSIT update: load valid %b ssid %x  store valid %b ssid %x\n", GTimer(), loadAssigned, loadOldSSID, storeAssigned, storeOldSSID)
288    }
289  }
290}
291
292
293// Last Fetched Store Table Entry
294class LFSTEntry(implicit p: Parameters) extends XSBundle  {
295  val valid = Bool()
296  val robIdx = new RobPtr
297}
298
299class LFSTReq(implicit p: Parameters) extends XSBundle {
300  val isstore = Bool()
301  val ssid = UInt(SSIDWidth.W) // use ssid to lookup LFST
302  val robIdx = new RobPtr
303}
304
305class LFSTResp(implicit p: Parameters) extends XSBundle {
306  val shouldWait = Bool()
307  val robIdx = new RobPtr
308}
309
310class DispatchLFSTIO(implicit p: Parameters) extends XSBundle {
311  val req = Vec(RenameWidth, Valid(new LFSTReq))
312  val resp = Vec(RenameWidth, Flipped(Valid(new LFSTResp)))
313}
314
315// Last Fetched Store Table
316class LFST(implicit p: Parameters) extends XSModule {
317  val io = IO(new Bundle {
318    // when redirect, mark canceled store as invalid
319    val redirect = Input(Valid(new Redirect))
320    val dispatch = Flipped(new DispatchLFSTIO)
321    // when store issued, mark store as invalid
322    val storeIssue = Vec(exuParameters.StuCnt, Flipped(Valid(new ExuInput)))
323    val csrCtrl = Input(new CustomCSRCtrlIO)
324  })
325
326  val validVec = RegInit(VecInit(Seq.fill(LFSTSize)(VecInit(Seq.fill(LFSTWidth)(false.B)))))
327  val robIdxVec = Reg(Vec(LFSTSize, Vec(LFSTWidth, new RobPtr)))
328  val allocPtr = RegInit(VecInit(Seq.fill(LFSTSize)(0.U(log2Up(LFSTWidth).W))))
329  val valid = Wire(Vec(LFSTSize, Bool()))
330  (0 until LFSTSize).map(i => {
331    valid(i) := validVec(i).asUInt.orR
332  })
333
334  // read LFST in rename stage
335  for (i <- 0 until RenameWidth) {
336    io.dispatch.resp(i).valid := io.dispatch.req(i).valid
337
338    // If store-load pair is in the same dispatch bundle, loadWaitBit should also be set for load
339    val hitInDispatchBundleVec = if(i > 0){
340      WireInit(VecInit((0 until i).map(j =>
341        io.dispatch.req(j).valid &&
342        io.dispatch.req(j).bits.isstore &&
343        io.dispatch.req(j).bits.ssid === io.dispatch.req(i).bits.ssid
344      )))
345    } else {
346      WireInit(VecInit(Seq(false.B))) // DontCare
347    }
348    val hitInDispatchBundle = hitInDispatchBundleVec.asUInt.orR
349    // Check if store set is valid in LFST
350    io.dispatch.resp(i).bits.shouldWait := (
351        (valid(io.dispatch.req(i).bits.ssid) || hitInDispatchBundle) &&
352        io.dispatch.req(i).valid &&
353        (!io.dispatch.req(i).bits.isstore || io.csrCtrl.storeset_wait_store)
354      ) && !io.csrCtrl.lvpred_disable || io.csrCtrl.no_spec_load
355    io.dispatch.resp(i).bits.robIdx := robIdxVec(io.dispatch.req(i).bits.ssid)(allocPtr(io.dispatch.req(i).bits.ssid)-1.U)
356    if(i > 0){
357      (0 until i).map(j =>
358        when(hitInDispatchBundleVec(j)){
359          io.dispatch.resp(i).bits.robIdx := io.dispatch.req(i).bits.robIdx
360        }
361      )
362    }
363  }
364
365  // when store is issued, mark it as invalid
366  (0 until exuParameters.StuCnt).map(i => {
367    // TODO: opt timing
368    (0 until LFSTWidth).map(j => {
369      when(io.storeIssue(i).valid && io.storeIssue(i).bits.uop.robIdx.value === robIdxVec(io.storeIssue(i).bits.uop.cf.ssid)(j).value){
370        validVec(io.storeIssue(i).bits.uop.cf.ssid)(j) := false.B
371      }
372    })
373  })
374
375  // when store is dispatched, mark it as valid
376  (0 until RenameWidth).map(i => {
377    when(io.dispatch.req(i).valid && io.dispatch.req(i).bits.isstore){
378      val waddr = io.dispatch.req(i).bits.ssid
379      val wptr = allocPtr(waddr)
380      allocPtr(waddr) := allocPtr(waddr) + 1.U
381      validVec(waddr)(wptr) := true.B
382      robIdxVec(waddr)(wptr) := io.dispatch.req(i).bits.robIdx
383    }
384  })
385
386  // when redirect, cancel store influenced
387  (0 until LFSTSize).map(i => {
388    (0 until LFSTWidth).map(j => {
389      when(robIdxVec(i)(j).needFlush(io.redirect)){
390        validVec(i)(j) := false.B
391      }
392    })
393  })
394
395  // recover robIdx after squash
396  // behavior model, to be refactored later
397  when(RegNext(io.redirect.fire())) {
398    (0 until LFSTSize).map(i => {
399      (0 until LFSTWidth).map(j => {
400        val check_position = WireInit(allocPtr(i) + (j+1).U)
401        when(!validVec(i)(check_position)){
402          allocPtr(i) := check_position
403        }
404      })
405    })
406  }
407}