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 org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utility.{XSPerfAccumulate, ClockGate} 23import utility.mbist.MbistPipeline 24import utility.sram.SRAMTemplate 25 26class TagReadReq(implicit p: Parameters) extends DCacheBundle { 27 val idx = UInt(idxBits.W) 28 val way_en = UInt(nWays.W) 29} 30 31class TagWriteReq(implicit p: Parameters) extends TagReadReq { 32 val vaddr = UInt(vtagBits.W) 33 val tag = UInt(tagBits.W) 34 val ecc = UInt(tagECCBits.W) 35 36 def asECCTag() = { 37 if (EnableTagEcc) { 38 Cat(ecc, tag) 39 } else { 40 tag 41 } 42 } 43} 44 45class TagEccWriteReq(implicit p: Parameters) extends TagReadReq { 46 val ecc = UInt(tagECCBits.W) 47} 48 49case object HasTagEccParam 50 51abstract class AbstractTagArray(implicit p: Parameters) extends DCacheModule { 52 val TagEccParam = if(EnableTagEcc) Some(HasTagEccParam) else None 53} 54 55class TagSRAMBank(index: Int)(implicit p: Parameters) extends AbstractTagArray { 56 val io = IO(new Bundle() { 57 val read = Flipped(DecoupledIO(new TagReadReq { 58 override val way_en = UInt(DCacheWayDiv.W) 59 })) 60 val resp = Output(Vec(DCacheWayDiv, UInt(encTagBits.W))) 61 val write = Flipped(DecoupledIO(new TagWriteReq { 62 override val way_en = UInt(DCacheWayDiv.W) 63 })) 64 }) 65 // TODO: reset is unnecessary? 66 val rst_cnt = RegInit(0.U(log2Up(nSets + 1).W)) 67 val rst = rst_cnt < nSets.U 68 val rstVal = 0.U 69 val waddr = Mux(rst, rst_cnt, io.write.bits.idx) 70 val wdata = Mux(rst, rstVal, io.write.bits.asECCTag()) 71 val wmask = Mux(rst || (DCacheWayDiv == 1).B, (-1).asSInt, io.write.bits.way_en.asSInt).asBools 72 val rmask = Mux(rst || (DCacheWayDiv == 1).B, (-1).asSInt, io.read.bits.way_en.asSInt).asBools 73 when (rst) { 74 rst_cnt := rst_cnt + 1.U 75 } 76 77 val tag_array = Module(new SRAMTemplate(UInt(encTagBits.W), set = nSets, way = DCacheWayDiv, 78 shouldReset = false, holdRead = false, singlePort = true, withClockGate = true, 79 hasMbist = hasMbist, hasSramCtl = hasSramCtl, suffix = Some("dcsh_tag"))) 80 81 val wen = rst || io.write.valid 82 io.write.ready := !rst 83 tag_array.io.w.req.valid := wen 84 tag_array.io.w.req.bits.apply( 85 setIdx = waddr, 86 data = wdata, 87 waymask = VecInit(wmask).asUInt 88 ) 89 90 // tag read 91 val ren = io.read.fire 92 io.read.ready := !wen 93 tag_array.io.r.req.valid := ren 94 tag_array.io.r.req.bits.apply(setIdx = io.read.bits.idx) 95 io.resp := tag_array.io.r.resp.data 96 97 XSPerfAccumulate("part_tag_read_counter_" + index, tag_array.io.r.req.valid) 98} 99 100class TagArray(implicit p: Parameters) extends AbstractTagArray { 101 val io = IO(new Bundle() { 102 val read = Flipped(DecoupledIO(new TagReadReq)) 103 val resp = Output(Vec(nWays, UInt(encTagBits.W))) 104 val write = Flipped(DecoupledIO(new TagWriteReq)) 105 }) 106 107 val tag_arrays = List.tabulate(nWays / DCacheWayDiv)(i => Module(new TagSRAMBank(i))) 108 tag_arrays.zipWithIndex.foreach { case (tag_array, i) => 109 tag_array.io.read <> io.read 110 tag_array.io.read.bits.way_en := io.read.bits.way_en((i + 1) * DCacheWayDiv - 1, i * DCacheWayDiv) 111 tag_array.io.write <> io.write 112 tag_array.io.write.bits.way_en := io.write.bits.way_en((i + 1) * DCacheWayDiv - 1, i * DCacheWayDiv) 113 } 114 io.resp.zip(tag_arrays.map(_.io.resp).flatten).foreach { 115 case (resp, bank_resp) => 116 resp := bank_resp 117 } 118} 119 120class DuplicatedTagArray(readPorts: Int)(implicit p: Parameters) extends AbstractTagArray { 121 val io = IO(new Bundle() { 122 val read = Vec(readPorts, Flipped(DecoupledIO(new TagReadReq))) 123 val resp = Output(Vec(readPorts, Vec(nWays, UInt(encTagBits.W)))) 124 val write = Flipped(DecoupledIO(new TagWriteReq)) 125 }) 126 127 val array = Seq.fill(readPorts) { Module(new TagArray) } 128 val mbistPl = MbistPipeline.PlaceMbistPipeline(1, s"MbistPipeDcacheTag", hasMbist) 129 130 def getECCFromEncTag(encTag: UInt) = { 131 if (EnableDataEcc) { 132 require(encTag.getWidth == encTagBits, s"encTag=$encTag != encTagBits=$encTagBits!") 133 encTag(encTagBits - 1, tagBits) 134 } else { 135 0.U 136 } 137 } 138 139 val tag_read_oh = WireInit(VecInit(Seq.fill(readPorts)(0.U(XLEN.W)))) 140 for (i <- 0 until readPorts) { 141 // normal read / write 142 array(i).io.write.valid := io.write.valid 143 array(i).io.write.bits.idx := io.write.bits.idx 144 array(i).io.write.bits.way_en := io.write.bits.way_en 145 array(i).io.write.bits.vaddr := io.write.bits.vaddr 146 array(i).io.write.bits.tag := io.write.bits.tag 147 array(i).io.write.bits.ecc := getECCFromEncTag(cacheParams.tagCode.encode(io.write.bits.tag)) 148 io.write.ready := true.B 149 150 array(i).io.read <> io.read(i) 151 io.read(i).ready := array(i).io.read.ready 152 io.resp(i) := array(i).io.resp 153 tag_read_oh(i) := PopCount(array(i).io.read.fire) 154 } 155 156 XSPerfAccumulate("tag_read_counter", tag_read_oh.reduce(_ + _)) 157} 158