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 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import xiangshan._ 24import xiangshan.cache._ 25import xiangshan.cache.{DCacheWordIO, DCacheLineIO, MemoryOpConstants} 26import xiangshan.mem._ 27import xiangshan.backend.rob.RobPtr 28 29class LQDataEntry(implicit p: Parameters) extends XSBundle { 30 // val vaddr = UInt(VAddrBits.W) 31 val paddr = UInt(PAddrBits.W) 32 val mask = UInt(8.W) 33 val data = UInt(XLEN.W) 34 val fwdMask = Vec(8, Bool()) 35} 36 37// Data module define 38// These data modules are like SyncDataModuleTemplate, but support cam-like ops 39class LQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 40 val io = IO(new Bundle { 41 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 42 val rdata = Output(Vec(numRead, UInt((PAddrBits).W))) 43 val wen = Input(Vec(numWrite, Bool())) 44 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 45 val wdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 46 val violationMdata = Input(Vec(StorePipelineWidth, UInt((PAddrBits).W))) 47 val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool()))) 48 val releaseMdata = Input(Vec(LoadPipelineWidth, UInt((PAddrBits).W))) 49 val releaseMmask = Output(Vec(LoadPipelineWidth, Vec(numEntries, Bool()))) 50 val refillMdata = Input(UInt((PAddrBits).W)) 51 val refillMmask = Output(Vec(numEntries, Bool())) 52 }) 53 54 val data = Reg(Vec(numEntries, UInt((PAddrBits).W))) 55 56 // read ports 57 for (i <- 0 until numRead) { 58 io.rdata(i) := data(RegNext(io.raddr(i))) 59 } 60 61 // below is the write ports (with priorities) 62 for (i <- 0 until numWrite) { 63 when (io.wen(i)) { 64 data(io.waddr(i)) := io.wdata(i) 65 } 66 } 67 68 // content addressed match 69 for (i <- 0 until StorePipelineWidth) { 70 for (j <- 0 until numEntries) { 71 io.violationMmask(i)(j) := io.violationMdata(i)(PAddrBits-1, DCacheIndexOffset) === data(j)(PAddrBits-1, DCacheIndexOffset) 72 } 73 } 74 for (i <- 0 until LoadPipelineWidth) { 75 for (j <- 0 until numEntries) { 76 io.releaseMmask(i)(j) := io.releaseMdata(i)(PAddrBits-1, DCacheIndexOffset) === data(j)(PAddrBits-1, DCacheIndexOffset) 77 } 78 } 79 80 for (j <- 0 until numEntries) { 81 io.refillMmask(j) := get_refill_addr(io.refillMdata) === get_refill_addr(data(j)) 82 } 83 84 // DataModuleTemplate should not be used when there're any write conflicts 85 for (i <- 0 until numWrite) { 86 for (j <- i+1 until numWrite) { 87 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 88 } 89 } 90} 91 92class MaskModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule { 93 val io = IO(new Bundle { 94 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 95 val rdata = Output(Vec(numRead, UInt(8.W))) 96 val wen = Input(Vec(numWrite, Bool())) 97 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 98 val wdata = Input(Vec(numWrite, UInt(8.W))) 99 val violationMdata = Input(Vec(StorePipelineWidth, UInt((PAddrBits).W))) 100 val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool()))) 101 }) 102 103 val data = Reg(Vec(numEntries, UInt(8.W))) 104 105 // read ports 106 for (i <- 0 until numRead) { 107 io.rdata(i) := data(RegNext(io.raddr(i))) 108 } 109 110 // below is the write ports (with priorities) 111 for (i <- 0 until numWrite) { 112 when (io.wen(i)) { 113 data(io.waddr(i)) := io.wdata(i) 114 } 115 } 116 117 // content addressed match 118 for (i <- 0 until StorePipelineWidth) { 119 for (j <- 0 until numEntries) { 120 io.violationMmask(i)(j) := (io.violationMdata(i) & data(j)).orR 121 } 122 } 123 124 // DataModuleTemplate should not be used when there're any write conflicts 125 for (i <- 0 until numWrite) { 126 for (j <- i+1 until numWrite) { 127 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 128 } 129 } 130} 131 132// class LQData8Module(numEntries: Int, numRead: Int, numWrite: Int) extends XSModule with HasDCacheParameters { 133// val io = IO(new Bundle { 134// // read 135// val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 136// val rdata = Output(Vec(numRead, UInt(8.W))) 137// // address indexed write 138// val wen = Input(Vec(numWrite, Bool())) 139// val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 140// val wdata = Input(Vec(numWrite, UInt(8.W))) 141// // masked write 142// val mwmask = Input(Vec(blockWords, Vec(numEntries, Bool()))) 143// val mwdata = Input(Vec(blockWords, UInt(8.W))) 144// }) 145 146// val data = Reg(Vec(numEntries, UInt(8.W))) 147 148// // read ports 149// for (i <- 0 until numRead) { 150// io.rdata(i) := data(RegNext(io.raddr(i))) 151// } 152 153// // below is the write ports (with priorities) 154// for (i <- 0 until numWrite) { 155// when (io.wen(i)) { 156// data(io.waddr(i)) := io.wdata(i) 157// } 158// } 159 160// // masked write 161// for (j <- 0 until numEntries) { 162// val wen = VecInit((0 until blockWords).map(i => io.mwmask(i)(j))).asUInt.orR 163// when (wen) { 164// data(j) := VecInit((0 until blockWords).map(i => { 165// Mux(io.mwmask(i)(j), io.mwdata(i), 0.U) 166// })).reduce(_ | _) 167// } 168// } 169 170// // DataModuleTemplate should not be used when there're any write conflicts 171// for (i <- 0 until numWrite) { 172// for (j <- i+1 until numWrite) { 173// assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 174// } 175// } 176// } 177 178class CoredataModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 179 val io = IO(new Bundle { 180 // data io 181 // read 182 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 183 val rdata = Output(Vec(numRead, UInt(XLEN.W))) 184 // address indexed write 185 val wen = Input(Vec(numWrite, Bool())) 186 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 187 val wdata = Input(Vec(numWrite, UInt(XLEN.W))) 188 // masked write 189 val mwmask = Input(Vec(numEntries, Bool())) 190 val refillData = Input(UInt(l1BusDataWidth.W)) 191 192 // fwdMask io 193 val fwdMaskWdata = Input(Vec(numWrite, UInt(8.W))) 194 val fwdMaskWen = Input(Vec(numWrite, Bool())) 195 // fwdMaskWaddr = waddr 196 197 // paddr io 198 // refillOffBits - wordOffBits bits in paddr need to be stored in CoredataModule for refilling 199 val paddrWdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 200 val paddrWen = Input(Vec(numWrite, Bool())) 201 }) 202 203 val data8 = Seq.fill(8)(Module(new MaskedSyncDataModuleTemplate(UInt(8.W), numEntries, numRead, numWrite, numMWrite = refillWords))) 204 val fwdMask = Reg(Vec(numEntries, UInt(8.W))) 205 val wordIndex = Reg(Vec(numEntries, UInt((refillOffBits - wordOffBits).W))) 206 207 // read ports 208 for (i <- 0 until numRead) { 209 for (j <- 0 until 8) { 210 data8(j).io.raddr(i) := io.raddr(i) 211 } 212 io.rdata(i) := VecInit((0 until 8).map(j => data8(j).io.rdata(i))).asUInt 213 } 214 215 // below is the write ports (with priorities) 216 for (i <- 0 until numWrite) { 217 // write to data8 218 for (j <- 0 until 8) { 219 data8(j).io.waddr(i) := io.waddr(i) 220 data8(j).io.wdata(i) := io.wdata(i)(8*(j+1)-1, 8*j) 221 data8(j).io.wen(i) := io.wen(i) 222 } 223 224 // write ctrl info 225 when (io.fwdMaskWen(i)) { 226 fwdMask(io.waddr(i)) := io.fwdMaskWdata(i) 227 } 228 when (io.paddrWen(i)) { 229 wordIndex(io.waddr(i)) := get_word(io.paddrWdata(i)) 230 } 231 } 232 233 // write refilled data to data8 234 235 // select refill data 236 // split dcache result into words 237 val words = VecInit((0 until refillWords) map { i => io.refillData(DataBits * (i + 1) - 1, DataBits * i)}) 238 // select refill data according to wordIndex (paddr) 239 for (i <- 0 until 8) { 240 for (j <- 0 until refillWords) { 241 data8(i).io.mwdata(j) := words(j)(8*(i+1)-1, 8*i) 242 } 243 } 244 245 // gen refill wmask 246 for (j <- 0 until refillWords) { 247 for (k <- 0 until numEntries) { 248 val wordMatch = wordIndex(k) === j.U 249 for (i <- 0 until 8) { 250 data8(i).io.mwmask(j)(k) := wordMatch && io.mwmask(k) && !fwdMask(k)(i) 251 } 252 } 253 } 254 255 // DataModuleTemplate should not be used when there're any write conflicts 256 for (i <- 0 until numWrite) { 257 for (j <- i+1 until numWrite) { 258 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 259 } 260 } 261} 262 263class LoadQueueData(size: Int, wbNumRead: Int, wbNumWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 264 val io = IO(new Bundle() { 265 val wb = new Bundle() { 266 val wen = Vec(wbNumWrite, Input(Bool())) 267 val waddr = Input(Vec(wbNumWrite, UInt(log2Up(size).W))) 268 val wdata = Input(Vec(wbNumWrite, new LQDataEntry)) 269 val raddr = Input(Vec(wbNumRead, UInt(log2Up(size).W))) 270 val rdata = Output(Vec(wbNumRead, new LQDataEntry)) 271 } 272 val uncache = new Bundle() { 273 val wen = Input(Bool()) 274 val waddr = Input(UInt(log2Up(size).W)) 275 val wdata = Input(UInt(XLEN.W)) // only write back uncache data 276 val raddr = Input(UInt(log2Up(size).W)) 277 val rdata = Output(new LQDataEntry) 278 } 279 val refill = new Bundle() { 280 val valid = Input(Bool()) 281 val paddr = Input(UInt(PAddrBits.W)) 282 val data = Input(UInt(l1BusDataWidth.W)) 283 val refillMask = Input(Vec(size, Bool())) 284 val matchMask = Output(Vec(size, Bool())) 285 } 286 // st-ld violation query, word level cam 287 val violation = Vec(StorePipelineWidth, new Bundle() { 288 val paddr = Input(UInt(PAddrBits.W)) 289 val mask = Input(UInt(8.W)) 290 val violationMask = Output(Vec(size, Bool())) 291 }) 292 // ld-ld violation query, cache line level cam 293 val release_violation = Vec(LoadPipelineWidth, new Bundle() { 294 val paddr = Input(UInt(PAddrBits.W)) 295 val match_mask = Output(Vec(size, Bool())) 296 // if ld-ld violation does happened, we replay from the elder load 297 }) 298 val debug = Output(Vec(size, new LQDataEntry)) 299 300 def wbWrite(channel: Int, waddr: UInt, wdata: LQDataEntry): Unit = { 301 require(channel < wbNumWrite && wbNumWrite >= 0) 302 // need extra "this.wb(channel).wen := true.B" 303 this.wb.waddr(channel) := waddr 304 this.wb.wdata(channel) := wdata 305 } 306 307 def uncacheWrite(waddr: UInt, wdata: UInt): Unit = { 308 // need extra "this.uncache.wen := true.B" 309 this.uncache.waddr := waddr 310 this.uncache.wdata := wdata 311 } 312 313 // def refillWrite(ldIdx: Int): Unit = { 314 // } 315 // use "this.refill.wen(ldIdx) := true.B" instead 316 }) 317 318 // val data = Reg(Vec(size, new LQDataEntry)) 319 // data module 320 val paddrModule = Module(new LQPaddrModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth)) 321 val maskModule = Module(new MaskModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth)) 322 val coredataModule = Module(new CoredataModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth+1)) 323 324 // read data 325 // read port 0 -> wbNumRead-1 326 (0 until wbNumRead).map(i => { 327 paddrModule.io.raddr(i) := io.wb.raddr(i) 328 maskModule.io.raddr(i) := io.wb.raddr(i) 329 coredataModule.io.raddr(i) := io.wb.raddr(i) 330 331 io.wb.rdata(i).paddr := paddrModule.io.rdata(i) 332 io.wb.rdata(i).mask := maskModule.io.rdata(i) 333 io.wb.rdata(i).data := coredataModule.io.rdata(i) 334 io.wb.rdata(i).fwdMask := DontCare 335 }) 336 337 // read port wbNumRead 338 paddrModule.io.raddr(wbNumRead) := io.uncache.raddr 339 maskModule.io.raddr(wbNumRead) := io.uncache.raddr 340 coredataModule.io.raddr(wbNumRead) := io.uncache.raddr 341 342 io.uncache.rdata.paddr := paddrModule.io.rdata(wbNumRead) 343 io.uncache.rdata.mask := maskModule.io.rdata(wbNumRead) 344 io.uncache.rdata.data := coredataModule.io.rdata(wbNumRead) 345 io.uncache.rdata.fwdMask := DontCare 346 347 // write data 348 // write port 0 -> wbNumWrite-1 349 (0 until wbNumWrite).map(i => { 350 paddrModule.io.wen(i) := false.B 351 maskModule.io.wen(i) := false.B 352 coredataModule.io.wen(i) := false.B 353 coredataModule.io.fwdMaskWen(i) := false.B 354 coredataModule.io.paddrWen(i) := false.B 355 356 paddrModule.io.waddr(i) := io.wb.waddr(i) 357 maskModule.io.waddr(i) := io.wb.waddr(i) 358 coredataModule.io.waddr(i) := io.wb.waddr(i) 359 360 paddrModule.io.wdata(i) := io.wb.wdata(i).paddr 361 maskModule.io.wdata(i) := io.wb.wdata(i).mask 362 coredataModule.io.wdata(i) := io.wb.wdata(i).data 363 coredataModule.io.fwdMaskWdata(i) := io.wb.wdata(i).fwdMask.asUInt 364 coredataModule.io.paddrWdata(i) := io.wb.wdata(i).paddr 365 366 when(io.wb.wen(i)){ 367 paddrModule.io.wen(i) := true.B 368 maskModule.io.wen(i) := true.B 369 coredataModule.io.wen(i) := true.B 370 coredataModule.io.fwdMaskWen(i) := true.B 371 coredataModule.io.paddrWen(i) := true.B 372 } 373 }) 374 375 // write port wbNumWrite 376 // exceptionModule.io.wen(wbNumWrite) := false.B 377 coredataModule.io.wen(wbNumWrite) := io.uncache.wen 378 coredataModule.io.fwdMaskWen(wbNumWrite) := false.B 379 coredataModule.io.paddrWen(wbNumWrite) := false.B 380 381 coredataModule.io.waddr(wbNumWrite) := io.uncache.waddr 382 383 coredataModule.io.fwdMaskWdata(wbNumWrite) := DontCare 384 coredataModule.io.paddrWdata(wbNumWrite) := DontCare 385 coredataModule.io.wdata(wbNumWrite) := io.uncache.wdata 386 387 // st-ld mem access violation check, gen violationMask 388 (0 until StorePipelineWidth).map(i => { 389 paddrModule.io.violationMdata(i) := io.violation(i).paddr 390 maskModule.io.violationMdata(i) := io.violation(i).mask 391 io.violation(i).violationMask := (paddrModule.io.violationMmask(i).asUInt & maskModule.io.violationMmask(i).asUInt).asBools 392 }) 393 394 // ld-ld mem access violation check, gen violationMask (cam match mask) 395 (0 until LoadPipelineWidth).map(i => { 396 paddrModule.io.releaseMdata(i) := io.release_violation(i).paddr 397 io.release_violation(i).match_mask := paddrModule.io.releaseMmask(i) 398 }) 399 400 // refill missed load 401 def mergeRefillData(refill: UInt, fwd: UInt, fwdMask: UInt): UInt = { 402 val res = Wire(Vec(8, UInt(8.W))) 403 (0 until 8).foreach(i => { 404 res(i) := Mux(fwdMask(i), fwd(8 * (i + 1) - 1, 8 * i), refill(8 * (i + 1) - 1, 8 * i)) 405 }) 406 res.asUInt 407 } 408 409 // gen paddr match mask 410 paddrModule.io.refillMdata := io.refill.paddr 411 (0 until size).map(i => { 412 io.refill.matchMask := paddrModule.io.refillMmask 413 // io.refill.matchMask(i) := get_block_addr(data(i).paddr) === get_block_addr(io.refill.paddr) 414 }) 415 416 // refill data according to matchMask, refillMask and refill.valid 417 coredataModule.io.refillData := io.refill.data 418 (0 until size).map(i => { 419 coredataModule.io.mwmask(i) := io.refill.valid && io.refill.matchMask(i) && io.refill.refillMask(i) 420 }) 421 422 // debug data read 423 io.debug := DontCare 424} 425