第10课 · 存储器
SRAMROM读写初始化
📌 学习目标:实现 SRAM(同步读写存储器)和 ROM(只读存储器),掌握 Verilog 存储器建模方法,通过 Verilator 验证读写和初始化功能。
一、存储器概述
存储器是计算机中用于存储数据和程序的部件。根据读写特性分为:
| 类型 | 读 | 写 | 挥发性 | 用途 |
| SRAM | ✅ | ✅ | 易失 | Cache、寄存器文件 |
| DRAM | ✅ | ✅ | 易失 | 主存 |
| ROM | ✅ | ❌ | 非易失 | 固件、启动代码 |
| Flash | ✅ | ✅(慢) | 非易失 | SSD、BIOS |
二、SRAM 原理
SRAM(Static Random-Access Memory)使用 6 个晶体管构成的双稳态触发器存储 1 位数据。
2.1 SRAM 特点
- 速度快(1-10ns)
- 不需要刷新
- 面积大、功耗高
- 用于 CPU Cache(L1/L2/L3)
2.2 SRAM 读写时序
| 操作 | cs | we | 地址 | 数据 |
| 读 | 1 | 0 | 有效 | dout ← mem[addr] |
| 写 | 1 | 1 | 有效 | mem[addr] ← din |
| 未选 | 0 | X | X | dout 高阻 |
三、ROM 原理
ROM(Read-Only Memory)在制造时写入数据,运行时只读。在 FPGA 中用初始化文件或 case 语句实现。
四、Verilog 实现
module sram #(parameter DEPTH=16, WIDTH=8) (
input clk,
input we,
input [$clog2(DEPTH)-1:0] addr,
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
reg [WIDTH-1:0] mem [0:DEPTH-1];
assign dout = mem[addr];
always @(posedge clk) begin
if (we)
mem[addr] <= din;
end
endmodule
module rom #(parameter DEPTH=16, WIDTH=8) (
input [$clog2(DEPTH)-1:0] addr,
output [WIDTH-1:0] dout
);
reg [WIDTH-1:0] mem [0:DEPTH-1];
initial begin
mem[0] = 8'h00; mem[1] = 8'h11;
mem[2] = 8'h22; mem[3] = 8'h33;
mem[4] = 8'h44; mem[5] = 8'h55;
mem[6] = 8'h66; mem[7] = 8'h77;
mem[8] = 8'h88; mem[9] = 8'h99;
mem[10] = 8'hAA; mem[11] = 8'hBB;
mem[12] = 8'hCC; mem[13] = 8'hDD;
mem[14] = 8'hEE; mem[15] = 8'hFF;
end
assign dout = mem[addr];
endmodule
4.1 测试台
module tb_memory;
reg clk, we;
reg [3:0] addr;
reg [7:0] din;
wire [7:0] sram_dout, rom_dout;
sram #(.DEPTH(16), .WIDTH(8)) u_sram (
.clk(clk), .we(we), .addr(addr), .din(din), .dout(sram_dout)
);
rom #(.DEPTH(16), .WIDTH(8)) u_rom (
.addr(addr), .dout(rom_dout)
);
integer pass = 0, fail = 0;
always #5 clk = ~clk;
initial begin
clk = 0; we = 0; addr = 0; din = 0;
#1;
for (integer i = 0; i < 16; i = i + 1) begin
addr = i; #1;
if (rom_dout !== (i * 8'h11)) begin
$display("FAIL ROM[%0d]: got %h exp %h", i, rom_dout, i*8'h11);
fail = fail + 1;
end else pass = pass + 1;
end
we = 1;
for (integer i = 0; i < 16; i = i + 1) begin
addr = i; din = i + 8'hA0; #10;
end
we = 0;
for (integer i = 0; i < 16; i = i + 1) begin
addr = i; #1;
if (sram_dout !== (i + 8'hA0)) begin
$display("FAIL SRAM read[%0d]: got %h", i, sram_dout);
fail = fail + 1;
end else pass = pass + 1;
end
we = 1; addr = 5; din = 8'hFF; #10;
we = 0; addr = 5; #1;
if (sram_dout !== 8'hFF) begin
$display("FAIL SRAM overwrite: got %h", sram_dout); fail=fail+1;
end else pass=pass+1;
$display("========================================");
$display("存储器测试: PASS=%0d FAIL=%0d", pass, fail);
if (fail == 0) $display("✅ SRAM读写+ROM初始化验证通过!");
else $display("❌ 存在失败!");
$display("========================================");
$finish;
end
endmodule
五、Verilator 编译命令
verilator --cc memory.v --exe tb_memory.v \
--build --top-module tb_memory
./obj_dir/Vtb_memory
六、存储器层次结构
┌─────────────────────────┐
│ CPU 寄存器 (x0-x31) │ ← 最快 (~0.3ns, ~1KB)
├─────────────────────────┤
│ L1 Cache (SRAM) │ ← 快 (~1ns, 32-64KB)
├─────────────────────────┤
│ L2 Cache (SRAM) │ ← 中等 (~5ns, 256KB-1MB)
├─────────────────────────┤
│ L3 Cache (SRAM) │ ← 较慢 (~10ns, 4-32MB)
├─────────────────────────┤
│ 主存 (DRAM) │ ← 慢 (~50ns, GB级)
├─────────────────────────┤
│ SSD (Flash) │ ← 很慢 (~100μs)
├─────────────────────────┤
│ HDD (磁盘) │ ← 最慢 (~10ms)
└─────────────────────────┘
locality principle:程序倾向于访问最近访问过的数据及其附近的数据。
🤔 思考题:为什么 SRAM 用 6 个晶体管而 DRAM 只用 1 个晶体管+1 个电容?SRAM 为什么不需要刷新?
💡 提示:SRAM 是正反馈双稳态电路(自保持),DRAM 是电容存储(会漏电需刷新)
🏆 成就解锁:存储器架构师
✅ Verilator 仿真验证通过
✅ SRAM 同步写、异步读验证正确
✅ ROM 初始化数据读取验证正确
✅ SRAM 覆盖写入验证正确
🎯 下一目标:RISC-V 指令集 → 第11课:RV32I 基础