1/*************************************************************************************** 2* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences 4* Copyright (c) 2020-2021 Peng Cheng Laboratory 5* 6* XiangShan is licensed under Mulan PSL v2. 7* You can use this software according to the terms and conditions of the Mulan PSL v2. 8* You may obtain a copy of Mulan PSL v2 at: 9* http://license.coscl.org.cn/MulanPSL2 10* 11* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14* 15* See the Mulan PSL v2 for more details. 16* 17* 18* Acknowledgement 19* 20* This implementation is inspired by several key papers: 21* [1] Gurindar S. Sohi, and Manoj Franklin. "[High-bandwidth data memory systems for superscalar processors.] 22* (https://doi.org/10.1145/106972.106980)" 4th International Conference on Architectural Support for Programming 23* Languages and Operating Systems (ASPLOS). 1991. 24***************************************************************************************/ 25 26package xiangshan.cache 27 28import org.chipsalliance.cde.config.Parameters 29import chisel3._ 30import utils._ 31import utility._ 32import chisel3.util._ 33import freechips.rocketchip.tilelink.{ClientMetadata, TLClientParameters, TLEdgeOut} 34import xiangshan.mem.LqPtr 35import xiangshan.{L1CacheErrorInfo, XSCoreParamsKey} 36 37import scala.math.max 38 39class BankConflictDB(implicit p: Parameters) extends DCacheBundle{ 40 val addr = Vec(LoadPipelineWidth, Bits(PAddrBits.W)) 41 val set_index = Vec(LoadPipelineWidth, UInt((DCacheAboveIndexOffset - DCacheSetOffset).W)) 42 val bank_index = Vec(VLEN/DCacheSRAMRowBits, UInt((DCacheSetOffset - DCacheBankOffset).W)) 43 val way_index = UInt(wayBits.W) 44 val fake_rr_bank_conflict = Bool() 45} 46 47class L1BankedDataReadReq(implicit p: Parameters) extends DCacheBundle 48{ 49 val way_en = Bits(DCacheWays.W) 50 val addr = Bits(PAddrBits.W) 51} 52 53class L1BankedDataReadReqWithMask(implicit p: Parameters) extends DCacheBundle 54{ 55 val way_en = Bits(DCacheWays.W) 56 val addr = Bits(PAddrBits.W) 57 val bankMask = Bits(DCacheBanks.W) 58 val kill = Bool() 59 val lqIdx = new LqPtr 60} 61 62class L1BankedDataReadLineReq(implicit p: Parameters) extends L1BankedDataReadReq 63{ 64 val rmask = Bits(DCacheBanks.W) 65} 66 67// Now, we can write a cache-block in a single cycle 68class L1BankedDataWriteReq(implicit p: Parameters) extends L1BankedDataReadReq 69{ 70 val wmask = Bits(DCacheBanks.W) 71 val data = Vec(DCacheBanks, Bits(DCacheSRAMRowBits.W)) 72} 73 74// cache-block write request without data 75class L1BankedDataWriteReqCtrl(implicit p: Parameters) extends L1BankedDataReadReq 76 77class L1BankedDataReadResult(implicit p: Parameters) extends DCacheBundle 78{ 79 // you can choose which bank to read to save power 80 val ecc = Bits(dataECCBits.W) 81 val raw_data = Bits(DCacheSRAMRowBits.W) 82 val error_delayed = Bool() // 1 cycle later than data resp 83 84 def asECCData() = { 85 Cat(ecc, raw_data) 86 } 87} 88 89class DataSRAMBankWriteReq(implicit p: Parameters) extends DCacheBundle { 90 val en = Bool() 91 val addr = UInt() 92 val way_en = UInt(DCacheWays.W) 93 val data = UInt(encDataBits.W) 94} 95 96// wrap a sram 97class DataSRAM(bankIdx: Int, wayIdx: Int)(implicit p: Parameters) extends DCacheModule { 98 val io = IO(new Bundle() { 99 val w = new Bundle() { 100 val en = Input(Bool()) 101 val addr = Input(UInt()) 102 val data = Input(UInt(encDataBits.W)) 103 } 104 105 val r = new Bundle() { 106 val en = Input(Bool()) 107 val addr = Input(UInt()) 108 val data = Output(UInt(encDataBits.W)) 109 } 110 }) 111 112 // data sram 113 val data_sram = Module(new SRAMTemplate( 114 Bits(encDataBits.W), 115 set = DCacheSets / DCacheSetDiv, 116 way = 1, 117 shouldReset = false, 118 holdRead = false, 119 singlePort = true 120 )) 121 122 data_sram.io.w.req.valid := io.w.en 123 data_sram.io.w.req.bits.apply( 124 setIdx = io.w.addr, 125 data = io.w.data, 126 waymask = 1.U 127 ) 128 data_sram.io.r.req.valid := io.r.en 129 data_sram.io.r.req.bits.apply(setIdx = io.r.addr) 130 io.r.data := data_sram.io.r.resp.data(0) 131 XSPerfAccumulate("part_data_read_counter", data_sram.io.r.req.valid) 132 133 def dump_r() = { 134 when(RegNext(io.r.en)) { 135 XSDebug("bank read set %x bank %x way %x data %x\n", 136 RegEnable(io.r.addr, io.r.en), 137 bankIdx.U, 138 wayIdx.U, 139 io.r.data 140 ) 141 } 142 } 143 144 def dump_w() = { 145 when(io.w.en) { 146 XSDebug("bank write set %x bank %x way %x data %x\n", 147 io.w.addr, 148 bankIdx.U, 149 wayIdx.U, 150 io.w.data 151 ) 152 } 153 } 154 155 def dump() = { 156 dump_w() 157 dump_r() 158 } 159} 160 161// wrap data rows of 8 ways 162class DataSRAMBank(index: Int)(implicit p: Parameters) extends DCacheModule { 163 val io = IO(new Bundle() { 164 val w = Input(new DataSRAMBankWriteReq) 165 166 val r = new Bundle() { 167 val en = Input(Bool()) 168 val addr = Input(UInt()) 169 val data = Output(Vec(DCacheWays, UInt(encDataBits.W))) 170 } 171 }) 172 173 assert(RegNext(!io.w.en || PopCount(io.w.way_en) <= 1.U)) 174 175 // external controls do not read and write at the same time 176 val w_info = io.w 177 // val rw_bypass = RegNext(io.w.addr === io.r.addr && io.w.way_en === io.r.way_en && io.w.en) 178 179 // multiway data bank 180 val data_bank = Seq.fill(DCacheWays) { 181 Module(new SRAMTemplate( 182 Bits(encDataBits.W), 183 set = DCacheSets / DCacheSetDiv, 184 way = 1, 185 shouldReset = false, 186 holdRead = false, 187 singlePort = true 188 )) 189 } 190 191 for (w <- 0 until DCacheWays) { 192 val wen = w_info.en && w_info.way_en(w) 193 data_bank(w).io.w.req.valid := wen 194 data_bank(w).io.w.req.bits.apply( 195 setIdx = w_info.addr, 196 data = w_info.data, 197 waymask = 1.U 198 ) 199 data_bank(w).io.r.req.valid := io.r.en 200 data_bank(w).io.r.req.bits.apply(setIdx = io.r.addr) 201 data_bank(w).clock := ClockGate(false.B, io.r.en | (io.w.en & io.w.way_en(w)), clock) 202 } 203 XSPerfAccumulate("part_data_read_counter", PopCount(Cat(data_bank.map(_.io.r.req.valid)))) 204 205 io.r.data := data_bank.map(_.io.r.resp.data(0)) 206 207 def dump_r() = { 208 when(RegNext(io.r.en)) { 209 XSDebug("bank read addr %x data %x\n", 210 RegEnable(io.r.addr, io.r.en), 211 io.r.data.asUInt 212 ) 213 } 214 } 215 216 def dump_w() = { 217 when(io.w.en) { 218 XSDebug("bank write addr %x way_en %x data %x\n", 219 io.w.addr, 220 io.w.way_en, 221 io.w.data 222 ) 223 } 224 } 225 226 def dump() = { 227 dump_w() 228 dump_r() 229 } 230} 231 232case object HasDataEccParam 233 234// Banked DCache Data 235// ----------------------------------------------------------------- 236// | Bank0 | Bank1 | Bank2 | Bank3 | Bank4 | Bank5 | Bank6 | Bank7 | 237// ----------------------------------------------------------------- 238// | Way0 | Way0 | Way0 | Way0 | Way0 | Way0 | Way0 | Way0 | 239// | Way1 | Way1 | Way1 | Way1 | Way1 | Way1 | Way1 | Way1 | 240// | .... | .... | .... | .... | .... | .... | .... | .... | 241// ----------------------------------------------------------------- 242abstract class AbstractBankedDataArray(implicit p: Parameters) extends DCacheModule 243{ 244 val DataEccParam = if(EnableDataEcc) Some(HasDataEccParam) else None 245 val ReadlinePortErrorIndex = LoadPipelineWidth 246 val io = IO(new DCacheBundle { 247 // load pipeline read word req 248 val read = Vec(LoadPipelineWidth, Flipped(DecoupledIO(new L1BankedDataReadReqWithMask))) 249 val is128Req = Input(Vec(LoadPipelineWidth, Bool())) 250 // main pipeline read / write line req 251 val readline_intend = Input(Bool()) 252 val readline = Flipped(DecoupledIO(new L1BankedDataReadLineReq)) 253 val write = Flipped(DecoupledIO(new L1BankedDataWriteReq)) 254 val write_dup = Vec(DCacheBanks, Flipped(Decoupled(new L1BankedDataWriteReqCtrl))) 255 // data for readline and loadpipe 256 val readline_resp = Output(Vec(DCacheBanks, new L1BankedDataReadResult())) 257 val readline_error_delayed = Output(Bool()) 258 val read_resp = Output(Vec(LoadPipelineWidth, Vec(VLEN/DCacheSRAMRowBits, new L1BankedDataReadResult()))) 259 val read_error_delayed = Output(Vec(LoadPipelineWidth,Vec(VLEN/DCacheSRAMRowBits, Bool()))) 260 // val nacks = Output(Vec(LoadPipelineWidth, Bool())) 261 // val errors = Output(Vec(LoadPipelineWidth + 1, ValidIO(new L1CacheErrorInfo))) // read ports + readline port 262 // when bank_conflict, read (1) port should be ignored 263 val bank_conflict_slow = Output(Vec(LoadPipelineWidth, Bool())) 264 val disable_ld_fast_wakeup = Output(Vec(LoadPipelineWidth, Bool())) 265 // customized cache op port 266 val cacheOp = Flipped(new L1CacheInnerOpIO) 267 val cacheOp_req_dup = Vec(DCacheDupNum, Flipped(Valid(new CacheCtrlReqInfo))) 268 val cacheOp_req_bits_opCode_dup = Input(Vec(DCacheDupNum, UInt(XLEN.W))) 269 val pseudo_error = Flipped(DecoupledIO(Vec(DCacheBanks, new CtrlUnitSignalingBundle))) 270 }) 271 272 def pipeMap[T <: Data](f: Int => T) = VecInit((0 until LoadPipelineWidth).map(f)) 273 274 def getECCFromEncWord(encWord: UInt) = { 275 if (EnableDataEcc) { 276 require(encWord.getWidth == encDataBits, s"encDataBits=$encDataBits != encDataBits=$encDataBits!") 277 encWord(encDataBits-1, DCacheSRAMRowBits) 278 } else { 279 0.U 280 } 281 } 282 283 def getDataFromEncWord(encWord: UInt) = { 284 encWord(DCacheSRAMRowBits-1, 0) 285 } 286 287 def asECCData(ecc: UInt, data: UInt) = { 288 if (EnableDataEcc) { 289 Cat(ecc, data) 290 } else { 291 data 292 } 293 } 294 295 def dumpRead = { 296 (0 until LoadPipelineWidth) map { w => 297 when(io.read(w).valid) { 298 XSDebug(s"DataArray Read channel: $w valid way_en: %x addr: %x\n", 299 io.read(w).bits.way_en, io.read(w).bits.addr) 300 } 301 } 302 when(io.readline.valid) { 303 XSDebug(s"DataArray Read Line, valid way_en: %x addr: %x rmask %x\n", 304 io.readline.bits.way_en, io.readline.bits.addr, io.readline.bits.rmask) 305 } 306 } 307 308 def dumpWrite = { 309 when(io.write.valid) { 310 XSDebug(s"DataArray Write valid way_en: %x addr: %x\n", 311 io.write.bits.way_en, io.write.bits.addr) 312 313 (0 until DCacheBanks) map { r => 314 XSDebug(s"cycle: $r data: %x wmask: %x\n", 315 io.write.bits.data(r), io.write.bits.wmask(r)) 316 } 317 } 318 } 319 320 def dumpResp = { 321 XSDebug(s"DataArray ReadeResp channel:\n") 322 (0 until LoadPipelineWidth) map { r => 323 XSDebug(s"cycle: $r data: %x\n", Mux(io.is128Req(r), 324 Cat(io.read_resp(r)(1).raw_data,io.read_resp(r)(0).raw_data), 325 io.read_resp(r)(0).raw_data)) 326 } 327 } 328 329 def dump() = { 330 dumpRead 331 dumpWrite 332 dumpResp 333 } 334 335 def selcetOldestPort(valid: Seq[Bool], bits: Seq[LqPtr], index: Seq[UInt]):((Bool, LqPtr), UInt) = { 336 require(valid.length == bits.length && bits.length == index.length, s"length must eq, valid:${valid.length}, bits:${bits.length}, index:${index.length}") 337 ParallelOperation(valid zip bits zip index, 338 (a: ((Bool, LqPtr), UInt), b: ((Bool, LqPtr), UInt)) => { 339 val au = a._1._2 340 val bu = b._1._2 341 val aValid = a._1._1 342 val bValid = b._1._1 343 val bSel = au > bu 344 val bits = Mux( 345 aValid && bValid, 346 Mux(bSel, b._1._2, a._1._2), 347 Mux(aValid && !bValid, a._1._2, b._1._2) 348 ) 349 val idx = Mux( 350 aValid && bValid, 351 Mux(bSel, b._2, a._2), 352 Mux(aValid && !bValid, a._2, b._2) 353 ) 354 ((aValid || bValid, bits), idx) 355 } 356 ) 357 } 358 359} 360 361// the smallest access unit is sram 362class SramedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { 363 println(" DCacheType: SramedDataArray") 364 val ReduceReadlineConflict = false 365 366 io.write.ready := true.B 367 io.write_dup.foreach(_.ready := true.B) 368 369 val data_banks = List.tabulate(DCacheSetDiv)( k => List.tabulate(DCacheBanks)(i => List.tabulate(DCacheWays)(j => Module(new DataSRAM(i,j))))) 370 data_banks.map(_.map(_.map(_.dump()))) 371 372 val way_en = Wire(Vec(LoadPipelineWidth, io.read(0).bits.way_en.cloneType)) 373 val set_addrs = Wire(Vec(LoadPipelineWidth, UInt())) 374 val div_addrs = Wire(Vec(LoadPipelineWidth, UInt())) 375 val bank_addrs = Wire(Vec(LoadPipelineWidth, Vec(VLEN/DCacheSRAMRowBits, UInt()))) 376 377 val line_set_addr = addr_to_dcache_div_set(io.readline.bits.addr) 378 val line_div_addr = addr_to_dcache_div(io.readline.bits.addr) 379 // when WPU is enabled, line_way_en is all enabled when read data 380 val line_way_en = Fill(DCacheWays, 1.U) // val line_way_en = io.readline.bits.way_en 381 val line_way_en_reg = RegEnable(io.readline.bits.way_en, 0.U(DCacheWays.W),io.readline.valid) 382 383 val write_bank_mask_reg = RegEnable(io.write.bits.wmask, 0.U(DCacheBanks.W), io.write.valid) 384 val write_data_reg = RegEnable(io.write.bits.data, io.write.valid) 385 val write_valid_reg = RegNext(io.write.valid) 386 val write_valid_dup_reg = io.write_dup.map(x => RegNext(x.valid)) 387 val write_wayen_dup_reg = io.write_dup.map(x => RegEnable(x.bits.way_en, 0.U(DCacheWays.W), x.valid)) 388 val write_set_addr_dup_reg = io.write_dup.map(x => RegEnable(addr_to_dcache_div_set(x.bits.addr), x.valid)) 389 val write_div_addr_dup_reg = io.write_dup.map(x => RegEnable(addr_to_dcache_div(x.bits.addr), x.valid)) 390 391 // read data_banks and ecc_banks 392 // for single port SRAM, do not allow read and write in the same cycle 393 val rrhazard = false.B // io.readline.valid 394 (0 until LoadPipelineWidth).map(rport_index => { 395 div_addrs(rport_index) := addr_to_dcache_div(io.read(rport_index).bits.addr) 396 set_addrs(rport_index) := addr_to_dcache_div_set(io.read(rport_index).bits.addr) 397 bank_addrs(rport_index)(0) := addr_to_dcache_bank(io.read(rport_index).bits.addr) 398 bank_addrs(rport_index)(1) := bank_addrs(rport_index)(0) + 1.U 399 400 // use way_en to select a way after data read out 401 assert(!(RegNext(io.read(rport_index).fire && PopCount(io.read(rport_index).bits.way_en) > 1.U))) 402 way_en(rport_index) := io.read(rport_index).bits.way_en 403 }) 404 405 // read conflict 406 val rr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => Seq.tabulate(LoadPipelineWidth)(y => { 407 if (x == y) { 408 false.B 409 } else { 410 io.read(x).valid && io.read(y).valid && 411 div_addrs(x) === div_addrs(y) && 412 (io.read(x).bits.bankMask & io.read(y).bits.bankMask) =/= 0.U && 413 io.read(x).bits.way_en === io.read(y).bits.way_en && 414 set_addrs(x) =/= set_addrs(y) 415 } 416 })) 417 val load_req_with_bank_conflict = rr_bank_conflict.map(_.reduce(_ || _)) 418 val load_req_valid = io.read.map(_.valid) 419 val load_req_lqIdx = io.read.map(_.bits.lqIdx) 420 val load_req_index = (0 until LoadPipelineWidth).map(_.asUInt) 421 422 423 val load_req_bank_conflict_selcet = selcetOldestPort(load_req_with_bank_conflict, load_req_lqIdx, load_req_index) 424 val load_req_bank_select_port = UIntToOH(load_req_bank_conflict_selcet._2).asBools 425 426 val rr_bank_conflict_oldest = (0 until LoadPipelineWidth).map(i => 427 !load_req_bank_select_port(i) && load_req_with_bank_conflict(i) 428 ) 429 430 val rrl_bank_conflict = Wire(Vec(LoadPipelineWidth, Bool())) 431 val rrl_bank_conflict_intend = Wire(Vec(LoadPipelineWidth, Bool())) 432 (0 until LoadPipelineWidth).foreach { i => 433 val judge = if (ReduceReadlineConflict) io.read(i).valid && (io.readline.bits.rmask & io.read(i).bits.bankMask) =/= 0.U && line_div_addr === div_addrs(i) && line_set_addr =/= set_addrs(i) 434 else io.read(i).valid && line_div_addr === div_addrs(i) && line_set_addr =/= set_addrs(i) 435 rrl_bank_conflict(i) := judge && io.readline.valid 436 rrl_bank_conflict_intend(i) := judge && io.readline_intend 437 } 438 val wr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => 439 io.read(x).valid && write_valid_reg && 440 div_addrs(x) === write_div_addr_dup_reg.head && 441 way_en(x) === write_wayen_dup_reg.head && 442 (write_bank_mask_reg(bank_addrs(x)(0)) || write_bank_mask_reg(bank_addrs(x)(1)) && io.is128Req(x)) 443 ) 444 val wrl_bank_conflict = io.readline.valid && write_valid_reg && line_div_addr === write_div_addr_dup_reg.head 445 // ready 446 io.readline.ready := !(wrl_bank_conflict) 447 io.read.zipWithIndex.map { case (x, i) => x.ready := !(wr_bank_conflict(i) || rrhazard) } 448 449 val perf_multi_read = PopCount(io.read.map(_.valid)) >= 2.U 450 val bank_conflict_fast = Wire(Vec(LoadPipelineWidth, Bool())) 451 (0 until LoadPipelineWidth).foreach(i => { 452 bank_conflict_fast(i) := wr_bank_conflict(i) || rrl_bank_conflict(i) || 453 rr_bank_conflict_oldest(i) 454 io.bank_conflict_slow(i) := RegNext(bank_conflict_fast(i)) 455 io.disable_ld_fast_wakeup(i) := wr_bank_conflict(i) || rrl_bank_conflict_intend(i) || 456 (if (i == 0) 0.B else (0 until i).map(rr_bank_conflict(_)(i)).reduce(_ || _)) 457 }) 458 XSPerfAccumulate("data_array_multi_read", perf_multi_read) 459 (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x => 460 XSPerfAccumulate(s"data_array_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y)) 461 )) 462 (0 until LoadPipelineWidth).foreach(i => { 463 XSPerfAccumulate(s"data_array_rrl_bank_conflict_${i}", rrl_bank_conflict(i)) 464 XSPerfAccumulate(s"data_array_rw_bank_conflict_${i}", wr_bank_conflict(i)) 465 XSPerfAccumulate(s"data_array_read_${i}", io.read(i).valid) 466 }) 467 XSPerfAccumulate("data_array_access_total", PopCount(io.read.map(_.valid))) 468 XSPerfAccumulate("data_array_read_line", io.readline.valid) 469 XSPerfAccumulate("data_array_write", io.write.valid) 470 471 val read_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays,new L1BankedDataReadResult())))) 472 val read_result_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays,new L1BankedDataReadResult())))) 473 val read_error_delayed_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) 474 dontTouch(read_result) 475 dontTouch(read_error_delayed_result) 476 477 val pseudo_data_toggle_mask = io.pseudo_error.bits.map { 478 case bank => 479 Mux(io.pseudo_error.valid && bank.valid, bank.mask, 0.U) 480 } 481 val readline_hit = io.readline.fire && 482 (io.readline.bits.rmask & VecInit(io.pseudo_error.bits.map(_.valid)).asUInt).orR 483 val readbank_hit = io.read.zip(bank_addrs.zip(io.is128Req)).zipWithIndex.map { 484 case ((read, (bank_addr, is128Req)), i) => 485 val error_bank0 = io.pseudo_error.bits(bank_addr(0)) 486 val error_bank1 = io.pseudo_error.bits(bank_addr(1)) 487 read.fire && (error_bank0.valid || error_bank1.valid && is128Req) && !io.bank_conflict_slow(i) 488 }.reduce(_|_) 489 io.pseudo_error.ready := RegNext(readline_hit || readbank_hit) 490 491 for (div_index <- 0 until DCacheSetDiv){ 492 for (bank_index <- 0 until DCacheBanks) { 493 for (way_index <- 0 until DCacheWays) { 494 // Set Addr & Read Way Mask 495 // 496 // Pipe 0 .... Pipe (n-1) 497 // + .... + 498 // | .... | 499 // +----+---------------+-----+ 500 // X X 501 // X +------+ Bank Addr Match 502 // +---------+----------+ 503 // | 504 // +--------+--------+ 505 // | Data Bank | 506 // +-----------------+ 507 val loadpipe_en = WireInit(VecInit(List.tabulate(LoadPipelineWidth)(i => { 508 io.read(i).valid && div_addrs(i) === div_index.U && (bank_addrs(i)(0) === bank_index.U || bank_addrs(i)(1) === bank_index.U && io.is128Req(i)) && 509 way_en(i)(way_index) && 510 !rr_bank_conflict_oldest(i) 511 }))) 512 val readline_en = Wire(Bool()) 513 if (ReduceReadlineConflict) { 514 readline_en := io.readline.valid && io.readline.bits.rmask(bank_index) && line_way_en(way_index) && div_index.U === line_div_addr 515 } else { 516 readline_en := io.readline.valid && line_way_en(way_index) && div_index.U === line_div_addr 517 } 518 val sram_set_addr = Mux(readline_en, 519 addr_to_dcache_div_set(io.readline.bits.addr), 520 PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => loadpipe_en(i) -> set_addrs(i))) 521 ) 522 val read_en = loadpipe_en.asUInt.orR || readline_en 523 // read raw data 524 val data_bank = data_banks(div_index)(bank_index)(way_index) 525 data_bank.io.r.en := read_en 526 data_bank.io.r.addr := sram_set_addr 527 528 read_result(div_index)(bank_index)(way_index).ecc := getECCFromEncWord(data_bank.io.r.data) 529 read_result(div_index)(bank_index)(way_index).raw_data := getDataFromEncWord(data_bank.io.r.data) ^ pseudo_data_toggle_mask(bank_index) 530 531 if (EnableDataEcc) { 532 val ecc_data = read_result(div_index)(bank_index)(way_index).asECCData() 533 val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_en)) 534 read_result(div_index)(bank_index)(way_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error 535 read_error_delayed_result(div_index)(bank_index)(way_index) := read_result(div_index)(bank_index)(way_index).error_delayed 536 } else { 537 read_result(div_index)(bank_index)(way_index).error_delayed := false.B 538 read_error_delayed_result(div_index)(bank_index)(way_index) := false.B 539 } 540 541 read_result_delayed(div_index)(bank_index)(way_index) := RegEnable(read_result(div_index)(bank_index)(way_index), RegNext(read_en)) 542 } 543 } 544 } 545 546 val data_read_oh = WireInit(VecInit(Seq.fill(DCacheSetDiv * DCacheBanks * DCacheWays)(0.U(1.W)))) 547 for(div_index <- 0 until DCacheSetDiv){ 548 for (bank_index <- 0 until DCacheBanks) { 549 for (way_index <- 0 until DCacheWays) { 550 data_read_oh(div_index * DCacheBanks * DCacheWays + bank_index * DCacheWays + way_index) := data_banks(div_index)(bank_index)(way_index).io.r.en 551 } 552 } 553 } 554 XSPerfAccumulate("data_read_counter", PopCount(Cat(data_read_oh))) 555 556 // read result: expose banked read result 557 // TODO: clock gate 558 (0 until LoadPipelineWidth).map(i => { 559 // io.read_resp(i) := read_result(RegNext(bank_addrs(i)))(RegNext(OHToUInt(way_en(i)))) 560 val r_read_fire = RegNext(io.read(i).fire) 561 val r_div_addr = RegEnable(div_addrs(i), io.read(i).fire) 562 val r_bank_addr = RegEnable(bank_addrs(i), io.read(i).fire) 563 val r_way_addr = RegNext(OHToUInt(way_en(i))) 564 val rr_read_fire = RegNext(RegNext(io.read(i).fire)) 565 val rr_div_addr = RegEnable(RegEnable(div_addrs(i), io.read(i).fire), r_read_fire) 566 val rr_bank_addr = RegEnable(RegEnable(bank_addrs(i), io.read(i).fire), r_read_fire) 567 val rr_way_addr = RegEnable(RegEnable(OHToUInt(way_en(i)), io.read(i).fire), r_read_fire) 568 (0 until VLEN/DCacheSRAMRowBits).map( j =>{ 569 io.read_resp(i)(j) := read_result(r_div_addr)(r_bank_addr(j))(r_way_addr) 570 // error detection 571 // normal read ports 572 io.read_error_delayed(i)(j) := rr_read_fire && read_error_delayed_result(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) 573 }) 574 }) 575 576 // readline port 577 val readline_error_delayed = Wire(Vec(DCacheBanks, Bool())) 578 val readline_r_way_addr = RegEnable(OHToUInt(io.readline.bits.way_en), io.readline.valid) 579 val readline_rr_way_addr = RegEnable(readline_r_way_addr, RegNext(io.readline.valid)) 580 val readline_r_div_addr = RegEnable(line_div_addr, io.readline.valid) 581 val readline_rr_div_addr = RegEnable(readline_r_div_addr, RegNext(io.readline.valid)) 582 (0 until DCacheBanks).map(i => { 583 io.readline_resp(i) := read_result(readline_r_div_addr)(i)(readline_r_way_addr) 584 readline_error_delayed(i) := read_result(readline_rr_div_addr)(i)(readline_rr_way_addr).error_delayed 585 }) 586 io.readline_error_delayed := RegNext(RegNext(io.readline.fire)) && readline_error_delayed.asUInt.orR 587 588 // write data_banks & ecc_banks 589 for (div_index <- 0 until DCacheSetDiv) { 590 for (bank_index <- 0 until DCacheBanks) { 591 for (way_index <- 0 until DCacheWays) { 592 // data write 593 val wen_reg = write_bank_mask_reg(bank_index) && 594 write_valid_dup_reg(bank_index) && 595 write_div_addr_dup_reg(bank_index) === div_index.U && 596 write_wayen_dup_reg(bank_index)(way_index) 597 val write_ecc_reg = RegEnable(getECCFromEncWord(cacheParams.dataCode.encode(io.write.bits.data(bank_index))), io.write.valid) 598 val data_bank = data_banks(div_index)(bank_index)(way_index) 599 data_bank.io.w.en := wen_reg 600 data_bank.io.w.addr := write_set_addr_dup_reg(bank_index) 601 data_bank.io.w.data := asECCData(write_ecc_reg, write_data_reg(bank_index)) 602 } 603 } 604 } 605 606 io.cacheOp.resp.valid := false.B 607 io.cacheOp.resp.bits := DontCare 608 609 val tableName = "BankConflict" + p(XSCoreParamsKey).HartId.toString 610 val siteName = "BankedDataArray" + p(XSCoreParamsKey).HartId.toString 611 val bankConflictTable = ChiselDB.createTable(tableName, new BankConflictDB) 612 val bankConflictData = Wire(new BankConflictDB) 613 for (i <- 0 until LoadPipelineWidth) { 614 bankConflictData.set_index(i) := set_addrs(i) 615 bankConflictData.addr(i) := io.read(i).bits.addr 616 } 617 618 // FIXME: rr_bank_conflict(0)(1) no generalization 619 when(rr_bank_conflict(0)(1)) { 620 (0 until (VLEN/DCacheSRAMRowBits)).map(i => { 621 bankConflictData.bank_index(i) := bank_addrs(0)(i) 622 }) 623 bankConflictData.way_index := OHToUInt(way_en(0)) 624 bankConflictData.fake_rr_bank_conflict := set_addrs(0) === set_addrs(1) && div_addrs(0) === div_addrs(1) 625 }.otherwise { 626 (0 until (VLEN/DCacheSRAMRowBits)).map(i => { 627 bankConflictData.bank_index(i) := 0.U 628 }) 629 bankConflictData.way_index := 0.U 630 bankConflictData.fake_rr_bank_conflict := false.B 631 } 632 633 val isWriteBankConflictTable = Constantin.createRecord(s"isWriteBankConflictTable${p(XSCoreParamsKey).HartId}") 634 bankConflictTable.log( 635 data = bankConflictData, 636 en = isWriteBankConflictTable.orR && rr_bank_conflict(0)(1), 637 site = siteName, 638 clock = clock, 639 reset = reset 640 ) 641 642 (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x => 643 XSPerfAccumulate(s"data_array_fake_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y) && set_addrs(x)===set_addrs(y) && div_addrs(x) === div_addrs(y)) 644 )) 645 646 if (backendParams.debugEn){ 647 load_req_with_bank_conflict.map(dontTouch(_)) 648 dontTouch(read_result) 649 dontTouch(read_error_delayed_result) 650 } 651} 652 653// the smallest access unit is bank 654class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { 655 println(" DCacheType: BankedDataArray") 656 val ReduceReadlineConflict = false 657 658 io.write.ready := true.B 659 io.write_dup.foreach(_.ready := true.B) 660 661 val data_banks = List.fill(DCacheSetDiv)(List.tabulate(DCacheBanks)(i => Module(new DataSRAMBank(i)))) 662 data_banks.map(_.map(_.dump())) 663 664 val way_en = Wire(Vec(LoadPipelineWidth, io.read(0).bits.way_en.cloneType)) 665 val set_addrs = Wire(Vec(LoadPipelineWidth, UInt())) 666 val div_addrs = Wire(Vec(LoadPipelineWidth, UInt())) 667 val bank_addrs = Wire(Vec(LoadPipelineWidth, Vec(VLEN/DCacheSRAMRowBits, UInt()))) 668 val way_en_reg = Wire(Vec(LoadPipelineWidth, io.read(0).bits.way_en.cloneType)) 669 val set_addrs_reg = Wire(Vec(LoadPipelineWidth, UInt())) 670 671 val line_set_addr = addr_to_dcache_div_set(io.readline.bits.addr) 672 val line_div_addr = addr_to_dcache_div(io.readline.bits.addr) 673 val line_way_en = io.readline.bits.way_en 674 675 val write_bank_mask_reg = RegEnable(io.write.bits.wmask, io.write.valid) 676 val write_data_reg = RegEnable(io.write.bits.data, io.write.valid) 677 val write_valid_reg = RegNext(io.write.valid) 678 val write_valid_dup_reg = io.write_dup.map(x => RegNext(x.valid)) 679 val write_wayen_dup_reg = io.write_dup.map(x => RegEnable(x.bits.way_en, x.valid)) 680 val write_set_addr_dup_reg = io.write_dup.map(x => RegEnable(addr_to_dcache_div_set(x.bits.addr), x.valid)) 681 val write_div_addr_dup_reg = io.write_dup.map(x => RegEnable(addr_to_dcache_div(x.bits.addr), x.valid)) 682 683 // read data_banks and ecc_banks 684 // for single port SRAM, do not allow read and write in the same cycle 685 val rwhazard = RegNext(io.write.valid) 686 val rrhazard = false.B // io.readline.valid 687 (0 until LoadPipelineWidth).map(rport_index => { 688 div_addrs(rport_index) := addr_to_dcache_div(io.read(rport_index).bits.addr) 689 bank_addrs(rport_index)(0) := addr_to_dcache_bank(io.read(rport_index).bits.addr) 690 bank_addrs(rport_index)(1) := Mux(io.is128Req(rport_index), bank_addrs(rport_index)(0) + 1.U, bank_addrs(rport_index)(0)) 691 set_addrs(rport_index) := addr_to_dcache_div_set(io.read(rport_index).bits.addr) 692 set_addrs_reg(rport_index) := RegEnable(addr_to_dcache_div_set(io.read(rport_index).bits.addr), io.read(rport_index).valid) 693 694 // use way_en to select a way after data read out 695 assert(!(RegNext(io.read(rport_index).fire && PopCount(io.read(rport_index).bits.way_en) > 1.U))) 696 way_en(rport_index) := io.read(rport_index).bits.way_en 697 way_en_reg(rport_index) := RegEnable(io.read(rport_index).bits.way_en, io.read(rport_index).valid) 698 }) 699 700 // read each bank, get bank result 701 val rr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => Seq.tabulate(LoadPipelineWidth)(y => { 702 if (x == y) { 703 false.B 704 } else { 705 io.read(x).valid && io.read(y).valid && 706 div_addrs(x) === div_addrs(y) && 707 (io.read(x).bits.bankMask & io.read(y).bits.bankMask) =/= 0.U && 708 set_addrs(x) =/= set_addrs(y) 709 } 710 } 711 )) 712 713 val load_req_with_bank_conflict = rr_bank_conflict.map(_.reduce(_ || _)) 714 val load_req_valid = io.read.map(_.valid) 715 val load_req_lqIdx = io.read.map(_.bits.lqIdx) 716 val load_req_index = (0 until LoadPipelineWidth).map(_.asUInt) 717 718 val load_req_bank_conflict_selcet = selcetOldestPort(load_req_with_bank_conflict, load_req_lqIdx, load_req_index) 719 val load_req_bank_select_port = UIntToOH(load_req_bank_conflict_selcet._2).asBools 720 721 val rr_bank_conflict_oldest = (0 until LoadPipelineWidth).map(i => 722 !load_req_bank_select_port(i) && load_req_with_bank_conflict(i) 723 ) 724 725 val rrl_bank_conflict = Wire(Vec(LoadPipelineWidth, Bool())) 726 val rrl_bank_conflict_intend = Wire(Vec(LoadPipelineWidth, Bool())) 727 (0 until LoadPipelineWidth).foreach { i => 728 val judge = if (ReduceReadlineConflict) io.read(i).valid && (io.readline.bits.rmask & io.read(i).bits.bankMask) =/= 0.U && div_addrs(i) === line_div_addr 729 else io.read(i).valid && div_addrs(i)===line_div_addr 730 rrl_bank_conflict(i) := judge && io.readline.valid 731 rrl_bank_conflict_intend(i) := judge && io.readline_intend 732 } 733 val wr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => 734 io.read(x).valid && 735 write_valid_reg && 736 div_addrs(x) === write_div_addr_dup_reg.head && 737 (write_bank_mask_reg(bank_addrs(x)(0)) || write_bank_mask_reg(bank_addrs(x)(1)) && io.is128Req(x)) 738 ) 739 val wrl_bank_conflict = io.readline.valid && write_valid_reg && line_div_addr === write_div_addr_dup_reg.head 740 // ready 741 io.readline.ready := !(wrl_bank_conflict) 742 io.read.zipWithIndex.map{case(x, i) => x.ready := !(wr_bank_conflict(i) || rrhazard)} 743 744 val perf_multi_read = PopCount(io.read.map(_.valid)) >= 2.U 745 (0 until LoadPipelineWidth).foreach(i => { 746 // remove fake rr_bank_conflict situation in s2 747 val real_other_bank_conflict_reg = RegNext(wr_bank_conflict(i) || rrl_bank_conflict(i)) 748 val real_rr_bank_conflict_reg = RegNext(rr_bank_conflict_oldest(i)) 749 io.bank_conflict_slow(i) := real_other_bank_conflict_reg || real_rr_bank_conflict_reg 750 751 // get result in s1 752 io.disable_ld_fast_wakeup(i) := wr_bank_conflict(i) || rrl_bank_conflict_intend(i) || 753 (if (i == 0) 0.B else (0 until i).map(rr_bank_conflict(_)(i)).reduce(_ || _)) 754 }) 755 XSPerfAccumulate("data_array_multi_read", perf_multi_read) 756 (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x => 757 XSPerfAccumulate(s"data_array_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y)) 758 )) 759 (0 until LoadPipelineWidth).foreach(i => { 760 XSPerfAccumulate(s"data_array_rrl_bank_conflict_${i}", rrl_bank_conflict(i)) 761 XSPerfAccumulate(s"data_array_rw_bank_conflict_${i}", wr_bank_conflict(i)) 762 XSPerfAccumulate(s"data_array_read_${i}", io.read(i).valid) 763 }) 764 XSPerfAccumulate("data_array_access_total", PopCount(io.read.map(_.valid))) 765 XSPerfAccumulate("data_array_read_line", io.readline.valid) 766 XSPerfAccumulate("data_array_write", io.write.valid) 767 768 val bank_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, new L1BankedDataReadResult())))) 769 val bank_result_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, new L1BankedDataReadResult())))) 770 val read_bank_error_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) 771 772 val pseudo_data_toggle_mask = io.pseudo_error.bits.map { 773 case bank => 774 Mux(io.pseudo_error.valid && bank.valid, bank.mask, 0.U) 775 } 776 val readline_hit = io.readline.fire && 777 (io.readline.bits.rmask & VecInit(io.pseudo_error.bits.map(_.valid)).asUInt).orR 778 val readbank_hit = io.read.zip(bank_addrs.zip(io.is128Req)).zipWithIndex.map { 779 case ((read, (bank_addr, is128Req)), i) => 780 val error_bank0 = io.pseudo_error.bits(bank_addr(0)) 781 val error_bank1 = io.pseudo_error.bits(bank_addr(1)) 782 read.fire && (error_bank0.valid || error_bank1.valid && is128Req) && !io.bank_conflict_slow(i) 783 }.reduce(_|_) 784 io.pseudo_error.ready := RegNext(readline_hit || readbank_hit) 785 786 for (div_index <- 0 until DCacheSetDiv) { 787 for (bank_index <- 0 until DCacheBanks) { 788 // Set Addr & Read Way Mask 789 // 790 // Pipe 0 .... Pipe (n-1) 791 // + .... + 792 // | .... | 793 // +----+---------------+-----+ 794 // X X 795 // X +------+ Bank Addr Match 796 // +---------+----------+ 797 // | 798 // +--------+--------+ 799 // | Data Bank | 800 // +-----------------+ 801 val bank_addr_matchs = WireInit(VecInit(List.tabulate(LoadPipelineWidth)(i => { 802 io.read(i).valid && div_addrs(i) === div_index.U && (bank_addrs(i)(0) === bank_index.U || bank_addrs(i)(1) === bank_index.U && io.is128Req(i)) && 803 !rr_bank_conflict_oldest(i) 804 }))) 805 val readline_match = Wire(Bool()) 806 if (ReduceReadlineConflict) { 807 readline_match := io.readline.valid && io.readline.bits.rmask(bank_index) && line_div_addr === div_index.U 808 } else { 809 readline_match := io.readline.valid && line_div_addr === div_index.U 810 } 811 812 val bank_set_addr = Mux(readline_match, 813 line_set_addr, 814 PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => bank_addr_matchs(i) -> set_addrs(i))) 815 ) 816 val read_enable = bank_addr_matchs.asUInt.orR || readline_match 817 818 // read raw data 819 val data_bank = data_banks(div_index)(bank_index) 820 data_bank.io.r.en := read_enable 821 data_bank.io.r.addr := bank_set_addr 822 for (way_index <- 0 until DCacheWays) { 823 bank_result(div_index)(bank_index)(way_index).ecc := getECCFromEncWord(data_bank.io.r.data(way_index)) 824 bank_result(div_index)(bank_index)(way_index).raw_data := getDataFromEncWord(data_bank.io.r.data(way_index)) ^ pseudo_data_toggle_mask(bank_index) 825 826 if (EnableDataEcc) { 827 val ecc_data = bank_result(div_index)(bank_index)(way_index).asECCData() 828 val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_enable)) 829 bank_result(div_index)(bank_index)(way_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error 830 read_bank_error_delayed(div_index)(bank_index)(way_index) := bank_result(div_index)(bank_index)(way_index).error_delayed 831 } else { 832 bank_result(div_index)(bank_index)(way_index).error_delayed := false.B 833 read_bank_error_delayed(div_index)(bank_index)(way_index) := false.B 834 } 835 bank_result_delayed(div_index)(bank_index)(way_index) := RegEnable(bank_result(div_index)(bank_index)(way_index), RegNext(read_enable)) 836 } 837 } 838 } 839 840 val data_read_oh = WireInit(VecInit(Seq.fill(DCacheSetDiv)(0.U(XLEN.W)))) 841 for (div_index <- 0 until DCacheSetDiv){ 842 val temp = WireInit(VecInit(Seq.fill(DCacheBanks)(0.U(XLEN.W)))) 843 for (bank_index <- 0 until DCacheBanks) { 844 temp(bank_index) := PopCount(Fill(DCacheWays, data_banks(div_index)(bank_index).io.r.en.asUInt)) 845 } 846 data_read_oh(div_index) := temp.reduce(_ + _) 847 } 848 XSPerfAccumulate("data_read_counter", data_read_oh.foldLeft(0.U)(_ + _)) 849 850 (0 until LoadPipelineWidth).map(i => { 851 // 1 cycle after read fire(load s2) 852 val r_read_fire = RegNext(io.read(i).fire) 853 val r_div_addr = RegEnable(div_addrs(i), io.read(i).fire) 854 val r_bank_addr = RegEnable(bank_addrs(i), io.read(i).fire) 855 val r_way_addr = RegEnable(OHToUInt(way_en(i)), io.read(i).fire) 856 // 2 cycles after read fire(load s3) 857 val rr_read_fire = RegNext(r_read_fire) 858 val rr_div_addr = RegEnable(RegEnable(div_addrs(i), io.read(i).fire), r_read_fire) 859 val rr_bank_addr = RegEnable(RegEnable(bank_addrs(i), io.read(i).fire), r_read_fire) 860 val rr_way_addr = RegEnable(RegEnable(OHToUInt(way_en(i)), io.read(i).fire), r_read_fire) 861 (0 until VLEN/DCacheSRAMRowBits).map( j =>{ 862 io.read_resp(i)(j) := bank_result(r_div_addr)(r_bank_addr(j))(r_way_addr) 863 // error detection 864 io.read_error_delayed(i)(j) := rr_read_fire && read_bank_error_delayed(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) 865 }) 866 }) 867 868 // read result: expose banked read result 869 val readline_error_delayed = Wire(Vec(DCacheBanks, Bool())) 870 val readline_r_way_addr = RegEnable(OHToUInt(io.readline.bits.way_en), io.readline.valid) 871 val readline_rr_way_addr = RegEnable(readline_r_way_addr, RegNext(io.readline.valid)) 872 val readline_r_div_addr = RegEnable(line_div_addr, io.readline.valid) 873 val readline_rr_div_addr = RegEnable(readline_r_div_addr, RegNext(io.readline.valid)) 874 (0 until DCacheBanks).map(i => { 875 io.readline_resp(i) := bank_result(readline_r_div_addr)(i)(readline_r_way_addr) 876 readline_error_delayed(i) := bank_result(readline_rr_div_addr)(i)(readline_rr_way_addr).error_delayed 877 }) 878 io.readline_error_delayed := RegNext(RegNext(io.readline.fire)) && readline_error_delayed.asUInt.orR 879 880 // write data_banks & ecc_banks 881 for (div_index <- 0 until DCacheSetDiv) { 882 for (bank_index <- 0 until DCacheBanks) { 883 // data write 884 val wen_reg = write_bank_mask_reg(bank_index) && 885 write_valid_dup_reg(bank_index) && 886 write_div_addr_dup_reg(bank_index) === div_index.U && RegNext(io.write.valid) 887 val write_ecc_reg = RegEnable(getECCFromEncWord(cacheParams.dataCode.encode(io.write.bits.data(bank_index))), io.write.valid) 888 val data_bank = data_banks(div_index)(bank_index) 889 data_bank.io.w.en := wen_reg 890 data_bank.io.w.way_en := write_wayen_dup_reg(bank_index) 891 data_bank.io.w.addr := write_set_addr_dup_reg(bank_index) 892 data_bank.io.w.data := asECCData(write_ecc_reg, write_data_reg(bank_index)) 893 } 894 } 895 896 io.cacheOp.resp.valid := false.B 897 io.cacheOp.resp.bits := DontCare 898 899 val tableName = "BankConflict" + p(XSCoreParamsKey).HartId.toString 900 val siteName = "BankedDataArray" + p(XSCoreParamsKey).HartId.toString 901 val bankConflictTable = ChiselDB.createTable(tableName, new BankConflictDB) 902 val bankConflictData = Wire(new BankConflictDB) 903 for (i <- 0 until LoadPipelineWidth) { 904 bankConflictData.set_index(i) := set_addrs(i) 905 bankConflictData.addr(i) := io.read(i).bits.addr 906 } 907 908 // FIXME: rr_bank_conflict(0)(1) no generalization 909 when(rr_bank_conflict(0)(1)) { 910 (0 until (VLEN/DCacheSRAMRowBits)).map(i => { 911 bankConflictData.bank_index(i) := bank_addrs(0)(i) 912 }) 913 bankConflictData.way_index := OHToUInt(way_en(0)) 914 bankConflictData.fake_rr_bank_conflict := set_addrs(0) === set_addrs(1) && div_addrs(0) === div_addrs(1) 915 }.otherwise { 916 (0 until (VLEN/DCacheSRAMRowBits)).map(i => { 917 bankConflictData.bank_index(i) := 0.U 918 }) 919 bankConflictData.way_index := 0.U 920 bankConflictData.fake_rr_bank_conflict := false.B 921 } 922 923 val isWriteBankConflictTable = Constantin.createRecord(s"isWriteBankConflictTable${p(XSCoreParamsKey).HartId}") 924 bankConflictTable.log( 925 data = bankConflictData, 926 en = isWriteBankConflictTable.orR && rr_bank_conflict(0)(1), 927 site = siteName, 928 clock = clock, 929 reset = reset 930 ) 931 932 (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x => 933 XSPerfAccumulate(s"data_array_fake_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y) && set_addrs(x) === set_addrs(y) && div_addrs(x) === div_addrs(y)) 934 )) 935 936 if (backendParams.debugEn){ 937 load_req_with_bank_conflict.map(dontTouch(_)) 938 dontTouch(bank_result) 939 dontTouch(read_bank_error_delayed) 940 } 941} 942