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