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