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