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