xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/data/DuplicatedDataArray.scala (revision 11269ca741bcbed259cf718605d4720728016f90)
11f0e2dc7SJiawei Lin/***************************************************************************************
2e3da8badSTang Haojin* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3e3da8badSTang Haojin* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
41f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Peng Cheng Laboratory
51f0e2dc7SJiawei Lin*
61f0e2dc7SJiawei Lin* XiangShan is licensed under Mulan PSL v2.
71f0e2dc7SJiawei Lin* You can use this software according to the terms and conditions of the Mulan PSL v2.
81f0e2dc7SJiawei Lin* You may obtain a copy of Mulan PSL v2 at:
91f0e2dc7SJiawei Lin*          http://license.coscl.org.cn/MulanPSL2
101f0e2dc7SJiawei Lin*
111f0e2dc7SJiawei Lin* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
121f0e2dc7SJiawei Lin* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
131f0e2dc7SJiawei Lin* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
141f0e2dc7SJiawei Lin*
151f0e2dc7SJiawei Lin* See the Mulan PSL v2 for more details.
161f0e2dc7SJiawei Lin***************************************************************************************/
171f0e2dc7SJiawei Lin
181f0e2dc7SJiawei Linpackage xiangshan.cache
191f0e2dc7SJiawei Lin
208891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
211f0e2dc7SJiawei Linimport chisel3._
221f0e2dc7SJiawei Linimport chisel3.util._
231f0e2dc7SJiawei Linimport freechips.rocketchip.tilelink.{ClientMetadata, TLClientParameters, TLEdgeOut}
24*11269ca7STang Haojinimport utility.{Code, ParallelOR, ReplacementPolicy, XSDebug}
25*11269ca7STang Haojinimport utility.sram.SRAMTemplate
261f0e2dc7SJiawei Lin
271f0e2dc7SJiawei Linimport scala.math.max
281f0e2dc7SJiawei Lin
291f0e2dc7SJiawei Linclass DuplicatedDataArray(implicit p: Parameters) extends AbstractDataArray {
301f0e2dc7SJiawei Lin  val singlePort = true
311f0e2dc7SJiawei Lin  val readHighPriority = false
321f0e2dc7SJiawei Lin
331f0e2dc7SJiawei Lin  def getECCFromEncWord(encWord: UInt) = {
341f0e2dc7SJiawei Lin    require(encWord.getWidth == encWordBits)
351f0e2dc7SJiawei Lin    encWord(encWordBits - 1, wordBits)
361f0e2dc7SJiawei Lin  }
371f0e2dc7SJiawei Lin
381f0e2dc7SJiawei Lin  def getECCFromRow(row: UInt) = {
391f0e2dc7SJiawei Lin    require(row.getWidth == rowBits)
401f0e2dc7SJiawei Lin    VecInit((0 until rowWords).map { w =>
411f0e2dc7SJiawei Lin      val word = row(wordBits * (w + 1) - 1, wordBits * w)
421f0e2dc7SJiawei Lin      getECCFromEncWord(cacheParams.dataCode.encode(word))
431f0e2dc7SJiawei Lin    })
441f0e2dc7SJiawei Lin  }
451f0e2dc7SJiawei Lin
46935edac4STang Haojin  val waddr = (io.write.bits.addr >> blockOffBits).asUInt
471f0e2dc7SJiawei Lin  val raddrs = io.read.map(r => (r.bits.addr >> blockOffBits).asUInt)
481f0e2dc7SJiawei Lin  io.write.ready := (if (readHighPriority) {
491f0e2dc7SJiawei Lin    if (singlePort) {
501f0e2dc7SJiawei Lin      !VecInit(io.read.map(_.valid)).asUInt.orR
511f0e2dc7SJiawei Lin    } else {
521f0e2dc7SJiawei Lin      !(Cat(io.read.zipWithIndex.map { case (r, i) => r.valid && raddrs(i) === waddr }).orR)
531f0e2dc7SJiawei Lin    }
541f0e2dc7SJiawei Lin  } else {
551f0e2dc7SJiawei Lin    true.B
561f0e2dc7SJiawei Lin  })
571f0e2dc7SJiawei Lin
581f0e2dc7SJiawei Lin  // wrap a data row and a ecc row
591f0e2dc7SJiawei Lin  class DataSRAMGroup extends Module {
601f0e2dc7SJiawei Lin    val io = IO(new Bundle() {
611f0e2dc7SJiawei Lin      val wen, ren = Input(Bool())
621f0e2dc7SJiawei Lin      val waddr, raddr = Input(UInt())
631f0e2dc7SJiawei Lin      val wdata = Input(UInt(rowBits.W))
641f0e2dc7SJiawei Lin      val w_way_en, r_way_en = Input(UInt(nWays.W))
651f0e2dc7SJiawei Lin      val rdata = Output(UInt())
661f0e2dc7SJiawei Lin    })
671f0e2dc7SJiawei Lin
685adc4829SYanqin Li    val r_way_en_reg = RegEnable(io.r_way_en, io.ren)
69e3da8badSTang Haojin    val data_array = Seq.fill(nWays) {
701f0e2dc7SJiawei Lin      Module(new SRAMTemplate(
711f0e2dc7SJiawei Lin        Bits(rowBits.W),
721f0e2dc7SJiawei Lin        set = nSets,
731f0e2dc7SJiawei Lin        way = 1,
741f0e2dc7SJiawei Lin        shouldReset = false,
751f0e2dc7SJiawei Lin        holdRead = false,
761f0e2dc7SJiawei Lin        singlePort = singlePort
771f0e2dc7SJiawei Lin      ))
781f0e2dc7SJiawei Lin    }
791f0e2dc7SJiawei Lin
801f0e2dc7SJiawei Lin    for (w <- 0 until nWays) {
811f0e2dc7SJiawei Lin      val wen = io.wen && io.w_way_en(w)
821f0e2dc7SJiawei Lin      data_array(w).io.w.req.valid := wen
831f0e2dc7SJiawei Lin      data_array(w).io.w.req.bits.apply(
841f0e2dc7SJiawei Lin        setIdx = io.waddr,
851f0e2dc7SJiawei Lin        data = io.wdata,
861f0e2dc7SJiawei Lin        waymask = 1.U
871f0e2dc7SJiawei Lin      )
881f0e2dc7SJiawei Lin      data_array(w).io.r.req.valid := io.ren
891f0e2dc7SJiawei Lin      data_array(w).io.r.req.bits.apply(setIdx = io.raddr)
901f0e2dc7SJiawei Lin    }
911f0e2dc7SJiawei Lin
921f0e2dc7SJiawei Lin    val half = nWays / 2
931f0e2dc7SJiawei Lin    val data_read = data_array.map(_.io.r.resp.data(0))
941f0e2dc7SJiawei Lin    val data_left = Mux1H(r_way_en_reg.tail(half), data_read.take(half))
951f0e2dc7SJiawei Lin    val data_right = Mux1H(r_way_en_reg.head(half), data_read.drop(half))
961f0e2dc7SJiawei Lin
97935edac4STang Haojin    val sel_low = r_way_en_reg.tail(half).orR
981f0e2dc7SJiawei Lin    val row_data = Mux(sel_low, data_left, data_right)
991f0e2dc7SJiawei Lin
1001f0e2dc7SJiawei Lin    io.rdata := row_data
1011f0e2dc7SJiawei Lin  }
1021f0e2dc7SJiawei Lin
1031f0e2dc7SJiawei Lin  for (j <- 0 until 3) {
1041f0e2dc7SJiawei Lin    val raddr = raddrs(j)
1051f0e2dc7SJiawei Lin    val rmask = io.read(j).bits.rmask
1061f0e2dc7SJiawei Lin
1071f0e2dc7SJiawei Lin    // for single port SRAM, do not allow read and write in the same cycle
1081f0e2dc7SJiawei Lin    // for dual port SRAM, raddr === waddr is undefined behavior
1091f0e2dc7SJiawei Lin    val rwhazard = if (singlePort) io.write.valid else io.write.valid && waddr === raddr
1101f0e2dc7SJiawei Lin    io.read(j).ready := (if (readHighPriority) true.B else !rwhazard)
1111f0e2dc7SJiawei Lin
1121f0e2dc7SJiawei Lin    // use way_en to select a way after data read out
113935edac4STang Haojin    assert(!(RegNext(io.read(j).fire && PopCount(io.read(j).bits.way_en) > 1.U)))
1145adc4829SYanqin Li    val way_en = RegEnable(io.read(j).bits.way_en, io.read(j).fire)
1151f0e2dc7SJiawei Lin
1161f0e2dc7SJiawei Lin    val row_error = Wire(Vec(blockRows, Vec(rowWords, Bool())))
1171f0e2dc7SJiawei Lin    for (r <- 0 until blockRows) {
1181f0e2dc7SJiawei Lin      val ecc_array = Module(new SRAMTemplate(
1191f0e2dc7SJiawei Lin        Vec(rowWords, Bits(eccBits.W)),
1201f0e2dc7SJiawei Lin        set = nSets,
1211f0e2dc7SJiawei Lin        way = nWays,
1221f0e2dc7SJiawei Lin        shouldReset = false,
1231f0e2dc7SJiawei Lin        holdRead = false,
1241f0e2dc7SJiawei Lin        singlePort = singlePort
1251f0e2dc7SJiawei Lin      ))
1261f0e2dc7SJiawei Lin      ecc_array.io.w.req.valid := io.write.valid && io.write.bits.wmask(r)
1271f0e2dc7SJiawei Lin      ecc_array.io.w.req.bits.apply(
1281f0e2dc7SJiawei Lin        setIdx = waddr,
1291f0e2dc7SJiawei Lin        data = getECCFromRow(io.write.bits.data(r)),
1301f0e2dc7SJiawei Lin        waymask = io.write.bits.way_en
1311f0e2dc7SJiawei Lin      )
1328b33cd30Sklin02      XSDebug(ecc_array.io.w.req.valid,
1338b33cd30Sklin02        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")
1341f0e2dc7SJiawei Lin      ecc_array.io.r.req.valid := io.read(j).valid && rmask(r)
1351f0e2dc7SJiawei Lin      ecc_array.io.r.req.bits.apply(setIdx = raddr)
1361f0e2dc7SJiawei Lin
1371f0e2dc7SJiawei Lin      val dataGroup = Module(new DataSRAMGroup)
1381f0e2dc7SJiawei Lin      dataGroup.io.wen := io.write.valid && io.write.bits.wmask(r)
1391f0e2dc7SJiawei Lin      dataGroup.io.w_way_en := io.write.bits.way_en
1401f0e2dc7SJiawei Lin      dataGroup.io.waddr := waddr
1411f0e2dc7SJiawei Lin      dataGroup.io.wdata := io.write.bits.data(r)
1421f0e2dc7SJiawei Lin      dataGroup.io.ren := io.read(j).valid && io.read(j).bits.rmask(r)
1431f0e2dc7SJiawei Lin      dataGroup.io.r_way_en := io.read(j).bits.way_en
1441f0e2dc7SJiawei Lin      dataGroup.io.raddr := raddr
1451f0e2dc7SJiawei Lin
1461f0e2dc7SJiawei Lin      val ecc_resp = Wire(Vec(rowWords, Vec(nWays, Bits(eccBits.W))))
1471f0e2dc7SJiawei Lin      for(w <- 0 until nWays){
1481f0e2dc7SJiawei Lin        for(k <- 0 until rowWords){
1491f0e2dc7SJiawei Lin          ecc_resp(k)(w) := ecc_array.io.r.resp.data(w)(k)
1501f0e2dc7SJiawei Lin        }
1511f0e2dc7SJiawei Lin      }
1521f0e2dc7SJiawei Lin      val ecc_resp_chosen = Wire(Vec(rowWords, Bits(eccBits.W)))
1531f0e2dc7SJiawei Lin      val data_resp_chosen = Wire(Vec(rowWords, Bits(wordBits.W)))
1541f0e2dc7SJiawei Lin      data_resp_chosen := dataGroup.io.rdata.asTypeOf(data_resp_chosen)
1551f0e2dc7SJiawei Lin      for (k <- 0 until rowWords) {
1561f0e2dc7SJiawei Lin        ecc_resp_chosen(k) := Mux1H(way_en, ecc_resp(k))
1571f0e2dc7SJiawei Lin      }
158e3da8badSTang Haojin      io.resp(j)(r) := Cat((0 until rowWords).reverseIterator.map {
1591f0e2dc7SJiawei Lin        k => {
1601f0e2dc7SJiawei Lin          val data = Cat(ecc_resp_chosen(k), data_resp_chosen(k))
1611f0e2dc7SJiawei Lin          row_error(r)(k) := dcacheParameters.dataCode.decode(data).error && RegNext(rmask(r))
1621f0e2dc7SJiawei Lin          data
1631f0e2dc7SJiawei Lin        }
164e3da8badSTang Haojin      }.toSeq)
1650184a80eSYanqin Li      io.errors(j).bits.report_to_beu := RegNext(io.read(j).fire) && Cat(row_error.flatten).orR
1665adc4829SYanqin Li      io.errors(j).bits.paddr := RegEnable(io.read(j).bits.addr, io.read(j).fire)
1671f0e2dc7SJiawei Lin    }
1681f0e2dc7SJiawei Lin
1691f0e2dc7SJiawei Lin    io.nacks(j) := false.B
1701f0e2dc7SJiawei Lin  }
1711f0e2dc7SJiawei Lin}
172