xref: /XiangShan/src/main/scala/xiangshan/backend/regfile/Regfile.scala (revision 748214a1e654ec0cc908319e861abaf6bb3287a5)
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 org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils.OptionWrapper
23import xiangshan._
24import xiangshan.backend.datapath.DataConfig._
25import xiangshan.backend.exu.ExeUnitParams
26
27class RfReadPort(dataWidth: Int, addrWidth: Int) extends Bundle {
28  val addr = Input(UInt(addrWidth.W))
29  val data = Output(UInt(dataWidth.W))
30}
31
32class RfWritePort(dataWidth: Int, addrWidth: Int) extends Bundle {
33  val wen = Input(Bool())
34  val addr = Input(UInt(addrWidth.W))
35  val data = Input(UInt(dataWidth.W))
36}
37
38class RfReadPortWithConfig(val rfReadDataCfg: DataConfig, addrWidth: Int) extends Bundle {
39  val addr: UInt = Input(UInt(addrWidth.W))
40  val srcType: UInt = Input(UInt(3.W))
41
42  def readInt: Boolean = IntRegSrcDataSet.contains(rfReadDataCfg)
43  def readFp : Boolean = FpRegSrcDataSet .contains(rfReadDataCfg)
44  def readVec: Boolean = VecRegSrcDataSet.contains(rfReadDataCfg)
45  def readVf : Boolean = VecRegSrcDataSet .contains(rfReadDataCfg)
46}
47
48class RfWritePortWithConfig(val rfWriteDataCfg: DataConfig, addrWidth: Int) extends Bundle {
49  val wen = Input(Bool())
50  val addr = Input(UInt(addrWidth.W))
51  val data = Input(UInt(rfWriteDataCfg.dataWidth.W))
52  val intWen = Input(Bool())
53  val fpWen = Input(Bool())
54  val vecWen = Input(Bool())
55  val v0Wen = Input(Bool())
56  val vlWen = Input(Bool())
57  def writeInt: Boolean = rfWriteDataCfg.isInstanceOf[IntData]
58  def writeFp : Boolean = rfWriteDataCfg.isInstanceOf[FpData]
59  def writeVec: Boolean = rfWriteDataCfg.isInstanceOf[VecData]
60  def writeV0 : Boolean = rfWriteDataCfg.isInstanceOf[V0Data]
61  def writeVl : Boolean = rfWriteDataCfg.isInstanceOf[VlData]
62}
63
64class Regfile
65(
66  name: String,
67  numPregs: Int,
68  numReadPorts: Int,
69  numWritePorts: Int,
70  hasZero: Boolean,
71  len: Int,
72  width: Int,
73  bankNum: Int = 1,
74  isVlRegfile: Boolean = false,
75) extends Module {
76  val io = IO(new Bundle() {
77    val readPorts = Vec(numReadPorts, new RfReadPort(len, width))
78    val writePorts = Vec(numWritePorts, new RfWritePort(len, width))
79    val debug_rports = Vec(65, new RfReadPort(len, width))
80  })
81  override def desiredName = name
82  println(name + ": size:" + numPregs + " read: " + numReadPorts + " write: " + numWritePorts)
83
84  val mem_0 = if (isVlRegfile) RegInit(0.U(len.W)) else Reg(UInt(len.W))
85  val mem = Reg(Vec(numPregs, UInt(len.W)))
86  val memForRead = Wire(Vec(numPregs, UInt(len.W)))
87  memForRead.zipWithIndex.map{ case(m, i) =>
88    if (i == 0) m := mem_0
89    else m := mem(i)
90  }
91  require(Seq(1, 2, 4).contains(bankNum), "bankNum must be 1 or 2 or 4")
92  for (r <- io.readPorts) {
93    if (bankNum == 1) {
94      r.data := memForRead(RegNext(r.addr))
95    }
96    else {
97      val banks = (0 until bankNum).map { case i =>
98        memForRead.zipWithIndex.filter{ case (m, index) => (index % bankNum) == i }.map(_._1)
99      }
100      val bankWidth = bankNum.U.getWidth - 1
101      val hitBankWire = VecInit((0 until bankNum).map { case i => r.addr(bankWidth - 1, 0) === i.U })
102      val hitBankReg = Reg(Vec(bankNum, Bool()))
103      hitBankReg := hitBankWire
104      val banksRdata = Wire(Vec(bankNum, UInt(len.W)))
105      for (i <- 0 until bankNum) {
106        banksRdata(i) := RegEnable(VecInit(banks(i))(r.addr(r.addr.getWidth - 1, bankWidth)), hitBankWire(i))
107      }
108      r.data := Mux1H(hitBankReg, banksRdata)
109    }
110  }
111  val writePorts = io.writePorts
112  for (i <- writePorts.indices) {
113    if (i < writePorts.size-1) {
114      val hasSameWrite = writePorts.drop(i + 1).map(w => w.wen && w.addr === writePorts(i).addr && writePorts(i).wen).reduce(_ || _)
115      assert(!hasSameWrite, "RegFile two or more writePorts write same addr")
116    }
117  }
118  for (i <- mem.indices) {
119    if (hasZero && i == 0) {
120      mem_0 := 0.U
121    }
122    else {
123      val wenOH = VecInit(io.writePorts.map(w => w.wen && w.addr === i.U))
124      val wData = Mux1H(wenOH, io.writePorts.map(_.data))
125      when(wenOH.asUInt.orR) {
126        if (i == 0) mem_0 := wData
127        else mem(i) := wData
128      }
129    }
130  }
131
132  for (rport <- io.debug_rports) {
133    rport.data := memForRead(rport.addr)
134  }
135}
136
137object Regfile {
138  // non-return version
139  def apply(
140    name         : String,
141    numEntries   : Int,
142    raddr        : Seq[UInt],
143    rdata        : Vec[UInt],
144    wen          : Seq[Bool],
145    waddr        : Seq[UInt],
146    wdata        : Seq[UInt],
147    hasZero      : Boolean,
148    withReset    : Boolean = false,
149    bankNum      : Int = 1,
150    debugReadAddr: Option[Seq[UInt]],
151    debugReadData: Option[Vec[UInt]],
152    isVlRegfile  : Boolean = false,
153  )(implicit p: Parameters): Unit = {
154    val numReadPorts = raddr.length
155    val numWritePorts = wen.length
156    require(wen.length == waddr.length)
157    require(wen.length == wdata.length)
158    val dataBits = wdata.map(_.getWidth).min
159    require(wdata.map(_.getWidth).min == wdata.map(_.getWidth).max, s"dataBits != $dataBits")
160    val addrBits = waddr.map(_.getWidth).min
161    require(waddr.map(_.getWidth).min == waddr.map(_.getWidth).max, s"addrBits != $addrBits")
162
163    val instanceName = name(0).toLower.toString() + name.drop(1)
164    require(instanceName != name, "Regfile Instance Name can't be same as Module name")
165    val regfile = Module(new Regfile(name, numEntries, numReadPorts, numWritePorts, hasZero, dataBits, addrBits, bankNum, isVlRegfile)).suggestName(instanceName)
166    rdata := regfile.io.readPorts.zip(raddr).map { case (rport, addr) =>
167      rport.addr := addr
168      rport.data
169    }
170
171    regfile.io.writePorts.zip(wen).zip(waddr).zip(wdata).foreach{ case (((wport, en), addr), data) =>
172      wport.wen := en
173      wport.addr := addr
174      wport.data := data
175    }
176    if (withReset) {
177      val numResetCycles = math.ceil(numEntries / numWritePorts).toInt
178      val resetCounter = RegInit(numResetCycles.U)
179      val resetWaddr = RegInit(VecInit((0 until numWritePorts).map(_.U(log2Up(numEntries + 1).W))))
180      val inReset = resetCounter =/= 0.U
181      when (inReset) {
182        resetCounter := resetCounter - 1.U
183        resetWaddr := VecInit(resetWaddr.map(_ + numWritePorts.U))
184      }
185      when (!inReset) {
186        resetWaddr.map(_ := 0.U)
187      }
188      for ((wport, i) <- regfile.io.writePorts.zipWithIndex) {
189        wport.wen := inReset || wen(i)
190        wport.addr := Mux(inReset, resetWaddr(i), waddr(i))
191        wport.data := wdata(i)
192      }
193    }
194
195    require(debugReadAddr.nonEmpty == debugReadData.nonEmpty, "Both debug addr and data bundles should be empty or not")
196    regfile.io.debug_rports := DontCare
197    if (debugReadAddr.nonEmpty && debugReadData.nonEmpty) {
198      debugReadData.get := VecInit(regfile.io.debug_rports.zip(debugReadAddr.get).map { case (rport, addr) =>
199        rport.addr := addr
200        rport.data
201      })
202    }
203  }
204}
205
206object IntRegFile {
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    debugReadAddr: Option[Seq[UInt]],
217    debugReadData: Option[Vec[UInt]],
218    withReset    : Boolean = false,
219    bankNum      : Int,
220  )(implicit p: Parameters): Unit = {
221    Regfile(
222      name, numEntries, raddr, rdata, wen, waddr, wdata,
223      hasZero = true, withReset, bankNum, debugReadAddr, debugReadData)
224  }
225}
226
227object IntRegFileSplit {
228  // non-return version
229  def apply(
230    name         : String,
231    numEntries   : Int,
232    splitNum     : Int,
233    raddr        : Seq[UInt],
234    rdata        : Vec[UInt],
235    wen          : Seq[Bool],
236    waddr        : Seq[UInt],
237    wdata        : Seq[UInt],
238    debugReadAddr: Option[Seq[UInt]],
239    debugReadData: Option[Vec[UInt]],
240    withReset    : Boolean = false,
241    bankNum      : Int,
242 )(implicit p: Parameters): Unit = {
243    require(Seq(1, 2, 4, 8).contains(splitNum))
244    val rdataVec = Wire(Vec(splitNum, Vec(rdata.length, UInt((rdata.head.getWidth / splitNum).W))))
245    rdata.zipWithIndex.map{ case (r, i) =>
246      r := Cat((0 until splitNum).map(x => rdataVec(x)(i)).reverse)
247    }
248    val debugReadDataVec = OptionWrapper(debugReadData.nonEmpty, Wire(Vec(splitNum, Vec(debugReadData.get.length, UInt((debugReadData.get.head.getWidth / splitNum).W)))))
249    if (debugReadData.nonEmpty) {
250      debugReadData.get.zipWithIndex.map { case (r, i) =>
251        r := Cat((0 until splitNum).map(x => debugReadDataVec.get(x)(i)).reverse)
252      }
253    }
254    for (i <- 0 until splitNum){
255      val wdataThisPart = wdata.map { case x =>
256        val widthThisPart = x.getWidth / splitNum
257        x((i + 1) * widthThisPart - 1, i * widthThisPart)
258      }
259      val nameSuffix = if (splitNum > 1) s"Part${i}" else ""
260      Regfile(
261        name + nameSuffix, numEntries, raddr, rdataVec(i), wen, waddr, wdataThisPart,
262        hasZero = true, withReset, bankNum, debugReadAddr, OptionWrapper(debugReadData.nonEmpty, debugReadDataVec.get(i)))
263    }
264  }
265}
266
267object FpRegFile {
268  // non-return version
269  def apply(
270             name         : String,
271             numEntries   : Int,
272             raddr        : Seq[UInt],
273             rdata        : Vec[UInt],
274             wen          : Seq[Bool],
275             waddr        : Seq[UInt],
276             wdata        : Seq[UInt],
277             debugReadAddr: Option[Seq[UInt]],
278             debugReadData: Option[Vec[UInt]],
279             withReset    : Boolean = false,
280             bankNum      : Int,
281             isVlRegfile  : Boolean = false,
282           )(implicit p: Parameters): Unit = {
283    Regfile(
284      name, numEntries, raddr, rdata, wen, waddr, wdata,
285      hasZero = false, withReset, bankNum, debugReadAddr, debugReadData, isVlRegfile)
286  }
287}
288
289object FpRegFileSplit {
290  // non-return version
291  def apply(
292             name         : String,
293             numEntries   : Int,
294             splitNum     : Int,
295             raddr        : Seq[UInt],
296             rdata        : Vec[UInt],
297             wen          : Seq[Bool],
298             waddr        : Seq[UInt],
299             wdata        : Seq[UInt],
300             debugReadAddr: Option[Seq[UInt]],
301             debugReadData: Option[Vec[UInt]],
302             withReset    : Boolean = false,
303             bankNum      : Int,
304             isVlRegfile  : Boolean = false,
305           )(implicit p: Parameters): Unit = {
306    require(Seq(1, 2, 4, 8).contains(splitNum))
307    val rdataVec = Wire(Vec(splitNum, Vec(rdata.length, UInt((rdata.head.getWidth / splitNum).W))))
308    rdata.zipWithIndex.map{ case (r, i) =>
309      r := Cat((0 until splitNum).map(x => rdataVec(x)(i)).reverse)
310    }
311    val debugReadDataVec = OptionWrapper(debugReadData.nonEmpty, Wire(Vec(splitNum, Vec(debugReadData.get.length, UInt((debugReadData.get.head.getWidth / splitNum).W)))))
312    if (debugReadData.nonEmpty) {
313      debugReadData.get.zipWithIndex.map { case (r, i) =>
314        r := Cat((0 until splitNum).map(x => debugReadDataVec.get(x)(i)).reverse)
315      }
316    }
317    for (i <- 0 until splitNum){
318      val wdataThisPart = wdata.map { case x =>
319        val widthThisPart = x.getWidth / splitNum
320        x((i + 1) * widthThisPart - 1, i * widthThisPart)
321      }
322      val nameSuffix = if (splitNum > 1) s"Part${i}" else ""
323      Regfile(
324        name + nameSuffix, numEntries, raddr, rdataVec(i), wen, waddr, wdataThisPart,
325        hasZero = false, withReset, bankNum, debugReadAddr, OptionWrapper(debugReadData.nonEmpty, debugReadDataVec.get(i)), isVlRegfile)
326    }
327  }
328}
329
330object VfRegFile {
331  // non-return version
332  def apply(
333    name         : String,
334    numEntries   : Int,
335    splitNum     : Int,
336    raddr        : Seq[UInt],
337    rdata        : Vec[UInt],
338    wen          : Seq[Seq[Bool]],
339    waddr        : Seq[UInt],
340    wdata        : Seq[UInt],
341    debugReadAddr: Option[Seq[UInt]],
342    debugReadData: Option[Vec[UInt]],
343    withReset    : Boolean = false,
344  )(implicit p: Parameters): Unit = {
345    require(splitNum >= 1, "splitNum should be no less than 1")
346    require(splitNum == wen.length, "splitNum should be equal to length of wen vec")
347    if (splitNum == 1) {
348      Regfile(
349        name, numEntries, raddr, rdata, wen.head, waddr, wdata,
350        hasZero = false, withReset, bankNum = 1, debugReadAddr, debugReadData)
351    } else {
352      val dataWidth = wdata.head.getWidth / splitNum
353      val numReadPorts = raddr.length
354      require(splitNum > 1 && wdata.head.getWidth == dataWidth * splitNum)
355      val wdataVec = Wire(Vec(splitNum, Vec(wdata.length, UInt(dataWidth.W))))
356      val rdataVec = Wire(Vec(splitNum, Vec(raddr.length, UInt(dataWidth.W))))
357      val debugRDataVec: Option[Vec[Vec[UInt]]] = debugReadData.map(x => Wire(Vec(splitNum, Vec(x.length, UInt(dataWidth.W)))))
358      for (i <- 0 until splitNum) {
359        wdataVec(i) := wdata.map(_ ((i + 1) * dataWidth - 1, i * dataWidth))
360        Regfile(
361          name + s"Part${i}", numEntries, raddr, rdataVec(i), wen(i), waddr, wdataVec(i),
362          hasZero = false, withReset, bankNum = 1, debugReadAddr, debugRDataVec.map(_(i))
363        )
364      }
365      for (i <- 0 until rdata.length) {
366        rdata(i) := Cat(rdataVec.map(_ (i)).reverse)
367      }
368      if (debugReadData.nonEmpty) {
369        for (i <- 0 until debugReadData.get.length) {
370          debugReadData.get(i) := Cat(debugRDataVec.get.map(_ (i)).reverse)
371        }
372      }
373    }
374  }
375}