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