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