xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/data/BankedDataArray.scala (revision cdbff57cf647e018be44a8306fc52228004168b3)
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 = 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("data_sram_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("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  val line_way_en = io.readline.bits.way_en
349
350  val write_bank_mask_reg = RegNext(io.write.bits.wmask)
351  val write_data_reg = RegNext(io.write.bits.data)
352  val write_valid_reg = RegNext(io.write.valid)
353  val write_valid_dup_reg = io.write_dup.map(x => RegNext(x.valid))
354  val write_wayen_dup_reg = io.write_dup.map(x => RegNext(x.bits.way_en))
355  val write_set_addr_dup_reg = io.write_dup.map(x => RegNext(addr_to_dcache_div_set(x.bits.addr)))
356  val write_div_addr_dup_reg = io.write_dup.map(x => RegNext(addr_to_dcache_div(x.bits.addr)))
357
358  // read data_banks and ecc_banks
359  // for single port SRAM, do not allow read and write in the same cycle
360  val rrhazard = false.B // io.readline.valid
361  (0 until LoadPipelineWidth).map(rport_index => {
362    div_addrs(rport_index) := addr_to_dcache_div(io.read(rport_index).bits.addr)
363    set_addrs(rport_index) := addr_to_dcache_div_set(io.read(rport_index).bits.addr)
364    bank_addrs(rport_index)(0) := addr_to_dcache_bank(io.read(rport_index).bits.addr)
365    bank_addrs(rport_index)(1) := bank_addrs(rport_index)(0) + 1.U
366
367    // use way_en to select a way after data read out
368    assert(!(RegNext(io.read(rport_index).fire() && PopCount(io.read(rport_index).bits.way_en) > 1.U)))
369    way_en(rport_index) := io.read(rport_index).bits.way_en
370  })
371
372  // read conflict
373  val rr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => Seq.tabulate(LoadPipelineWidth)(y =>
374    io.read(x).valid && io.read(y).valid &&
375    div_addrs(x) === div_addrs(y) &&
376    (io.read(x).bits.bankMask & io.read(y).bits.bankMask) =/= 0.U &&
377    io.read(x).bits.way_en === io.read(y).bits.way_en &&
378    set_addrs(x) =/= set_addrs(y)
379  ))
380  val rrl_bank_conflict = Wire(Vec(LoadPipelineWidth, Bool()))
381  val rrl_bank_conflict_intend = Wire(Vec(LoadPipelineWidth, Bool()))
382  (0 until LoadPipelineWidth).foreach { i =>
383    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) && io.readline.bits.way_en === way_en(i) && line_set_addr =/= set_addrs(i)
384                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)
385    rrl_bank_conflict(i) := judge && io.readline.valid
386    rrl_bank_conflict_intend(i) := judge && io.readline_intend
387  }
388  val wr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x =>
389    io.read(x).valid && write_valid_reg &&
390    div_addrs(x) === write_div_addr_dup_reg.head &&
391    way_en(x) === write_wayen_dup_reg.head &&
392    (write_bank_mask_reg(bank_addrs(x)(0)) || write_bank_mask_reg(bank_addrs(x)(1)) && io.is128Req(x))
393  )
394  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
395  // ready
396  io.readline.ready := !(wrl_bank_conflict)
397  io.read.zipWithIndex.map { case (x, i) => x.ready := !(wr_bank_conflict(i) || rrhazard) }
398
399  val perf_multi_read = PopCount(io.read.map(_.valid)) >= 2.U
400  val bank_conflict_fast = Wire(Vec(LoadPipelineWidth, Bool()))
401  (0 until LoadPipelineWidth).foreach(i => {
402    bank_conflict_fast(i) := wr_bank_conflict(i) || rrl_bank_conflict(i) ||
403      (if (i == 0) 0.B else (0 until i).map(rr_bank_conflict(_)(i)).reduce(_ || _))
404    io.bank_conflict_slow(i) := RegNext(bank_conflict_fast(i))
405    io.disable_ld_fast_wakeup(i) := wr_bank_conflict(i) || rrl_bank_conflict_intend(i) ||
406      (if (i == 0) 0.B else (0 until i).map(rr_bank_conflict(_)(i)).reduce(_ || _))
407  })
408  XSPerfAccumulate("data_array_multi_read", perf_multi_read)
409  (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x =>
410    XSPerfAccumulate(s"data_array_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y))
411  ))
412  (0 until LoadPipelineWidth).foreach(i => {
413    XSPerfAccumulate(s"data_array_rrl_bank_conflict_${i}", rrl_bank_conflict(i))
414    XSPerfAccumulate(s"data_array_rw_bank_conflict_${i}", wr_bank_conflict(i))
415    XSPerfAccumulate(s"data_array_read_${i}", io.read(i).valid)
416  })
417  XSPerfAccumulate("data_array_access_total", PopCount(io.read.map(_.valid)))
418  XSPerfAccumulate("data_array_read_line", io.readline.valid)
419  XSPerfAccumulate("data_array_write", io.write.valid)
420
421  val read_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays,new L1BankedDataReadResult()))))
422  val read_error_delayed_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool()))))
423  dontTouch(read_result)
424  dontTouch(read_error_delayed_result)
425  for (div_index <- 0 until DCacheSetDiv){
426    for (bank_index <- 0 until DCacheBanks) {
427      for (way_index <- 0 until DCacheWays) {
428        //     Set Addr & Read Way Mask
429        //
430        //    Pipe 0   ....  Pipe (n-1)
431        //      +      ....     +
432        //      |      ....     |
433        // +----+---------------+-----+
434        //  X                        X
435        //   X                      +------+ Bank Addr Match
436        //    +---------+----------+
437        //              |
438        //     +--------+--------+
439        //     |    Data Bank    |
440        //     +-----------------+
441        val loadpipe_en = WireInit(VecInit(List.tabulate(LoadPipelineWidth)(i => {
442          io.read(i).valid && div_addrs(i) === div_index.U && (bank_addrs(i)(0) === bank_index.U || bank_addrs(i)(1) === bank_index.U && io.is128Req(i)) && way_en(i)(way_index)
443        })))
444        val readline_en = Wire(Bool())
445        if (ReduceReadlineConflict) {
446          readline_en := io.readline.valid && io.readline.bits.rmask(bank_index) && io.readline.bits.way_en(way_index) && div_index.U === line_div_addr
447        } else {
448          readline_en := io.readline.valid && io.readline.bits.way_en(way_index) && div_index.U === line_div_addr
449        }
450        val sram_set_addr = Mux(readline_en,
451          addr_to_dcache_div_set(io.readline.bits.addr),
452          PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => loadpipe_en(i) -> set_addrs(i)))
453        )
454        val read_en = loadpipe_en.asUInt.orR || readline_en
455        // read raw data
456        val data_bank = data_banks(div_index)(bank_index)(way_index)
457        data_bank.io.r.en := read_en
458        data_bank.io.r.addr := sram_set_addr
459        val ecc_bank = ecc_banks(div_index)(bank_index)(way_index)
460        ecc_bank.io.r.req.valid := read_en
461        ecc_bank.io.r.req.bits.apply(setIdx = sram_set_addr)
462
463        read_result(div_index)(bank_index)(way_index).raw_data := data_bank.io.r.data
464        read_result(div_index)(bank_index)(way_index).ecc := ecc_bank.io.r.resp.data(0)
465
466        // use ECC to check error
467        val ecc_data = read_result(div_index)(bank_index)(way_index).asECCData()
468        val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_en))
469        read_result(div_index)(bank_index)(way_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error
470        read_error_delayed_result(div_index)(bank_index)(way_index) := read_result(div_index)(bank_index)(way_index).error_delayed
471      }
472    }
473  }
474
475  // read result: expose banked read result
476  val read_result_delayed = RegNext(read_result)
477  (0 until LoadPipelineWidth).map(i => {
478    // io.read_resp(i) := read_result(RegNext(bank_addrs(i)))(RegNext(OHToUInt(way_en(i))))
479    val rr_read_fire = RegNext(RegNext(io.read(i).fire))
480    val rr_div_addr = RegNext(RegNext(div_addrs(i)))
481    val rr_bank_addr = RegNext(RegNext(bank_addrs(i)))
482    val rr_way_addr = RegNext(RegNext(OHToUInt(way_en(i))))
483    (0 until VLEN/DCacheSRAMRowBits).map( j =>{
484      io.read_resp_delayed(i)(j) := read_result_delayed(rr_div_addr)(rr_bank_addr(j))(rr_way_addr)
485      // error detection
486      // normal read ports
487      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))
488    })
489  })
490
491  // readline port
492  (0 until DCacheBanks).map(i => {
493    io.readline_resp(i) := read_result(RegNext(line_div_addr))(i)(RegNext(OHToUInt(io.readline.bits.way_en)))
494  })
495  io.readline_error_delayed := RegNext(RegNext(io.readline.fire())) &&
496    VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).error_delayed)).asUInt().orR
497
498  // write data_banks & ecc_banks
499  for (div_index <- 0 until DCacheSetDiv) {
500    for (bank_index <- 0 until DCacheBanks) {
501      for (way_index <- 0 until DCacheWays) {
502        // data write
503        val wen_reg = write_bank_mask_reg(bank_index) &&
504          write_valid_dup_reg(bank_index) &&
505          write_div_addr_dup_reg(bank_index) === div_index.U &&
506          write_wayen_dup_reg(bank_index)(way_index)
507        val data_bank = data_banks(div_index)(bank_index)(way_index)
508        data_bank.io.w.en := wen_reg
509
510        data_bank.io.w.addr := write_set_addr_dup_reg(bank_index)
511        data_bank.io.w.data := write_data_reg(bank_index)
512        // ecc write
513        val ecc_bank = ecc_banks(div_index)(bank_index)(way_index)
514        ecc_bank.io.w.req.valid := wen_reg
515        ecc_bank.io.w.req.bits.apply(
516          setIdx = write_set_addr_dup_reg(bank_index),
517          data = RegNext(getECCFromEncWord(cacheParams.dataCode.encode((io.write.bits.data(bank_index))))),
518          waymask = 1.U
519        )
520        when(ecc_bank.io.w.req.valid) {
521          XSDebug("write in ecc sram: bank %x set %x data %x waymask %x\n",
522            bank_index.U,
523            addr_to_dcache_div_set(io.write.bits.addr),
524            getECCFromEncWord(cacheParams.dataCode.encode((io.write.bits.data(bank_index)))),
525            io.write.bits.way_en
526          );
527        }
528      }
529    }
530  }
531
532  require(nWays <= 32)
533  io.cacheOp.resp.bits := DontCare
534  val cacheOpShouldResp = WireInit(false.B)
535  val eccReadResult = Wire(Vec(DCacheBanks, UInt(eccBits.W)))
536  // DCacheDupNum is 16
537  // vec: the dupIdx for every bank and every group
538  val rdata_dup_vec = Seq(0,0,1,1,2,2,3,3)
539  val rdataEcc_dup_vec = Seq(4,4,5,5,6,6,7,7)
540  val wdata_dup_vec = Seq(8,8,9,9,10,10,11,11)
541  val wdataEcc_dup_vec = Seq(12,12,13,13,14,14,15,15)
542  val cacheOpDivAddr = set_to_dcache_div(io.cacheOp.req.bits.index)
543  val cacheOpSetAddr = set_to_dcache_div_set(io.cacheOp.req.bits.index)
544  val cacheOpWayNum = io.cacheOp.req.bits.wayNum(4, 0)
545  rdata_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
546    for (divIdx <- 0 until DCacheSetDiv){
547      for (wayIdx <- 0 until DCacheWays) {
548        when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isReadData(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
549          val data_bank = data_banks(divIdx)(bankIdx)(wayIdx)
550          data_bank.io.r.en := UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))(wayIdx) && cacheOpDivAddr === divIdx.U
551          data_bank.io.r.addr := cacheOpSetAddr
552          cacheOpShouldResp := true.B
553        }
554      }
555    }
556  }
557  rdataEcc_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.isReadDataECC(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
561          val ecc_bank = ecc_banks(divIdx)(bankIdx)(wayIdx)
562          ecc_bank.io.r.req.valid := true.B
563          ecc_bank.io.r.req.bits.setIdx := cacheOpSetAddr
564          cacheOpShouldResp := true.B
565        }
566      }
567    }
568  }
569  wdata_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.isWriteData(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
573          val data_bank = data_banks(divIdx)(bankIdx)(wayIdx)
574          data_bank.io.w.en := UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))(wayIdx) && cacheOpDivAddr === divIdx.U
575          data_bank.io.w.addr := cacheOpSetAddr
576          data_bank.io.w.data := io.cacheOp.req.bits.write_data_vec(bankIdx)
577          cacheOpShouldResp := true.B
578        }
579      }
580    }
581  }
582  wdataEcc_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
583    for (divIdx <- 0 until DCacheSetDiv) {
584      for (wayIdx <- 0 until DCacheWays) {
585        when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isWriteDataECC(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
586          val ecc_bank = ecc_banks(divIdx)(bankIdx)(wayIdx)
587          ecc_bank.io.w.req.valid := UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))(wayIdx) && cacheOpDivAddr === divIdx.U
588          ecc_bank.io.w.req.bits.apply(
589            setIdx = cacheOpSetAddr,
590            data = io.cacheOp.req.bits.write_data_ecc,
591            waymask = 1.U
592          )
593          cacheOpShouldResp := true.B
594        }
595      }
596    }
597  }
598
599  io.cacheOp.resp.valid := RegNext(io.cacheOp.req.valid && cacheOpShouldResp)
600  for (bank_index <- 0 until DCacheBanks) {
601    io.cacheOp.resp.bits.read_data_vec(bank_index) := read_result(RegNext(cacheOpDivAddr))(bank_index)(RegNext(cacheOpWayNum)).raw_data
602    eccReadResult(bank_index) := read_result(RegNext(cacheOpDivAddr))(bank_index)(RegNext(cacheOpWayNum)).ecc
603  }
604
605  io.cacheOp.resp.bits.read_data_ecc := Mux(io.cacheOp.resp.valid,
606    eccReadResult(RegNext(io.cacheOp.req.bits.bank_num)),
607    0.U
608  )
609
610  val tableName =  "BankConflict" + p(XSCoreParamsKey).HartId.toString
611  val siteName = "BankedDataArray" + p(XSCoreParamsKey).HartId.toString
612  val bankConflictTable = ChiselDB.createTable(tableName, new BankConflictDB)
613  val bankConflictData = Wire(new BankConflictDB)
614  for (i <- 0 until LoadPipelineWidth) {
615    bankConflictData.set_index(i) := set_addrs(i)
616    bankConflictData.addr(i) := io.read(i).bits.addr
617  }
618
619  // FIXME: rr_bank_conflict(0)(1) no generalization
620  when(rr_bank_conflict(0)(1)) {
621    (0 until (VLEN/DCacheSRAMRowBits)).map(i => {
622      bankConflictData.bank_index(i) := bank_addrs(0)(i)
623    })
624    bankConflictData.way_index  := OHToUInt(way_en(0))
625    bankConflictData.fake_rr_bank_conflict := set_addrs(0) === set_addrs(1) && div_addrs(0) === div_addrs(1)
626  }.otherwise {
627    (0 until (VLEN/DCacheSRAMRowBits)).map(i => {
628      bankConflictData.bank_index(i) := 0.U
629    })
630    bankConflictData.way_index := 0.U
631    bankConflictData.fake_rr_bank_conflict := false.B
632  }
633
634  val isWriteBankConflictTable = WireInit(Constantin.createRecord("isWriteBankConflictTable" + p(XSCoreParamsKey).HartId.toString))
635  bankConflictTable.log(
636    data = bankConflictData,
637    en = isWriteBankConflictTable.orR && rr_bank_conflict(0)(1),
638    site = siteName,
639    clock = clock,
640    reset = reset
641  )
642
643  (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x =>
644    XSPerfAccumulate(s"data_array_fake_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y) && set_addrs(x)===set_addrs(y))
645  ))
646
647}
648
649// the smallest access unit is bank
650class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray {
651  println("  DCacheType: BankedDataArray")
652  val ReduceReadlineConflict = false
653
654  io.write.ready := true.B
655  io.write_dup.foreach(_.ready := true.B)
656
657  val data_banks = List.fill(DCacheSetDiv)(List.tabulate(DCacheBanks)(i => Module(new DataSRAMBank(i))))
658  val ecc_banks = List.fill(DCacheSetDiv)(List.fill(DCacheBanks)(Module(new SRAMTemplate(
659    Bits(eccBits.W),
660    set = DCacheSets / DCacheSetDiv,
661    way = DCacheWays,
662    shouldReset = false,
663    holdRead = false,
664    singlePort = true
665  ))))
666
667  data_banks.map(_.map(_.dump()))
668
669  val way_en = Wire(Vec(LoadPipelineWidth, io.read(0).bits.way_en.cloneType))
670  val set_addrs = Wire(Vec(LoadPipelineWidth, UInt()))
671  val div_addrs = Wire(Vec(LoadPipelineWidth, UInt()))
672  val bank_addrs = Wire(Vec(LoadPipelineWidth, Vec(VLEN/DCacheSRAMRowBits, UInt())))
673  val way_en_reg = Wire(Vec(LoadPipelineWidth, io.read(0).bits.way_en.cloneType))
674  val set_addrs_reg = Wire(Vec(LoadPipelineWidth, UInt()))
675
676  val line_set_addr = addr_to_dcache_div_set(io.readline.bits.addr)
677  val line_div_addr = addr_to_dcache_div(io.readline.bits.addr)
678  val line_way_en = io.readline.bits.way_en
679
680  val write_bank_mask_reg = RegNext(io.write.bits.wmask)
681  val write_data_reg = RegNext(io.write.bits.data)
682  val write_valid_reg = RegNext(io.write.valid)
683  val write_valid_dup_reg = io.write_dup.map(x => RegNext(x.valid))
684  val write_wayen_dup_reg = io.write_dup.map(x => RegNext(x.bits.way_en))
685  val write_set_addr_dup_reg = io.write_dup.map(x => RegNext(addr_to_dcache_div_set(x.bits.addr)))
686  val write_div_addr_dup_reg = io.write_dup.map(x => RegNext(addr_to_dcache_div(x.bits.addr)))
687
688  // read data_banks and ecc_banks
689  // for single port SRAM, do not allow read and write in the same cycle
690  val rwhazard = RegNext(io.write.valid)
691  val rrhazard = false.B // io.readline.valid
692  (0 until LoadPipelineWidth).map(rport_index => {
693    div_addrs(rport_index) := addr_to_dcache_div(io.read(rport_index).bits.addr)
694    bank_addrs(rport_index)(0) := addr_to_dcache_bank(io.read(rport_index).bits.addr)
695    bank_addrs(rport_index)(1) := Mux(io.is128Req(rport_index), bank_addrs(rport_index)(0) + 1.U, DCacheBanks.asUInt)
696    set_addrs(rport_index) := addr_to_dcache_div_set(io.read(rport_index).bits.addr)
697    set_addrs_reg(rport_index) := RegNext(addr_to_dcache_div_set(io.read(rport_index).bits.addr))
698
699    // use way_en to select a way after data read out
700    assert(!(RegNext(io.read(rport_index).fire() && PopCount(io.read(rport_index).bits.way_en) > 1.U)))
701    way_en(rport_index) := io.read(rport_index).bits.way_en
702    way_en_reg(rport_index) := RegNext(io.read(rport_index).bits.way_en)
703  })
704
705  // read each bank, get bank result
706  val rr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x => Seq.tabulate(LoadPipelineWidth)(y =>
707    io.read(x).valid && io.read(y).valid &&
708    div_addrs(x) === div_addrs(y) &&
709    (io.read(x).bits.bankMask & io.read(y).bits.bankMask) =/= 0.U
710  ))
711  val rrl_bank_conflict = Wire(Vec(LoadPipelineWidth, Bool()))
712  val rrl_bank_conflict_intend = Wire(Vec(LoadPipelineWidth, Bool()))
713  (0 until LoadPipelineWidth).foreach { i =>
714    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
715                else io.read(i).valid && div_addrs(i)===line_div_addr
716    rrl_bank_conflict(i) := judge && io.readline.valid
717    rrl_bank_conflict_intend(i) := judge && io.readline_intend
718  }
719  val wr_bank_conflict = Seq.tabulate(LoadPipelineWidth)(x =>
720    io.read(x).valid &&
721    write_valid_reg &&
722    div_addrs(x) === write_div_addr_dup_reg.head &&
723    (write_bank_mask_reg(bank_addrs(x)(0)) || write_bank_mask_reg(bank_addrs(x)(1)) && io.is128Req(x))
724  )
725  val wrl_bank_conflict = io.readline.valid && write_valid_reg && line_div_addr === write_div_addr_dup_reg.head
726  // ready
727  io.readline.ready := !(wrl_bank_conflict)
728  io.read.zipWithIndex.map{case(x, i) => x.ready := !(wr_bank_conflict(i) || rrhazard)}
729
730  val perf_multi_read = PopCount(io.read.map(_.valid)) >= 2.U
731  (0 until LoadPipelineWidth).foreach(i => {
732    // remove fake rr_bank_conflict situation in s2
733    val real_other_bank_conflict_reg = RegNext(wr_bank_conflict(i) || rrl_bank_conflict(i))
734    val real_rr_bank_conflict_reg = (if (i == 0) 0.B else (0 until i).map{ j =>
735      RegNext(rr_bank_conflict(j)(i)) &&
736      (way_en_reg(j) =/= way_en_reg(i) || set_addrs_reg(j) =/= set_addrs_reg(i))
737    }.reduce(_ || _))
738    io.bank_conflict_slow(i) := real_other_bank_conflict_reg || real_rr_bank_conflict_reg
739
740    // get result in s1
741    io.disable_ld_fast_wakeup(i) := wr_bank_conflict(i) || rrl_bank_conflict_intend(i) ||
742      (if (i == 0) 0.B else (0 until i).map(rr_bank_conflict(_)(i)).reduce(_ || _))
743  })
744  XSPerfAccumulate("data_array_multi_read", perf_multi_read)
745  (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x =>
746    XSPerfAccumulate(s"data_array_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y))
747  ))
748  (0 until LoadPipelineWidth).foreach(i => {
749    XSPerfAccumulate(s"data_array_rrl_bank_conflict_${i}", rrl_bank_conflict(i))
750    XSPerfAccumulate(s"data_array_rw_bank_conflict_${i}", wr_bank_conflict(i))
751    XSPerfAccumulate(s"data_array_read_${i}", io.read(i).valid)
752  })
753  XSPerfAccumulate("data_array_access_total", PopCount(io.read.map(_.valid)))
754  XSPerfAccumulate("data_array_read_line", io.readline.valid)
755  XSPerfAccumulate("data_array_write", io.write.valid)
756
757  val bank_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, new L1BankedDataReadResult())))
758  val ecc_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, UInt(eccBits.W)))))
759  val read_bank_error_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Bool())))
760  dontTouch(bank_result)
761  dontTouch(read_bank_error_delayed)
762  for (div_index <- 0 until DCacheSetDiv) {
763    for (bank_index <- 0 until DCacheBanks) {
764      //     Set Addr & Read Way Mask
765      //
766      //    Pipe 0   ....  Pipe (n-1)
767      //      +      ....     +
768      //      |      ....     |
769      // +----+---------------+-----+
770      //  X                        X
771      //   X                      +------+ Bank Addr Match
772      //    +---------+----------+
773      //              |
774      //     +--------+--------+
775      //     |    Data Bank    |
776      //     +-----------------+
777      val bank_addr_matchs = WireInit(VecInit(List.tabulate(LoadPipelineWidth)(i => {
778        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))
779      })))
780      val readline_match = Wire(Bool())
781      if (ReduceReadlineConflict) {
782        readline_match := io.readline.valid && io.readline.bits.rmask(bank_index) && line_div_addr === div_index.U
783      } else {
784        readline_match := io.readline.valid && line_div_addr === div_index.U
785      }
786      val bank_way_en = Mux(readline_match,
787        io.readline.bits.way_en,
788        PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => bank_addr_matchs(i) -> way_en(i)))
789      )
790      // it is too long of bank_way_en's caculation, so bank_way_en_reg can not be caculated by RegNext(bank_way_en)
791      val bank_way_en_reg = Mux(RegNext(readline_match),
792        RegNext(io.readline.bits.way_en),
793        PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => RegNext(bank_addr_matchs(i)) -> RegNext(way_en(i))))
794      )
795      val bank_set_addr = Mux(readline_match,
796        line_set_addr,
797        PriorityMux(Seq.tabulate(LoadPipelineWidth)(i => bank_addr_matchs(i) -> set_addrs(i)))
798      )
799
800      val read_enable = bank_addr_matchs.asUInt.orR || readline_match
801
802      // read raw data
803      val data_bank = data_banks(div_index)(bank_index)
804      data_bank.io.r.en := read_enable
805      data_bank.io.r.way_en := bank_way_en
806      data_bank.io.r.addr := bank_set_addr
807      bank_result(div_index)(bank_index).raw_data := data_bank.io.r.data
808
809      // read ECC
810      val ecc_bank = ecc_banks(div_index)(bank_index)
811      ecc_bank.io.r.req.valid := read_enable
812      ecc_bank.io.r.req.bits.apply(setIdx = bank_set_addr)
813      ecc_result(div_index)(bank_index) := ecc_bank.io.r.resp.data
814      bank_result(div_index)(bank_index).ecc := Mux1H(bank_way_en_reg, ecc_bank.io.r.resp.data)
815
816      // use ECC to check error
817      val ecc_data = bank_result(div_index)(bank_index).asECCData()
818      val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_enable))
819      bank_result(div_index)(bank_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error
820      read_bank_error_delayed(div_index)(bank_index) := bank_result(div_index)(bank_index).error_delayed
821    }
822  }
823
824  val bank_result_delayed = RegNext(bank_result)
825  (0 until LoadPipelineWidth).map(i => {
826    val rr_read_fire = RegNext(RegNext(io.read(i).fire))
827    val rr_div_addr = RegNext(RegNext(div_addrs(i)))
828    val rr_bank_addr = RegNext(RegNext(bank_addrs(i)))
829    val rr_way_addr = RegNext(RegNext(OHToUInt(way_en(i))))
830    (0 until VLEN/DCacheSRAMRowBits).map( j =>{
831      io.read_resp_delayed(i)(j) := bank_result_delayed(rr_div_addr)(rr_bank_addr(j))
832      // error detection
833      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))
834    })
835  })
836
837  // read result: expose banked read result
838  io.readline_resp := bank_result(RegNext(line_div_addr))
839  io.readline_error_delayed := RegNext(RegNext(io.readline.fire())) &&
840    VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).error_delayed)).asUInt().orR
841
842  // write data_banks & ecc_banks
843  for (div_index <- 0 until DCacheSetDiv) {
844    for (bank_index <- 0 until DCacheBanks) {
845      // data write
846      val wen_reg = write_bank_mask_reg(bank_index) &&
847        write_valid_dup_reg(bank_index) &&
848        write_div_addr_dup_reg(bank_index) === div_index.U
849      val data_bank = data_banks(div_index)(bank_index)
850      data_bank.io.w.en := wen_reg
851      data_bank.io.w.way_en := write_wayen_dup_reg(bank_index)
852      data_bank.io.w.addr := write_set_addr_dup_reg(bank_index)
853      data_bank.io.w.data := write_data_reg(bank_index)
854
855      // ecc write
856      val ecc_bank = ecc_banks(div_index)(bank_index)
857      ecc_bank.io.w.req.valid := wen_reg
858      ecc_bank.io.w.req.bits.apply(
859        setIdx = write_set_addr_dup_reg(bank_index),
860        data = RegNext(getECCFromEncWord(cacheParams.dataCode.encode((io.write.bits.data(bank_index))))),
861        waymask = write_wayen_dup_reg(bank_index)
862      )
863      when(ecc_bank.io.w.req.valid) {
864        XSDebug("write in ecc sram: bank %x set %x data %x waymask %x\n",
865          bank_index.U,
866          addr_to_dcache_div_set(io.write.bits.addr),
867          getECCFromEncWord(cacheParams.dataCode.encode((io.write.bits.data(bank_index)))),
868          io.write.bits.way_en
869        );
870      }
871    }
872  }
873
874  // deal with customized cache op
875  require(nWays <= 32)
876  io.cacheOp.resp.bits := DontCare
877  val cacheOpShouldResp = WireInit(false.B)
878  val eccReadResult = Wire(Vec(DCacheBanks, UInt(eccBits.W)))
879  // DCacheDupNum is 16
880  // vec: the dupIdx for every bank and every group
881  val rdata_dup_vec = Seq(0, 0, 1, 1, 2, 2, 3, 3)
882  val rdataEcc_dup_vec = Seq(4, 4, 5, 5, 6, 6, 7, 7)
883  val wdata_dup_vec = Seq(8, 8, 9, 9, 10, 10, 11, 11)
884  val wdataEcc_dup_vec = Seq(12, 12, 13, 13, 14, 14, 15, 15)
885  val cacheOpDivAddr = set_to_dcache_div(io.cacheOp.req.bits.index)
886  val cacheOpSetAddr = set_to_dcache_div_set(io.cacheOp.req.bits.index)
887  val cacheOpWayMask = UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))
888  rdata_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
889    for (divIdx <- 0 until DCacheSetDiv) {
890      when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isReadData(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
891        val data_bank = data_banks(divIdx)(bankIdx)
892        data_bank.io.r.en := true.B
893        data_bank.io.r.way_en := cacheOpWayMask
894        data_bank.io.r.addr := cacheOpSetAddr
895        cacheOpShouldResp := true.B
896      }
897    }
898  }
899  rdataEcc_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
900    for (divIdx <- 0 until DCacheSetDiv) {
901      when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isReadDataECC(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
902        val ecc_bank = ecc_banks(divIdx)(bankIdx)
903        ecc_bank.io.r.req.valid := true.B
904        ecc_bank.io.r.req.bits.setIdx := cacheOpSetAddr
905        cacheOpShouldResp := true.B
906      }
907    }
908  }
909  wdata_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
910    for (divIdx <- 0 until DCacheSetDiv) {
911      when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isWriteData(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
912        val data_bank = data_banks(divIdx)(bankIdx)
913        data_bank.io.w.en := cacheOpDivAddr === divIdx.U
914        data_bank.io.w.way_en := cacheOpWayMask
915        data_bank.io.w.addr := cacheOpSetAddr
916        data_bank.io.w.data := io.cacheOp.req.bits.write_data_vec(bankIdx)
917        cacheOpShouldResp := true.B
918      }
919    }
920  }
921  wdataEcc_dup_vec.zipWithIndex.map{ case(dupIdx, bankIdx) =>
922    for (divIdx <- 0 until DCacheSetDiv) {
923      when(io.cacheOp_req_dup(dupIdx).valid && CacheInstrucion.isWriteDataECC(io.cacheOp_req_bits_opCode_dup(dupIdx))) {
924        val ecc_bank = ecc_banks(divIdx)(bankIdx)
925        ecc_bank.io.w.req.valid := cacheOpDivAddr === divIdx.U
926        ecc_bank.io.w.req.bits.apply(
927          setIdx = cacheOpSetAddr,
928          data = io.cacheOp.req.bits.write_data_ecc,
929          waymask = cacheOpWayMask
930        )
931        cacheOpShouldResp := true.B
932      }
933    }
934  }
935
936  io.cacheOp.resp.valid := RegNext(io.cacheOp.req.valid && cacheOpShouldResp)
937  for (bank_index <- 0 until DCacheBanks) {
938    io.cacheOp.resp.bits.read_data_vec(bank_index) := bank_result(RegNext(cacheOpDivAddr))(bank_index).raw_data
939    eccReadResult(bank_index) := Mux1H(RegNext(cacheOpWayMask), ecc_result(RegNext(cacheOpDivAddr))(bank_index))
940  }
941
942  io.cacheOp.resp.bits.read_data_ecc := Mux(io.cacheOp.resp.valid,
943    eccReadResult(RegNext(io.cacheOp.req.bits.bank_num)),
944    0.U
945  )
946
947  val tableName = "BankConflict" + p(XSCoreParamsKey).HartId.toString
948  val siteName = "BankedDataArray" + p(XSCoreParamsKey).HartId.toString
949  val bankConflictTable = ChiselDB.createTable(tableName, new BankConflictDB)
950  val bankConflictData = Wire(new BankConflictDB)
951  for (i <- 0 until LoadPipelineWidth) {
952    bankConflictData.set_index(i) := set_addrs(i)
953    bankConflictData.addr(i) := io.read(i).bits.addr
954  }
955
956  // FIXME: rr_bank_conflict(0)(1) no generalization
957  when(rr_bank_conflict(0)(1)) {
958    (0 until (VLEN/DCacheSRAMRowBits)).map(i => {
959      bankConflictData.bank_index(i) := bank_addrs(0)(i)
960    })
961    bankConflictData.way_index := OHToUInt(way_en(0))
962    bankConflictData.fake_rr_bank_conflict := set_addrs(0) === set_addrs(1) && div_addrs(0) === div_addrs(1)
963  }.otherwise {
964    (0 until (VLEN/DCacheSRAMRowBits)).map(i => {
965      bankConflictData.bank_index(i) := 0.U
966    })
967    bankConflictData.way_index := 0.U
968    bankConflictData.fake_rr_bank_conflict := false.B
969  }
970
971  val isWriteBankConflictTable = WireInit(Constantin.createRecord("isWriteBankConflictTable" + p(XSCoreParamsKey).HartId.toString))
972  bankConflictTable.log(
973    data = bankConflictData,
974    en = isWriteBankConflictTable.orR && rr_bank_conflict(0)(1),
975    site = siteName,
976    clock = clock,
977    reset = reset
978  )
979
980  (1 until LoadPipelineWidth).foreach(y => (0 until y).foreach(x =>
981    XSPerfAccumulate(s"data_array_fake_rr_bank_conflict_${x}_${y}", rr_bank_conflict(x)(y) && set_addrs(x) === set_addrs(y))
982  ))
983
984}