xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/data/DuplicatedDataArray.scala (revision 6639e9a467468f4e1b05a25a5de4500772aedeb1)
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, SRAMTemplate, XSDebug}
25
26import scala.math.max
27
28class DuplicatedDataArray(implicit p: Parameters) extends AbstractDataArray {
29  val singlePort = true
30  val readHighPriority = false
31
32  def getECCFromEncWord(encWord: UInt) = {
33    require(encWord.getWidth == encWordBits)
34    encWord(encWordBits - 1, wordBits)
35  }
36
37  def getECCFromRow(row: UInt) = {
38    require(row.getWidth == rowBits)
39    VecInit((0 until rowWords).map { w =>
40      val word = row(wordBits * (w + 1) - 1, wordBits * w)
41      getECCFromEncWord(cacheParams.dataCode.encode(word))
42    })
43  }
44
45  val waddr = (io.write.bits.addr >> blockOffBits).asUInt
46  val raddrs = io.read.map(r => (r.bits.addr >> blockOffBits).asUInt)
47  io.write.ready := (if (readHighPriority) {
48    if (singlePort) {
49      !VecInit(io.read.map(_.valid)).asUInt.orR
50    } else {
51      !(Cat(io.read.zipWithIndex.map { case (r, i) => r.valid && raddrs(i) === waddr }).orR)
52    }
53  } else {
54    true.B
55  })
56
57  // wrap a data row and a ecc row
58  class DataSRAMGroup extends Module {
59    val io = IO(new Bundle() {
60      val wen, ren = Input(Bool())
61      val waddr, raddr = Input(UInt())
62      val wdata = Input(UInt(rowBits.W))
63      val w_way_en, r_way_en = Input(UInt(nWays.W))
64      val rdata = Output(UInt())
65    })
66
67    val r_way_en_reg = RegEnable(io.r_way_en, io.ren)
68    val data_array = Seq.fill(nWays) {
69      Module(new SRAMTemplate(
70        Bits(rowBits.W),
71        set = nSets,
72        way = 1,
73        shouldReset = false,
74        holdRead = false,
75        singlePort = singlePort
76      ))
77    }
78
79    for (w <- 0 until nWays) {
80      val wen = io.wen && io.w_way_en(w)
81      data_array(w).io.w.req.valid := wen
82      data_array(w).io.w.req.bits.apply(
83        setIdx = io.waddr,
84        data = io.wdata,
85        waymask = 1.U
86      )
87      data_array(w).io.r.req.valid := io.ren
88      data_array(w).io.r.req.bits.apply(setIdx = io.raddr)
89    }
90
91    val half = nWays / 2
92    val data_read = data_array.map(_.io.r.resp.data(0))
93    val data_left = Mux1H(r_way_en_reg.tail(half), data_read.take(half))
94    val data_right = Mux1H(r_way_en_reg.head(half), data_read.drop(half))
95
96    val sel_low = r_way_en_reg.tail(half).orR
97    val row_data = Mux(sel_low, data_left, data_right)
98
99    io.rdata := row_data
100  }
101
102  for (j <- 0 until 3) {
103    val raddr = raddrs(j)
104    val rmask = io.read(j).bits.rmask
105
106    // for single port SRAM, do not allow read and write in the same cycle
107    // for dual port SRAM, raddr === waddr is undefined behavior
108    val rwhazard = if (singlePort) io.write.valid else io.write.valid && waddr === raddr
109    io.read(j).ready := (if (readHighPriority) true.B else !rwhazard)
110
111    // use way_en to select a way after data read out
112    assert(!(RegNext(io.read(j).fire && PopCount(io.read(j).bits.way_en) > 1.U)))
113    val way_en = RegEnable(io.read(j).bits.way_en, io.read(j).fire)
114
115    val row_error = Wire(Vec(blockRows, Vec(rowWords, Bool())))
116    for (r <- 0 until blockRows) {
117      val ecc_array = Module(new SRAMTemplate(
118        Vec(rowWords, Bits(eccBits.W)),
119        set = nSets,
120        way = nWays,
121        shouldReset = false,
122        holdRead = false,
123        singlePort = singlePort
124      ))
125      ecc_array.io.w.req.valid := io.write.valid && io.write.bits.wmask(r)
126      ecc_array.io.w.req.bits.apply(
127        setIdx = waddr,
128        data = getECCFromRow(io.write.bits.data(r)),
129        waymask = io.write.bits.way_en
130      )
131      when(ecc_array.io.w.req.valid) {
132        XSDebug(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")
133      }
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