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