xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/meta/TagArray.scala (revision 602aa9f1a8fb63310bea30e8b3e247e5aca5f123)
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