xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/data/DuplicatedDataArray.scala (revision 11269ca741bcbed259cf718605d4720728016f90)
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 chisel3.util._
23import freechips.rocketchip.tilelink.{ClientMetadata, TLClientParameters, TLEdgeOut}
24import utility.{Code, ParallelOR, ReplacementPolicy, XSDebug}
25import utility.sram.SRAMTemplate
26
27import scala.math.max
28
29class DuplicatedDataArray(implicit p: Parameters) extends AbstractDataArray {
30  val singlePort = true
31  val readHighPriority = false
32
33  def getECCFromEncWord(encWord: UInt) = {
34    require(encWord.getWidth == encWordBits)
35    encWord(encWordBits - 1, wordBits)
36  }
37
38  def getECCFromRow(row: UInt) = {
39    require(row.getWidth == rowBits)
40    VecInit((0 until rowWords).map { w =>
41      val word = row(wordBits * (w + 1) - 1, wordBits * w)
42      getECCFromEncWord(cacheParams.dataCode.encode(word))
43    })
44  }
45
46  val waddr = (io.write.bits.addr >> blockOffBits).asUInt
47  val raddrs = io.read.map(r => (r.bits.addr >> blockOffBits).asUInt)
48  io.write.ready := (if (readHighPriority) {
49    if (singlePort) {
50      !VecInit(io.read.map(_.valid)).asUInt.orR
51    } else {
52      !(Cat(io.read.zipWithIndex.map { case (r, i) => r.valid && raddrs(i) === waddr }).orR)
53    }
54  } else {
55    true.B
56  })
57
58  // wrap a data row and a ecc row
59  class DataSRAMGroup extends Module {
60    val io = IO(new Bundle() {
61      val wen, ren = Input(Bool())
62      val waddr, raddr = Input(UInt())
63      val wdata = Input(UInt(rowBits.W))
64      val w_way_en, r_way_en = Input(UInt(nWays.W))
65      val rdata = Output(UInt())
66    })
67
68    val r_way_en_reg = RegEnable(io.r_way_en, io.ren)
69    val data_array = Seq.fill(nWays) {
70      Module(new SRAMTemplate(
71        Bits(rowBits.W),
72        set = nSets,
73        way = 1,
74        shouldReset = false,
75        holdRead = false,
76        singlePort = singlePort
77      ))
78    }
79
80    for (w <- 0 until nWays) {
81      val wen = io.wen && io.w_way_en(w)
82      data_array(w).io.w.req.valid := wen
83      data_array(w).io.w.req.bits.apply(
84        setIdx = io.waddr,
85        data = io.wdata,
86        waymask = 1.U
87      )
88      data_array(w).io.r.req.valid := io.ren
89      data_array(w).io.r.req.bits.apply(setIdx = io.raddr)
90    }
91
92    val half = nWays / 2
93    val data_read = data_array.map(_.io.r.resp.data(0))
94    val data_left = Mux1H(r_way_en_reg.tail(half), data_read.take(half))
95    val data_right = Mux1H(r_way_en_reg.head(half), data_read.drop(half))
96
97    val sel_low = r_way_en_reg.tail(half).orR
98    val row_data = Mux(sel_low, data_left, data_right)
99
100    io.rdata := row_data
101  }
102
103  for (j <- 0 until 3) {
104    val raddr = raddrs(j)
105    val rmask = io.read(j).bits.rmask
106
107    // for single port SRAM, do not allow read and write in the same cycle
108    // for dual port SRAM, raddr === waddr is undefined behavior
109    val rwhazard = if (singlePort) io.write.valid else io.write.valid && waddr === raddr
110    io.read(j).ready := (if (readHighPriority) true.B else !rwhazard)
111
112    // use way_en to select a way after data read out
113    assert(!(RegNext(io.read(j).fire && PopCount(io.read(j).bits.way_en) > 1.U)))
114    val way_en = RegEnable(io.read(j).bits.way_en, io.read(j).fire)
115
116    val row_error = Wire(Vec(blockRows, Vec(rowWords, Bool())))
117    for (r <- 0 until blockRows) {
118      val ecc_array = Module(new SRAMTemplate(
119        Vec(rowWords, Bits(eccBits.W)),
120        set = nSets,
121        way = nWays,
122        shouldReset = false,
123        holdRead = false,
124        singlePort = singlePort
125      ))
126      ecc_array.io.w.req.valid := io.write.valid && io.write.bits.wmask(r)
127      ecc_array.io.w.req.bits.apply(
128        setIdx = waddr,
129        data = getECCFromRow(io.write.bits.data(r)),
130        waymask = io.write.bits.way_en
131      )
132      XSDebug(ecc_array.io.w.req.valid,
133        p"write in ecc sram ${j.U} row ${r.U}: setIdx=${Hexadecimal(ecc_array.io.w.req.bits.setIdx)} ecc(0)=${Hexadecimal(getECCFromRow(io.write.bits.data(r))(0))} ecc(1)=${Hexadecimal(getECCFromRow(io.write.bits.data(r))(1))} waymask=${Hexadecimal(io.write.bits.way_en)}\n")
134      ecc_array.io.r.req.valid := io.read(j).valid && rmask(r)
135      ecc_array.io.r.req.bits.apply(setIdx = raddr)
136
137      val dataGroup = Module(new DataSRAMGroup)
138      dataGroup.io.wen := io.write.valid && io.write.bits.wmask(r)
139      dataGroup.io.w_way_en := io.write.bits.way_en
140      dataGroup.io.waddr := waddr
141      dataGroup.io.wdata := io.write.bits.data(r)
142      dataGroup.io.ren := io.read(j).valid && io.read(j).bits.rmask(r)
143      dataGroup.io.r_way_en := io.read(j).bits.way_en
144      dataGroup.io.raddr := raddr
145
146      val ecc_resp = Wire(Vec(rowWords, Vec(nWays, Bits(eccBits.W))))
147      for(w <- 0 until nWays){
148        for(k <- 0 until rowWords){
149          ecc_resp(k)(w) := ecc_array.io.r.resp.data(w)(k)
150        }
151      }
152      val ecc_resp_chosen = Wire(Vec(rowWords, Bits(eccBits.W)))
153      val data_resp_chosen = Wire(Vec(rowWords, Bits(wordBits.W)))
154      data_resp_chosen := dataGroup.io.rdata.asTypeOf(data_resp_chosen)
155      for (k <- 0 until rowWords) {
156        ecc_resp_chosen(k) := Mux1H(way_en, ecc_resp(k))
157      }
158      io.resp(j)(r) := Cat((0 until rowWords).reverseIterator.map {
159        k => {
160          val data = Cat(ecc_resp_chosen(k), data_resp_chosen(k))
161          row_error(r)(k) := dcacheParameters.dataCode.decode(data).error && RegNext(rmask(r))
162          data
163        }
164      }.toSeq)
165      io.errors(j).bits.report_to_beu := RegNext(io.read(j).fire) && Cat(row_error.flatten).orR
166      io.errors(j).bits.paddr := RegEnable(io.read(j).bits.addr, io.read(j).fire)
167    }
168
169    io.nacks(j) := false.B
170  }
171}
172