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