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