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}