代码整体如下
class RegisterFile(readPorts: Int) extends Module {
require(readPorts >= 0)
val io = IO(new Bundle {
val wen = Input(Bool())
val waddr = Input(UInt(5.W))
val wdata = Input(UInt(32.W))
val raddr = Input(Vec(readPorts, UInt(5.W)))
val rdata = Output(Vec(readPorts, UInt(32.W)))
})
// A Register of a vector of UInts
val reg = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))
when (io.wen) {
reg(io.waddr) := io.wdata
}
for (i <- 0 until readPorts) {
when (io.raddr(i) === 0.U) {
io.rdata(i) := 0.U
} .otherwise {
io.rdata(i) := reg(io.raddr(i))
}
}
}
代码定义了一个名为 RegisterFile
的类,Chisel 模块,用于创建一个寄存器文件。下面对每一行代码的逐行解释:
class RegisterFile(readPorts: Int) extends Module {
定义了一个名为 RegisterFile
的类,它接受一个整数参数 readPorts
作为构造函数的输入,表示这个寄存器文件将支持的读端口数量。这个类继承自 Chisel 的 Module
类,意味着它是一个硬件模块。
require(readPorts >= 0)
使用 Chisel 的 require
方法来确保 readPorts
参数是非负的。如果 readPorts
是负数,Chisel 会在编译时抛出一个错误。
val io = IO(new Bundle {
// Bundle 定义了模块的输入输出端口
val wen = Input(Bool()) // 写使能信号,布尔类型
val waddr = Input(UInt(5.W)) // 写地址,无符号整数类型,宽度为5位
val wdata = Input(UInt(32.W)) // 写数据,无符号整数类型,宽度为32位
val raddr = Input(Vec(readPorts, UInt(5.W))) // 读地址,一个包含 `readPorts` 个5位宽无符号整数的向量
val rdata = Output(Vec(readPorts, UInt(32.W))) // 读数据,一个包含 `readPorts` 个32位宽无符号整数的向量
})
定义了模块的 io
对象,它是 RegisterFile
的接口。io
使用 Bundle
对象来定义一组端口,包括:
wen
:写使能信号,当它为真时允许写操作。waddr
:写操作的目标地址。wdata
:要写入的数据。raddr
:一个向量,包含多个读地址(数量由readPorts
参数决定)。rdata
:一个向量,包含从不同地址读出的数据(数量由readPorts
参数决定)。
val reg = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))
在模块内部声明了一个 reg
变量,它是一个寄存器向量,初始化为包含32个元素,每个元素都是宽度为32位的无符号整数,初始值都为0。RegInit
是 Chisel 中用于初始化寄存器的方法。
when (io.wen) { reg(io.waddr) := io.wdata }
这是一个条件语句,当 wen
为真时执行写操作。它将 wdata
的值赋给 reg
向量中 waddr
索引对应的元素。
for (i <- 0 until readPorts) {
开始一个 for 循环,循环变量 i
从0开始,直到 readPorts
(不包括 readPorts
)。
when (io.raddr(i) === 0.U) { io.rdata(i) := 0.U } .otherwise { io.rdata(i) := reg(io.raddr(i)) } }
在 for 循环内部,使用 when
和 .otherwise
来处理每个读端口的读操作。对于索引 i
对应的读地址 io.raddr(i)
:
- 如果读地址是0,则将对应输出端口
io.rdata(i)
置为0。 - 否则,将
reg
向量中io.raddr(i)
索引对应的值赋给io.rdata(i)
。
这个模块实现了一个简单的寄存器文件,支持多个读操作和单个写操作。写操作仅在写使能为真时发生,而读操作则可以并行进行,并且每个读端口可以读取不同的寄存器值。如果读地址为0,则输出0,否则输出寄存器中相应地址的值。