xref: /XiangShan/src/main/scala/xiangshan/backend/regfile/Regfile.scala (revision 9ab1568e215c540ca0554308577ff4d1813bfa8c)
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.experimental.ExtModule
22import chisel3.util._
23import xiangshan._
24
25class RfReadPort(dataWidth: Int, addrWidth: Int)(implicit p: Parameters) extends XSBundle {
26  val addr = Input(UInt(addrWidth.W))
27  val data = Output(UInt(dataWidth.W))
28}
29
30class RfWritePort(dataWidth: Int, addrWidth: Int)(implicit p: Parameters) extends XSBundle {
31  val wen = Input(Bool())
32  val addr = Input(UInt(addrWidth.W))
33  val data = Input(UInt(dataWidth.W))
34}
35
36class Regfile
37(
38  name: String,
39  numReadPorts: Int,
40  numWritePorts: Int,
41  hasZero: Boolean,
42  len: Int,
43  width: Int,
44)(implicit p: Parameters) extends XSModule {
45  val io = IO(new Bundle() {
46    val readPorts = Vec(numReadPorts, new RfReadPort(len, width))
47    val writePorts = Vec(numWritePorts, new RfWritePort(len, width))
48    val debug_rports = Vec(64, new RfReadPort(len, width))
49  })
50
51  println(name + ": size:" + NRPhyRegs + " read: " + numReadPorts + " write: " + numWritePorts)
52
53  val mem = Reg(Vec(NRPhyRegs, UInt(len.W)))
54  for (r <- io.readPorts) {
55    val rdata = if (hasZero) Mux(r.addr === 0.U, 0.U, mem(r.addr)) else mem(r.addr)
56    r.data := rdata
57  }
58  for (w <- io.writePorts) {
59    when(w.wen) {
60      mem(w.addr) := w.data
61    }
62  }
63
64  for (rport <- io.debug_rports) {
65    val zero_rdata = Mux(rport.addr === 0.U, 0.U, mem(rport.addr))
66    rport.data := (if (hasZero) zero_rdata else mem(rport.addr))
67  }
68}
69
70object Regfile {
71  def apply(
72    name         : String,
73    numEntries   : Int,
74    raddr        : Seq[UInt],
75    wen          : Seq[Bool],
76    waddr        : Seq[UInt],
77    wdata        : Seq[UInt],
78    hasZero      : Boolean,
79    withReset    : Boolean = false,
80    debugReadAddr: Option[Seq[UInt]] = None,
81  )(implicit p: Parameters): Seq[UInt] = {
82    val numReadPorts = raddr.length
83    val numWritePorts = wen.length
84    require(wen.length == waddr.length)
85    require(wen.length == wdata.length)
86    val dataBits = wdata.map(_.getWidth).min
87    require(wdata.map(_.getWidth).min == wdata.map(_.getWidth).max, s"dataBits != $dataBits")
88    val addrBits = waddr.map(_.getWidth).min
89    require(waddr.map(_.getWidth).min == waddr.map(_.getWidth).max, s"addrBits != $addrBits")
90
91    val regfile = Module(new Regfile(name, numReadPorts, numWritePorts, hasZero, dataBits, addrBits))
92    val rdata = regfile.io.readPorts.zip(raddr).map { case (rport, addr) =>
93      rport.addr := addr
94      rport.data
95    }
96
97    regfile.io.writePorts.zip(wen).zip(waddr).zip(wdata).foreach{ case (((wport, en), addr), data) =>
98      wport.wen := en
99      wport.addr := addr
100      wport.data := data
101    }
102    if (withReset) {
103      val numResetCycles = math.ceil(numEntries / numWritePorts).toInt
104      val resetCounter = RegInit(numResetCycles.U)
105      val resetWaddr = RegInit(VecInit((0 until numWritePorts).map(_.U(log2Up(numEntries + 1).W))))
106      val inReset = resetCounter =/= 0.U
107      when (inReset) {
108        resetCounter := resetCounter - 1.U
109        resetWaddr := VecInit(resetWaddr.map(_ + numWritePorts.U))
110      }
111      when (!inReset) {
112        resetWaddr.map(_ := 0.U)
113      }
114      for ((wport, i) <- regfile.io.writePorts.zipWithIndex) {
115        wport.wen := inReset || wen(i)
116        wport.addr := Mux(inReset, resetWaddr(i), waddr(i))
117        wport.data := wdata(i)
118      }
119    }
120    regfile.io.debug_rports := DontCare
121    val debug_rdata = regfile.io.debug_rports.zip(debugReadAddr.getOrElse(Seq())).map { case (rport, addr) =>
122      rport.addr := addr
123      rport.data
124    }
125    rdata ++ debug_rdata
126  }
127}
128
129object IntRegFile {
130  def apply(
131    name         : String,
132    numEntries   : Int,
133    raddr        : Seq[UInt],
134    wen          : Seq[Bool],
135    waddr        : Seq[UInt],
136    wdata        : Seq[UInt],
137    withReset    : Boolean = false,
138    debugReadAddr: Option[Seq[UInt]] = None,
139  )(implicit p: Parameters): Seq[UInt] = {
140    Regfile(
141      name, numEntries, raddr, wen, waddr, wdata,
142      hasZero = true, withReset, debugReadAddr)
143  }
144}
145
146object VfRegFile {
147  def apply(
148    name         : String,
149    numEntries   : Int,
150    splitNum     : Int,
151    raddr        : Seq[UInt],
152    wen          : Seq[Seq[Bool]],
153    waddr        : Seq[UInt],
154    wdata        : Seq[UInt],
155    withReset    : Boolean = false,
156    debugReadAddr: Option[Seq[UInt]] = None,
157  )(implicit p: Parameters) : Seq[UInt] = {
158    require(splitNum >= 1, "splitNum should be no less than 1")
159    require(splitNum == wen.length, "splitNum should be equal to length of wen vec")
160    if (splitNum == 1) {
161      Regfile(name, numEntries, raddr, wen.head, waddr, wdata,
162        hasZero = false, withReset, debugReadAddr)
163    } else {
164      val dataWidth = 64
165      val numReadPorts = raddr.length + debugReadAddr.getOrElse(Seq()).length
166      require(splitNum > 1 && wdata.head.getWidth == dataWidth * splitNum)
167      val wdataVec = Wire(Vec(splitNum, Vec(wdata.length, UInt(dataWidth.W))))
168      var rdataVec = Wire(Vec(splitNum, Vec(numReadPorts, UInt(dataWidth.W))))
169      for (i <- 0 until splitNum) {
170        wdataVec(i) := wdata.map(_((i + 1) * dataWidth - 1, i * dataWidth))
171        rdataVec(i) := Regfile(name+s"Part${i}", numEntries, raddr, wen(i), waddr, wdataVec(i),
172          hasZero = false, withReset, debugReadAddr)
173      }
174      val rdata = Wire(Vec(numReadPorts, UInt(wdata.head.getWidth.W)))
175      for (i <- 0 until rdata.length) {
176        rdata(i) := Cat(rdataVec.map(_(i)).reverse)
177      }
178      rdata
179    }
180  }
181
182//  // for dummy usage
183//  def apply(
184//    numEntries   : Int,
185//    raddr        : Vec[UInt],
186//    wen          : Vec[Bool],
187//    waddr        : Vec[UInt],
188//    wdata        : Vec[UInt],
189//    withReset    : Boolean = false,
190//    debugReadAddr: Option[Vec[UInt]] = None,
191//  )(implicit p: Parameters) : Unit = {
192//    Regfile(numEntries, raddr, wen, waddr, wdata,
193//      hasZero = false, withReset, debugReadAddr)
194//  }
195}
196