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