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