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 paddr = UInt(PAddrBits.W) 31 val mask = UInt(8.W) 32 val data = UInt(XLEN.W) 33 val fwdMask = Vec(8, Bool()) 34} 35 36// Data module define 37// These data modules are like SyncDataModuleTemplate, but support cam-like ops 38 39// load queue paddr module 40// 41// It supports 3 cam sources: 42// * st-ld violation addr cam 43// * data release addr cam 44// * data refill addr cam 45class LQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 46 val io = IO(new Bundle { 47 // normal read/write ports 48 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 49 val rdata = Output(Vec(numRead, UInt((PAddrBits).W))) 50 val wen = Input(Vec(numWrite, Bool())) 51 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 52 val wdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 53 // violation cam: hit if addr is in the same word 54 val violationMdata = Input(Vec(StorePipelineWidth, UInt((PAddrBits).W))) // addr 55 val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool()))) // cam result mask 56 // release cam: hit if addr is in the same cacheline 57 val releaseMdata = Input(Vec(LoadPipelineWidth, UInt((PAddrBits).W))) 58 val releaseMmask = Output(Vec(LoadPipelineWidth, Vec(numEntries, Bool()))) 59 // refill cam: hit if addr is in the same cacheline 60 val refillMdata = Input(UInt((PAddrBits).W)) 61 val refillMmask = Output(Vec(numEntries, Bool())) 62 }) 63 64 val data = Reg(Vec(numEntries, UInt((PAddrBits).W))) 65 66 // read ports 67 for (i <- 0 until numRead) { 68 io.rdata(i) := data(RegNext(io.raddr(i))) 69 } 70 71 // below is the write ports (with priorities) 72 for (i <- 0 until numWrite) { 73 when (io.wen(i)) { 74 data(io.waddr(i)) := io.wdata(i) 75 } 76 } 77 78 // content addressed match 79 for (i <- 0 until StorePipelineWidth) { 80 for (j <- 0 until numEntries) { 81 io.violationMmask(i)(j) := io.violationMdata(i)(PAddrBits-1, DCacheWordOffset) === data(j)(PAddrBits-1, DCacheWordOffset) 82 } 83 } 84 for (i <- 0 until LoadPipelineWidth) { 85 for (j <- 0 until numEntries) { 86 io.releaseMmask(i)(j) := io.releaseMdata(i)(PAddrBits-1, DCacheLineOffset) === data(j)(PAddrBits-1, DCacheLineOffset) 87 } 88 } 89 90 for (j <- 0 until numEntries) { 91 io.refillMmask(j) := get_refill_addr(io.refillMdata) === get_refill_addr(data(j)) 92 } 93 94 // DataModuleTemplate should not be used when there're any write conflicts 95 for (i <- 0 until numWrite) { 96 for (j <- i+1 until numWrite) { 97 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 98 } 99 } 100} 101 102// load queue load mask module 103class LQMaskModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule { 104 val io = IO(new Bundle { 105 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 106 val rdata = Output(Vec(numRead, UInt(8.W))) 107 val wen = Input(Vec(numWrite, Bool())) 108 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 109 val wdata = Input(Vec(numWrite, UInt(8.W))) 110 // st-ld violation check wmask compare 111 val violationMdata = Input(Vec(StorePipelineWidth, UInt(8.W))) // input 8-bit wmask 112 val violationMmask = Output(Vec(StorePipelineWidth, Vec(numEntries, Bool()))) // output wmask overlap vector 113 }) 114 115 val data = Reg(Vec(numEntries, UInt(8.W))) 116 117 // read ports 118 for (i <- 0 until numRead) { 119 io.rdata(i) := data(RegNext(io.raddr(i))) 120 } 121 122 // below is the write ports (with priorities) 123 for (i <- 0 until numWrite) { 124 when (io.wen(i)) { 125 data(io.waddr(i)) := io.wdata(i) 126 } 127 } 128 129 // st-ld violation check wmask compare 130 for (i <- 0 until StorePipelineWidth) { 131 for (j <- 0 until numEntries) { 132 io.violationMmask(i)(j) := (io.violationMdata(i) & data(j)).orR 133 } 134 } 135 136 // DataModuleTemplate should not be used when there're any write conflicts 137 for (i <- 0 until numWrite) { 138 for (j <- i+1 until numWrite) { 139 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 140 } 141 } 142} 143 144// SQDataModule is a wrapper of 8 bit MaskedSyncDataModuleTemplates 145// 146// It also contains: 147// * fwdMask, which is used to merge refill data and forwarded data 148// * word index extracted from paddr, which is used to select data from refill data (a cacheline) 149class LQDataModule(numEntries: Int, numRead: Int, numWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 150 val io = IO(new Bundle { 151 // sync read 152 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 153 val rdata = Output(Vec(numRead, UInt(XLEN.W))) 154 155 // address indexed write 156 val wen = Input(Vec(numWrite, Bool())) 157 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 158 val wdata = Input(Vec(numWrite, UInt(XLEN.W))) 159 // forward mask needs to be recorded to merge data 160 val fwdMaskWdata = Input(Vec(numWrite, UInt(8.W))) 161 // refillOffBits - wordOffBits bits in paddr need to be stored in LQDataModule for refilling 162 val paddrWdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 163 164 // masked write 165 val mwmask = Input(Vec(numEntries, Bool())) 166 val refillData = Input(UInt(l1BusDataWidth.W)) 167 }) 168 169 val data8 = Seq.fill(8)(Module(new MaskedBankedSyncDataModuleTemplate( 170 UInt(8.W), numEntries, numRead, numWrite, numMWrite = refillWords, numWBanks = LoadQueueNWriteBanks 171 ))) 172 val fwdMask = Reg(Vec(numEntries, UInt(8.W))) 173 val wordIndex = Reg(Vec(numEntries, UInt((refillOffBits - wordOffBits).W))) 174 175 // read ports 176 for (i <- 0 until numRead) { 177 for (j <- 0 until 8) { 178 data8(j).io.raddr(i) := io.raddr(i) 179 } 180 io.rdata(i) := VecInit((0 until 8).map(j => data8(j).io.rdata(i))).asUInt 181 } 182 183 // below is the write ports (with priorities) 184 for (i <- 0 until numWrite) { 185 // write to data8 186 for (j <- 0 until 8) { 187 data8(j).io.waddr(i) := io.waddr(i) 188 data8(j).io.wdata(i) := io.wdata(i)(8*(j+1)-1, 8*j) 189 data8(j).io.wen(i) := io.wen(i) 190 } 191 192 // write ctrl info 193 when (io.wen(i)) { 194 fwdMask(io.waddr(i)) := io.fwdMaskWdata(i) 195 } 196 when (io.wen(i)) { 197 wordIndex(io.waddr(i)) := get_word(io.paddrWdata(i)) 198 } 199 } 200 201 // write refilled data to data8 202 203 // select refill data 204 // split dcache result into words 205 val words = VecInit((0 until refillWords) map { i => io.refillData(DataBits * (i + 1) - 1, DataBits * i)}) 206 // select refill data according to wordIndex (paddr) 207 for (i <- 0 until 8) { 208 for (j <- 0 until refillWords) { 209 data8(i).io.mwdata(j) := words(j)(8*(i+1)-1, 8*i) 210 } 211 } 212 213 // gen refill wmask 214 for (j <- 0 until refillWords) { 215 for (k <- 0 until numEntries) { 216 val wordMatch = wordIndex(k) === j.U 217 for (i <- 0 until 8) { 218 data8(i).io.mwmask(j)(k) := wordMatch && io.mwmask(k) && !fwdMask(k)(i) 219 } 220 } 221 } 222 223 // DataModuleTemplate should not be used when there're any write conflicts 224 for (i <- 0 until numWrite) { 225 for (j <- i+1 until numWrite) { 226 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 227 } 228 } 229} 230 231// LoadQueueDataWrapper wraps: 232// * load queue paddrModule 233// * load queue maskModule 234// * load queue dataModule 235// and their interconnect 236class LoadQueueDataWrapper(size: Int, wbNumRead: Int, wbNumWrite: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 237 val io = IO(new Bundle() { 238 val wb = new Bundle() { 239 val wen = Vec(wbNumWrite, Input(Bool())) 240 val waddr = Input(Vec(wbNumWrite, UInt(log2Up(size).W))) 241 val wdata = Input(Vec(wbNumWrite, new LQDataEntry)) 242 val raddr = Input(Vec(wbNumRead, UInt(log2Up(size).W))) 243 val rdata = Output(Vec(wbNumRead, new LQDataEntry)) 244 } 245 val uncache = new Bundle() { 246 val wen = Input(Bool()) 247 val waddr = Input(UInt(log2Up(size).W)) 248 val wdata = Input(UInt(XLEN.W)) // only write back uncache data 249 val raddr = Input(UInt(log2Up(size).W)) 250 val rdata = Output(new LQDataEntry) 251 } 252 val refill = new Bundle() { 253 val valid = Input(Bool()) 254 val paddr = Input(UInt(PAddrBits.W)) 255 val data = Input(UInt(l1BusDataWidth.W)) 256 val refillMask = Input(Vec(size, Bool())) 257 val matchMask = Output(Vec(size, Bool())) 258 } 259 // st-ld violation query, word level cam 260 val violation = Vec(StorePipelineWidth, new Bundle() { 261 val paddr = Input(UInt(PAddrBits.W)) 262 val mask = Input(UInt(8.W)) 263 val violationMask = Output(Vec(size, Bool())) 264 }) 265 // ld-ld violation query, cache line level cam 266 val release_violation = Vec(LoadPipelineWidth, new Bundle() { 267 val paddr = Input(UInt(PAddrBits.W)) 268 val match_mask = Output(Vec(size, Bool())) 269 // if ld-ld violation does happened, we replay from the elder load 270 }) 271 val debug = Output(Vec(size, new LQDataEntry)) 272 273 def wbWrite(channel: Int, waddr: UInt, wdata: LQDataEntry): Unit = { 274 require(channel < wbNumWrite && wbNumWrite >= 0) 275 // need extra "this.wb(channel).wen := true.B" 276 this.wb.waddr(channel) := waddr 277 this.wb.wdata(channel) := wdata 278 } 279 280 def uncacheWrite(waddr: UInt, wdata: UInt): Unit = { 281 // need extra "this.uncache.wen := true.B" 282 this.uncache.waddr := waddr 283 this.uncache.wdata := wdata 284 } 285 }) 286 287 // data module 288 val paddrModule = Module(new LQPaddrModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth)) 289 val maskModule = Module(new LQMaskModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth)) 290 val dataModule = Module(new LQDataModule(size, numRead = LoadPipelineWidth+1, numWrite = LoadPipelineWidth+1)) 291 292 // read data 293 // read port 0 -> wbNumRead-1 294 (0 until wbNumRead).map(i => { 295 paddrModule.io.raddr(i) := io.wb.raddr(i) 296 maskModule.io.raddr(i) := io.wb.raddr(i) 297 dataModule.io.raddr(i) := io.wb.raddr(i) 298 299 io.wb.rdata(i).paddr := paddrModule.io.rdata(i) 300 io.wb.rdata(i).mask := maskModule.io.rdata(i) 301 io.wb.rdata(i).data := dataModule.io.rdata(i) 302 io.wb.rdata(i).fwdMask := DontCare 303 }) 304 305 // read port wbNumRead 306 paddrModule.io.raddr(wbNumRead) := io.uncache.raddr 307 maskModule.io.raddr(wbNumRead) := io.uncache.raddr 308 dataModule.io.raddr(wbNumRead) := io.uncache.raddr 309 310 io.uncache.rdata.paddr := paddrModule.io.rdata(wbNumRead) 311 io.uncache.rdata.mask := maskModule.io.rdata(wbNumRead) 312 io.uncache.rdata.data := dataModule.io.rdata(wbNumRead) 313 io.uncache.rdata.fwdMask := DontCare 314 315 // write data 316 // write port 0 -> wbNumWrite-1 317 (0 until wbNumWrite).map(i => { 318 paddrModule.io.wen(i) := false.B 319 maskModule.io.wen(i) := false.B 320 dataModule.io.wen(i) := false.B 321 322 paddrModule.io.waddr(i) := io.wb.waddr(i) 323 maskModule.io.waddr(i) := io.wb.waddr(i) 324 dataModule.io.waddr(i) := io.wb.waddr(i) 325 326 paddrModule.io.wdata(i) := io.wb.wdata(i).paddr 327 maskModule.io.wdata(i) := io.wb.wdata(i).mask 328 dataModule.io.wdata(i) := io.wb.wdata(i).data 329 dataModule.io.fwdMaskWdata(i) := io.wb.wdata(i).fwdMask.asUInt 330 dataModule.io.paddrWdata(i) := io.wb.wdata(i).paddr 331 332 when(io.wb.wen(i)){ 333 paddrModule.io.wen(i) := true.B 334 maskModule.io.wen(i) := true.B 335 dataModule.io.wen(i) := true.B 336 } 337 }) 338 339 // write port wbNumWrite 340 dataModule.io.wen(wbNumWrite) := io.uncache.wen 341 // dataModule.io.fwdMaskWen(wbNumWrite) := false.B 342 // dataModule.io.paddrWen(wbNumWrite) := false.B 343 344 dataModule.io.waddr(wbNumWrite) := io.uncache.waddr 345 346 dataModule.io.fwdMaskWdata(wbNumWrite) := DontCare 347 dataModule.io.paddrWdata(wbNumWrite) := DontCare 348 dataModule.io.wdata(wbNumWrite) := io.uncache.wdata 349 350 // st-ld mem access violation check, gen violationMask 351 (0 until StorePipelineWidth).map(i => { 352 paddrModule.io.violationMdata(i) := io.violation(i).paddr 353 maskModule.io.violationMdata(i) := io.violation(i).mask 354 io.violation(i).violationMask := (paddrModule.io.violationMmask(i).asUInt & maskModule.io.violationMmask(i).asUInt).asBools 355 }) 356 357 // ld-ld mem access violation check, gen violationMask (cam match mask) 358 (0 until LoadPipelineWidth).map(i => { 359 paddrModule.io.releaseMdata(i) := io.release_violation(i).paddr 360 io.release_violation(i).match_mask := paddrModule.io.releaseMmask(i) 361 }) 362 363 // gen paddr match mask 364 paddrModule.io.refillMdata := io.refill.paddr 365 (0 until size).map(i => { 366 io.refill.matchMask := paddrModule.io.refillMmask 367 // io.refill.matchMask(i) := get_block_addr(data(i).paddr) === get_block_addr(io.refill.paddr) 368 }) 369 370 // refill data according to matchMask, refillMask and refill.valid 371 dataModule.io.refillData := io.refill.data 372 (0 until size).map(i => { 373 dataModule.io.mwmask(i) := io.refill.valid && io.refill.matchMask(i) && io.refill.refillMask(i) 374 }) 375 376 // debug data read 377 io.debug := DontCare 378} 379