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