RAM(随机存取存储器)模块,它与 ROM 模块非常相似,功能是存储和读取数据。
模块端口说明:
module ram(
input wire clk, // 时钟信号
input wire rst, // 复位信号
input wire we_i, // 写使能信号
input wire[`MemAddrBus] addr_i, // 地址输入信号
input wire[`MemBus] data_i, // 写入数据
output reg[`MemBus] data_o // 输出读取的数据
);
clk
:时钟信号,用于同步操作。rst
:复位信号,通常用于初始化 RAM 内容或清除 RAM。we_i
:写使能信号,控制是否允许向 RAM 写入数据。如果为1
,则执行写操作;如果为0
,则不进行写操作。addr_i
:32 位的地址信号,用于指定 RAM 中存储单元的地址。通常使用这个信号来选择 RAM 中的数据存储位置。data_i
:要写入 RAM 的数据。data_o
:从 RAM 读取的数据输出。
RAM 存储单元:
reg[`MemBus] _ram[0:`MemNum - 1];
_ram
是一个 数组,用于存储 RAM 中的数据。MemBus
是存储单元的大小(通常是 32 位,即 4 字节),MemNum
表示 RAM 的深度(即存储单元的数量)。_ram[0:
MemNum - 1]定义了一个包含
MemNum个元素的数组,每个元素是
MemBus` 宽度的寄存器。
写操作:
always @ (posedge clk) begin
if (we_i == `WriteEnable) begin
_ram[addr_i[31:2]] <= data_i;
end
end
- 这个
always
块在每个时钟上升沿触发。 we_i == WriteEnable
:如果写使能信号为WriteEnable
(即we_i
为1
),则执行写操作。addr_i[31:2]
:这是地址信号。这里使用了addr_i[31:2]
来去除地址的最低两位。由于每个存储单元是 32 位(4 字节),最低两位代表地址中的字节偏移。通过去除最低两位,我们确保地址是按照 32 位对齐 来访问存储单元的。- 举个例子,地址
0x00000000
对应_ram[0]
,地址0x00000004
对应_ram[1]
,依此类推。
- 举个例子,地址
- 如果
we_i
为1
,则 写入数据 (data_i
) 到_ram[addr_i[31:2]]
指定的地址位置。
读操作:
always @ (*) begin
if (rst == `RstEnable) begin
data_o = `ZeroWord;
end else begin
data_o = _ram[addr_i[31:2]];
end
end
- 这个
always
块是一个组合逻辑块,任何信号变化时都会触发。 - 复位逻辑:如果
rst
信号为RstEnable
,则输出数据data_o
被设置为ZeroWord
(通常是0
)。这意味着如果系统复位,RAM 输出的数据会被清零。 - 读取数据:如果没有复位,则根据 地址
addr_i
读取指定位置的数据_ram[addr_i[31:2]]
并将其输出到data_o
。
总结:
- 这个 RAM 模块实现了 读写操作,支持根据地址对 RAM 存储单元进行读取和写入。
- 地址映射:由于每个存储单元是 32 位(4 字节),通过去除地址的最低两位(
addr_i[31:2]
),确保地址访问是 4 字节对齐的。 - 写操作:只有在
we_i ==
WriteEnable时,数据才会被写入到
_ram` 数组的指定位置。 - 读操作:读取时,通过
addr_i[31:2]
映射到 RAM 中的存储单元,并将数据输出。
这段代码实现了一个简单的、基于地址映射的 RAM 模块,适用于存储和读取 32 位宽的数据。