集成电路流片随笔7:ROM模块的学习tinyriscv

ROM (只读存储器) 模块:实现了一个简单的内存模型,其中可以存储数据并且可以读取数据。


1. 输入输出端口:

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             // 读取的数据
  • clkrst:时钟和复位信号,用于同步电路的操作。
  • we_i:写使能信号,用于决定是否向 ROM 中写入数据。如果 we_i1,表示要执行写操作。
  • addr_i:地址输入信号,用于指定要访问的 ROM 地址。
  • data_i:要写入 ROM 的数据。
  • data_o:ROM 的输出数据,用于读取指定地址的数据。

2. ROM 存储单元:

reg[`MemBus] _rom[0:`RomNum - 1];
  • _rom:一个 ROM 存储器数组,它用于存储从地址 0RomNum - 1 的数据。_rom 的大小是由 RomNum 参数定义的。

3. 写操作:

always @ (posedge clk) begin
    if (we_i == `WriteEnable) begin
        _rom[addr_i[31:2]] <= data_i;
    end
end
  • 写操作:当 we_iWriteEnable 时(即允许写操作),ROM 会根据传入的地址 (addr_i) 和数据 (data_i) 将数据写入到 _rom 数组中。
  • addr_i[31:2]:地址信号的高 30 位被用作 ROM 数组的索引。由于每个数据单元是 32 位宽(即 4 字节),addr_i[31:2] 去除了最低的两位地址(即对齐到 4 字节的边界),因此地址从 0RomNum - 1 的数据可以有效地映射到 ROM 数组中。

理解 ROM 地址映射时,我们需要理解 字节对齐(byte alignment)的概念,尤其是针对像 ROM 这样的存储器。
为什么我们要使用 addr_i[31:2] 来做地址映射。

问题背景:

_rom[addr_i[31:2]] <= data_i;

为什么低地址是四字节边界?

  1. ROM 中每个数据单元大小是 32 位,即每个数据单元占 4 字节
  2. 在计算机中,内存的 字节对齐 是一种优化方式,要求数据按照其大小对齐到特定的边界。在这种情况下,32 位数据(4 字节)通常对齐到 4 字节边界。换句话说,每次读写操作都需要访问 4 字节对齐的地址。

解释地址映射的步骤:

  • addr_i[31:2]:在 Verilog 中,addr_i 是一个 32 位地址,而每个数据单元是 4 字节(32 位)。因为 addr_i 的最低两位(addr_i[1:0])对应的是 字节偏移,对于 4 字节对齐的地址,最低的两位一定为 00,所以我们只需要关注 高 30 位addr_i[31:2])来索引 ROM 中的数据。

    • 低两位的作用:例如,地址 0x00000000 对应 ROM[0],而地址 0x000000010x000000020x00000003 都不能单独访问 32 位数据单元,因为它们不满足 4 字节对齐的要求。通过 addr_i[31:2],我们实际上在访问的是按 4 字节边界对齐的地址。
  • 为什么要去掉低两位?:由于每个数据单元是 4 字节,所以我们不需要关心地址的低两位。通过将地址的低两位丢弃,我们确保访问的是 4 字节对齐的地址。

    • 例如,地址 0x00000000 映射到 ROM 的索引 0(_rom[0])。
    • 地址 0x00000004 映射到 ROM 的索引 1(_rom[1])。
    • 地址 0x00000008 映射到 ROM 的索引 2(_rom[2])。
    • 依此类推……
  • ROM 数组的索引:所以,实际上存储器数组 _rom 以 4 字节为单位来存储数据。当访问地址时,我们需要将 32 位的地址 addr_i 按 4 字节对齐来映射到 ROM 中的单元,这就是通过 addr_i[31:2] 来实现的。

更清楚的例子:

假设 RomNum 定义为 256,那么地址范围将从 0x000000000x000003FF(即 256 个 32 位数据单元)。每个数据单元占 4 字节,所以我们需要去除地址的低两位,确保访问的是每 4 字节一个单元的结构。(0x表示16进制。)
例如:

  • 地址 0x00000000 映射到 _rom[0]
  • 地址 0x00000004 映射到 _rom[1]
  • 地址 0x00000008 映射到 _rom[2]
  • 地址 0x000003FF 映射到 _rom[255]

总结:

  • 由于每个数据单元是 32 位(4 字节),为了访问对齐的内存块,地址的最低两位(addr_i[1:0])必须为 00。
  • 因此,通过 addr_i[31:2] 来计算 ROM 中的数据单元索引,去掉最低的两位地址。
  • 这样做确保了访问的内存是 4 字节对齐 的。

4. 读操作:

always @ (*) begin
    if (rst == `RstEnable) begin
        data_o = `ZeroWord;
    end else begin
        data_o = _rom[addr_i[31:2]];
    end
end
  • 读操作:该 always 块是一个组合逻辑块,它在任何信号变化时都会被触发。
  • 如果 复位信号 rst 为有效(RstEnable),则输出的数据 data_o 被设置为 ZeroWord,即 0
  • 如果没有复位,则根据传入的地址 addr_i,从 _rom 数组中读取对应位置的数据,并将其输出到 data_o

可能的修改/扩展:

  • ROM 的初始化:当前 ROM 是空的,如果需要在仿真或硬件中加载预设数据,可以在初始化阶段填充 _rom 数组(比如通过一个初始化文件或者将数据直接嵌入到代码中)。
  • 大小限制:目前 ROM 数组的大小是由 RomNum 定义的,可以根据需要调整其大小。如果 ROM 的数据量较大,还需要考虑是否需要在硬件设计中支持更多的存储单元。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值