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