xref: /XiangShan/src/main/scala/xiangshan/mem/mdp/StoreSet.scala (revision d600fd3a19a15c9bf642ce651f46c56d402fe19f)
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        when(memPredUpdateReqReg.stpc === memPredUpdateReqReg.ldpc){
203          // make SyncDataModuleTemplate happy
204          valid_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
205          data_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
206        }
207      }
208      // 2. "If the load has been assigned a store set, but the store has not,
209      // the store is assigned the load’s store set."
210      is ("b10".U(2.W)) {
211        update_st_ssit_entry(
212          pc = memPredUpdateReqReg.stpc,
213          valid = true.B,
214          ssid = loadOldSSID,
215          strict = false.B
216        )
217      }
218      // 3. "If the store has been assigned a store set, but the load has not,
219      // the load is assigned the store’s store set."
220      is ("b01".U(2.W)) {
221        update_ld_ssit_entry(
222          pc = memPredUpdateReqReg.ldpc,
223          valid = true.B,
224          ssid = storeOldSSID,
225          strict = false.B
226        )
227      }
228      // 4. "If both the load and the store have already been assigned store sets,
229      // one of the two store sets is declared the "winner".
230      // The instruction belonging to the loser’s store set is assigned the winner’s store set."
231      is ("b11".U(2.W)) {
232        update_ld_ssit_entry(
233          pc = memPredUpdateReqReg.ldpc,
234          valid = true.B,
235          ssid = winnerSSID,
236          strict = false.B
237        )
238        update_st_ssit_entry(
239          pc = memPredUpdateReqReg.stpc,
240          valid = true.B,
241          ssid = winnerSSID,
242          strict = false.B
243        )
244        when(ssidIsSame){
245          data_sram.io.wdata(SSIT_UPDATE_LOAD_READ_PORT).strict := true.B
246          debug_strict(memPredUpdateReqReg.ldpc) := false.B
247        }
248        when(memPredUpdateReqReg.stpc === memPredUpdateReqReg.ldpc){
249          // make SyncDataModuleTemplate happy
250          valid_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
251          data_sram.io.wen(SSIT_UPDATE_STORE_WRITE_PORT) := false.B
252        }
253      }
254    }
255  }
256
257  XSPerfAccumulate("ssit_update_lxsx", memPredUpdateReqValid && !loadAssigned && !storeAssigned)
258  XSPerfAccumulate("ssit_update_lysx", memPredUpdateReqValid && loadAssigned && !storeAssigned)
259  XSPerfAccumulate("ssit_update_lxsy", memPredUpdateReqValid && !loadAssigned && storeAssigned)
260  XSPerfAccumulate("ssit_update_lysy", memPredUpdateReqValid && loadAssigned && storeAssigned)
261  XSPerfAccumulate("ssit_update_should_strict", memPredUpdateReqValid && ssidIsSame && loadAssigned && storeAssigned)
262  XSPerfAccumulate("ssit_update_strict_failed",
263    memPredUpdateReqValid && ssidIsSame && loadStrict && loadAssigned && storeAssigned
264  ) // should be zero
265
266  // reset period: ResetTimeMax2Pow
267  val resetStepCounter = RegInit(0.U((log2Up(SSITSize)+1).W))
268  val resetStepCounterFull = resetStepCounter(log2Up(SSITSize))
269  val s_idle :: s_flush :: Nil = Enum(2)
270  val state = RegInit(s_flush)
271
272  switch (state) {
273    is(s_idle) {
274      when(resetCounter(ResetTimeMax2Pow-1, ResetTimeMin2Pow)(RegNext(io.csrCtrl.lvpred_timeout))) {
275        state := s_flush
276        resetCounter := 0.U
277      }
278    }
279    is(s_flush) {
280      when(resetStepCounterFull) {
281        state := s_idle // reset finished
282        resetStepCounter := 0.U
283      }.otherwise{
284        valid_sram.io.wen(SSIT_MISC_WRITE_PORT) := true.B
285        valid_sram.io.waddr(SSIT_MISC_WRITE_PORT) := resetStepCounter
286        valid_sram.io.wdata(SSIT_MISC_WRITE_PORT) := false.B
287        debug_valid(resetStepCounter) := false.B
288        resetStepCounter := resetStepCounter + 1.U
289      }
290    }
291  }
292
293  // debug
294  for (i <- 0 until StorePipelineWidth) {
295    when (memPredUpdateReqReg.valid) {
296      XSDebug("%d: SSIT update: load pc %x store pc %x\n", GTimer(), memPredUpdateReqReg.ldpc, memPredUpdateReqReg.stpc)
297      XSDebug("%d: SSIT update: load valid %b ssid %x  store valid %b ssid %x\n", GTimer(), loadAssigned, loadOldSSID, storeAssigned, storeOldSSID)
298    }
299  }
300}
301
302
303// Last Fetched Store Table Entry
304class LFSTEntry(implicit p: Parameters) extends XSBundle  {
305  val valid = Bool()
306  val robIdx = new RobPtr
307}
308
309class LFSTReq(implicit p: Parameters) extends XSBundle {
310  val isstore = Bool()
311  val ssid = UInt(SSIDWidth.W) // use ssid to lookup LFST
312  val robIdx = new RobPtr
313}
314
315class LFSTResp(implicit p: Parameters) extends XSBundle {
316  val shouldWait = Bool()
317  val robIdx = new RobPtr
318}
319
320class DispatchLFSTIO(implicit p: Parameters) extends XSBundle {
321  val req = Vec(RenameWidth, Valid(new LFSTReq))
322  val resp = Vec(RenameWidth, Flipped(Valid(new LFSTResp)))
323}
324
325// Last Fetched Store Table
326class LFST(implicit p: Parameters) extends XSModule {
327  val io = IO(new Bundle {
328    // when redirect, mark canceled store as invalid
329    val redirect = Input(Valid(new Redirect))
330    val dispatch = Flipped(new DispatchLFSTIO)
331    // when store issued, mark store as invalid
332    val storeIssue = Vec(exuParameters.StuCnt, Flipped(Valid(new ExuInput)))
333    val csrCtrl = Input(new CustomCSRCtrlIO)
334  })
335
336  val validVec = RegInit(VecInit(Seq.fill(LFSTSize)(VecInit(Seq.fill(LFSTWidth)(false.B)))))
337  val robIdxVec = Reg(Vec(LFSTSize, Vec(LFSTWidth, new RobPtr)))
338  val allocPtr = RegInit(VecInit(Seq.fill(LFSTSize)(0.U(log2Up(LFSTWidth).W))))
339  val valid = Wire(Vec(LFSTSize, Bool()))
340  (0 until LFSTSize).map(i => {
341    valid(i) := validVec(i).asUInt.orR
342  })
343
344  // read LFST in rename stage
345  for (i <- 0 until RenameWidth) {
346    io.dispatch.resp(i).valid := io.dispatch.req(i).valid
347
348    // If store-load pair is in the same dispatch bundle, loadWaitBit should also be set for load
349    val hitInDispatchBundleVec = if(i > 0){
350      WireInit(VecInit((0 until i).map(j =>
351        io.dispatch.req(j).valid &&
352        io.dispatch.req(j).bits.isstore &&
353        io.dispatch.req(j).bits.ssid === io.dispatch.req(i).bits.ssid
354      )))
355    } else {
356      WireInit(VecInit(Seq(false.B))) // DontCare
357    }
358    val hitInDispatchBundle = hitInDispatchBundleVec.asUInt.orR
359    // Check if store set is valid in LFST
360    io.dispatch.resp(i).bits.shouldWait := (
361        (valid(io.dispatch.req(i).bits.ssid) || hitInDispatchBundle) &&
362        io.dispatch.req(i).valid &&
363        (!io.dispatch.req(i).bits.isstore || io.csrCtrl.storeset_wait_store)
364      ) && !io.csrCtrl.lvpred_disable || io.csrCtrl.no_spec_load
365    io.dispatch.resp(i).bits.robIdx := robIdxVec(io.dispatch.req(i).bits.ssid)(allocPtr(io.dispatch.req(i).bits.ssid)-1.U)
366    if(i > 0){
367      (0 until i).map(j =>
368        when(hitInDispatchBundleVec(j)){
369          io.dispatch.resp(i).bits.robIdx := io.dispatch.req(i).bits.robIdx
370        }
371      )
372    }
373  }
374
375  // when store is issued, mark it as invalid
376  (0 until exuParameters.StuCnt).map(i => {
377    // TODO: opt timing
378    (0 until LFSTWidth).map(j => {
379      when(io.storeIssue(i).valid && io.storeIssue(i).bits.uop.robIdx.value === robIdxVec(io.storeIssue(i).bits.uop.cf.ssid)(j).value){
380        validVec(io.storeIssue(i).bits.uop.cf.ssid)(j) := false.B
381      }
382    })
383  })
384
385  // when store is dispatched, mark it as valid
386  (0 until RenameWidth).map(i => {
387    when(io.dispatch.req(i).valid && io.dispatch.req(i).bits.isstore){
388      val waddr = io.dispatch.req(i).bits.ssid
389      val wptr = allocPtr(waddr)
390      allocPtr(waddr) := allocPtr(waddr) + 1.U
391      validVec(waddr)(wptr) := true.B
392      robIdxVec(waddr)(wptr) := io.dispatch.req(i).bits.robIdx
393    }
394  })
395
396  // when redirect, cancel store influenced
397  (0 until LFSTSize).map(i => {
398    (0 until LFSTWidth).map(j => {
399      when(robIdxVec(i)(j).needFlush(io.redirect)){
400        validVec(i)(j) := false.B
401      }
402    })
403  })
404
405  // recover robIdx after squash
406  // behavior model, to be refactored later
407  when(RegNext(io.redirect.fire())) {
408    (0 until LFSTSize).map(i => {
409      (0 until LFSTWidth).map(j => {
410        val check_position = WireInit(allocPtr(i) + (j+1).U)
411        when(!validVec(i)(check_position)){
412          allocPtr(i) := check_position
413        }
414      })
415    })
416  }
417}