xref: /XiangShan/src/main/scala/xiangshan/backend/regfile/Regfile.scala (revision aa825ab5a37d9b59a3aadaaa9ac7d5cb01206e6c)
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.backend.regfile
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23
24class RfReadPort(dataWidth: Int, addrWidth: Int)(implicit p: Parameters) extends XSBundle {
25  val addr = Input(UInt(addrWidth.W))
26  val data = Output(UInt(dataWidth.W))
27}
28
29class RfWritePort(dataWidth: Int, addrWidth: Int)(implicit p: Parameters) extends XSBundle {
30  val wen = Input(Bool())
31  val addr = Input(UInt(addrWidth.W))
32  val data = Input(UInt(dataWidth.W))
33}
34
35class Regfile
36(
37  name: String,
38  numReadPorts: Int,
39  numWritePorts: Int,
40  hasZero: Boolean,
41  len: Int,
42  width: Int,
43)(implicit p: Parameters) extends XSModule {
44  val io = IO(new Bundle() {
45    val readPorts = Vec(numReadPorts, new RfReadPort(len, width))
46    val writePorts = Vec(numWritePorts, new RfWritePort(len, width))
47    val debug_rports = Vec(64, new RfReadPort(len, width))
48  })
49
50  println(name + ": size:" + NRPhyRegs + " read: " + numReadPorts + " write: " + numWritePorts)
51
52  val mem = Reg(Vec(NRPhyRegs, UInt(len.W)))
53  for (r <- io.readPorts) {
54    val rdata = if (hasZero) Mux(r.addr === 0.U, 0.U, mem(r.addr)) else mem(r.addr)
55    r.data := rdata
56  }
57  for (w <- io.writePorts) {
58    when(w.wen) {
59      mem(w.addr) := w.data
60    }
61  }
62
63  for (rport <- io.debug_rports) {
64    val zero_rdata = Mux(rport.addr === 0.U, 0.U, mem(rport.addr))
65    rport.data := (if (hasZero) zero_rdata else mem(rport.addr))
66  }
67}
68
69object Regfile {
70  def apply(
71    name         : String,
72    numEntries   : Int,
73    raddr        : Seq[UInt],
74    wen          : Seq[Bool],
75    waddr        : Seq[UInt],
76    wdata        : Seq[UInt],
77    hasZero      : Boolean,
78    withReset    : Boolean = false,
79    debugReadAddr: Option[Seq[UInt]] = None,
80  )(implicit p: Parameters): Seq[UInt] = {
81    val numReadPorts = raddr.length
82    val numWritePorts = wen.length
83    require(wen.length == waddr.length)
84    require(wen.length == wdata.length)
85    val dataBits = wdata.map(_.getWidth).min
86    require(wdata.map(_.getWidth).min == wdata.map(_.getWidth).max, s"dataBits != $dataBits")
87    val addrBits = waddr.map(_.getWidth).min
88    require(waddr.map(_.getWidth).min == waddr.map(_.getWidth).max, s"addrBits != $addrBits")
89
90    val regfile = Module(new Regfile(name, numReadPorts, numWritePorts, hasZero, dataBits, addrBits))
91    val rdata = regfile.io.readPorts.zip(raddr).map { case (rport, addr) =>
92      rport.addr := addr
93      rport.data
94    }
95
96    regfile.io.writePorts.zip(wen).zip(waddr).zip(wdata).foreach{ case (((wport, en), addr), data) =>
97      wport.wen := en
98      wport.addr := addr
99      wport.data := data
100    }
101    if (withReset) {
102      val numResetCycles = math.ceil(numEntries / numWritePorts).toInt
103      val resetCounter = RegInit(numResetCycles.U)
104      val resetWaddr = RegInit(VecInit((0 until numWritePorts).map(_.U(log2Up(numEntries + 1).W))))
105      val inReset = resetCounter =/= 0.U
106      when (inReset) {
107        resetCounter := resetCounter - 1.U
108        resetWaddr := VecInit(resetWaddr.map(_ + numWritePorts.U))
109      }
110      when (!inReset) {
111        resetWaddr.map(_ := 0.U)
112      }
113      for ((wport, i) <- regfile.io.writePorts.zipWithIndex) {
114        wport.wen := inReset || wen(i)
115        wport.addr := Mux(inReset, resetWaddr(i), waddr(i))
116        wport.data := wdata(i)
117      }
118    }
119    regfile.io.debug_rports := DontCare
120    val debug_rdata = regfile.io.debug_rports.zip(debugReadAddr.getOrElse(Seq())).map { case (rport, addr) =>
121      rport.addr := addr
122      rport.data
123    }
124    rdata ++ debug_rdata
125  }
126
127  // non-return version
128  def apply(
129    name         : String,
130    numEntries   : Int,
131    raddr        : Seq[UInt],
132    rdata        : Vec[UInt],
133    wen          : Seq[Bool],
134    waddr        : Seq[UInt],
135    wdata        : Seq[UInt],
136    hasZero      : Boolean,
137    withReset    : Boolean = false,
138    debugReadAddr: Option[Seq[UInt]] = None,
139    debugReadData: Option[Vec[UInt]] = None,
140  )(implicit p: Parameters): Unit = {
141    val numReadPorts = raddr.length
142    val numWritePorts = wen.length
143    require(wen.length == waddr.length)
144    require(wen.length == wdata.length)
145    val dataBits = wdata.map(_.getWidth).min
146    require(wdata.map(_.getWidth).min == wdata.map(_.getWidth).max, s"dataBits != $dataBits")
147    val addrBits = waddr.map(_.getWidth).min
148    require(waddr.map(_.getWidth).min == waddr.map(_.getWidth).max, s"addrBits != $addrBits")
149
150    val regfile = Module(new Regfile(name, numReadPorts, numWritePorts, hasZero, dataBits, addrBits))
151    rdata := regfile.io.readPorts.zip(raddr).map { case (rport, addr) =>
152      rport.addr := addr
153      rport.data
154    }
155
156    regfile.io.writePorts.zip(wen).zip(waddr).zip(wdata).foreach{ case (((wport, en), addr), data) =>
157      wport.wen := en
158      wport.addr := addr
159      wport.data := data
160    }
161    if (withReset) {
162      val numResetCycles = math.ceil(numEntries / numWritePorts).toInt
163      val resetCounter = RegInit(numResetCycles.U)
164      val resetWaddr = RegInit(VecInit((0 until numWritePorts).map(_.U(log2Up(numEntries + 1).W))))
165      val inReset = resetCounter =/= 0.U
166      when (inReset) {
167        resetCounter := resetCounter - 1.U
168        resetWaddr := VecInit(resetWaddr.map(_ + numWritePorts.U))
169      }
170      when (!inReset) {
171        resetWaddr.map(_ := 0.U)
172      }
173      for ((wport, i) <- regfile.io.writePorts.zipWithIndex) {
174        wport.wen := inReset || wen(i)
175        wport.addr := Mux(inReset, resetWaddr(i), waddr(i))
176        wport.data := wdata(i)
177      }
178    }
179
180    require(debugReadAddr.nonEmpty == debugReadData.nonEmpty, "Both debug addr and data bundles should be empty or not")
181    regfile.io.debug_rports := DontCare
182    if (debugReadAddr.nonEmpty && debugReadData.nonEmpty) {
183      debugReadData.get := VecInit(regfile.io.debug_rports.zip(debugReadAddr.get).map { case (rport, addr) =>
184        rport.addr := addr
185        rport.data
186      })
187    }
188  }
189}
190
191object IntRegFile {
192  def apply(
193    name         : String,
194    numEntries   : Int,
195    raddr        : Seq[UInt],
196    wen          : Seq[Bool],
197    waddr        : Seq[UInt],
198    wdata        : Seq[UInt],
199    withReset    : Boolean = false,
200    debugReadAddr: Option[Seq[UInt]] = None,
201  )(implicit p: Parameters): Seq[UInt] = {
202    Regfile(
203      name, numEntries, raddr, wen, waddr, wdata,
204      hasZero = true, withReset, debugReadAddr)
205  }
206
207  // non-return version
208  def apply(
209    name         : String,
210    numEntries   : Int,
211    raddr        : Seq[UInt],
212    rdata        : Vec[UInt],
213    wen          : Seq[Bool],
214    waddr        : Seq[UInt],
215    wdata        : Seq[UInt],
216    withReset    : Boolean = false,
217    debugReadAddr: Option[Seq[UInt]] = None,
218    debugReadData: Option[Vec[UInt]] = None,
219  )(implicit p: Parameters): Unit = {
220    Regfile(
221      name, numEntries, raddr, rdata, wen, waddr, wdata,
222      hasZero = true, withReset, debugReadAddr, debugReadData)
223  }
224}
225
226object VfRegFile {
227  def apply(
228    name         : String,
229    numEntries   : Int,
230    splitNum     : Int,
231    raddr        : Seq[UInt],
232    wen          : Seq[Seq[Bool]],
233    waddr        : Seq[UInt],
234    wdata        : Seq[UInt],
235    withReset    : Boolean = false,
236    debugReadAddr: Option[Seq[UInt]] = None,
237  )(implicit p: Parameters) : Seq[UInt] = {
238    require(splitNum >= 1, "splitNum should be no less than 1")
239    require(splitNum == wen.length, "splitNum should be equal to length of wen vec")
240    if (splitNum == 1) {
241      Regfile(name, numEntries, raddr, wen.head, waddr, wdata,
242        hasZero = false, withReset, debugReadAddr)
243    } else {
244      val dataWidth = 64
245      val numReadPorts = raddr.length + debugReadAddr.getOrElse(Seq()).length
246      require(splitNum > 1 && wdata.head.getWidth == dataWidth * splitNum)
247      val wdataVec = Wire(Vec(splitNum, Vec(wdata.length, UInt(dataWidth.W))))
248      var rdataVec = Wire(Vec(splitNum, Vec(numReadPorts, UInt(dataWidth.W))))
249      for (i <- 0 until splitNum) {
250        wdataVec(i) := wdata.map(_((i + 1) * dataWidth - 1, i * dataWidth))
251        rdataVec(i) := Regfile(name+s"Part${i}", numEntries, raddr, wen(i), waddr, wdataVec(i),
252          hasZero = false, withReset, debugReadAddr)
253      }
254      val rdata = Wire(Vec(numReadPorts, UInt(wdata.head.getWidth.W)))
255      for (i <- 0 until rdata.length) {
256        rdata(i) := Cat(rdataVec.map(_(i)).reverse)
257      }
258      rdata
259    }
260  }
261
262  // non-return version
263  def apply(
264    name         : String,
265    numEntries   : Int,
266    splitNum     : Int,
267    raddr        : Seq[UInt],
268    rdata        : Vec[UInt],
269    wen          : Seq[Seq[Bool]],
270    waddr        : Seq[UInt],
271    wdata        : Seq[UInt],
272    withReset    : Boolean = false,
273    debugReadAddr: Option[Seq[UInt]] = None,
274    debugReadData: Option[Vec[UInt]] = None,
275  )(implicit p: Parameters) : Unit = {
276    require(splitNum >= 1, "splitNum should be no less than 1")
277    require(splitNum == wen.length, "splitNum should be equal to length of wen vec")
278    if (splitNum == 1) {
279      Regfile(name, numEntries, raddr, rdata, wen.head, waddr, wdata,
280        hasZero = false, withReset, debugReadAddr, debugReadData)
281    } else {
282      val dataWidth = 64
283      val numReadPorts = raddr.length
284      require(splitNum > 1 && wdata.head.getWidth == dataWidth * splitNum)
285      val wdataVec = Wire(Vec(splitNum, Vec(wdata.length, UInt(dataWidth.W))))
286      val rdataVec = Wire(Vec(splitNum, Vec(raddr.length, UInt(dataWidth.W))))
287      for (i <- 0 until splitNum) {
288        wdataVec(i) := wdata.map(_((i + 1) * dataWidth - 1, i * dataWidth))
289        Regfile(name+s"Part${i}", numEntries, raddr, rdataVec(i), wen(i), waddr, wdataVec(i),
290          hasZero = false, withReset, debugReadAddr, debugReadData)
291      }
292      for (i <- 0 until rdata.length) {
293        rdata(i) := Cat(rdataVec.map(_(i)).reverse)
294      }
295    }
296  }
297}
298