编程语言
存储设备:RAM 静态随机存取存储器(SRAM)芯片及异步 SRAM 特性与 HDL 读写测试
介绍 RAM 类型对比,重点讲解异步 SRAM(如 CY7C1041CV33)的特性与控制信号。详细阐述了写操作、读操作及高阻态机制,并提供了基于 Verilog 的 SRAM 控制器模块设计,包含状态机逻辑和三态总线处理。此外,给出了 Testbench 测试激励及读写验证流程,确保 FPGA 设计中异步 SRAM 接口的时序满足要求。

介绍 RAM 类型对比,重点讲解异步 SRAM(如 CY7C1041CV33)的特性与控制信号。详细阐述了写操作、读操作及高阻态机制,并提供了基于 Verilog 的 SRAM 控制器模块设计,包含状态机逻辑和三态总线处理。此外,给出了 Testbench 测试激励及读写验证流程,确保 FPGA 设计中异步 SRAM 接口的时序满足要求。

| 类型 | 全称 | 特点 | 应用 |
|---|---|---|---|
| SRAM | Static RAM(静态 RAM) | - 6 晶体管结构 - 无需刷新 - 速度快、功耗高、成本高 | CPU 缓存、FPGA 片外高速缓存 |
| DRAM | Dynamic RAM(动态 RAM) | - 1 晶体管 + 1 电容 - 需定期刷新(~64ms) - 速度较慢、密度高、成本低 | 计算机主内存(DDR4/DDR5) |
| 典型异步型号 | 容量 | 位宽 | 封装 | 应用场景 |
|---|---|---|---|---|
| CY7C1041CV33 | 512KB (256K × 16) | 16-bit | TSOPII-54 | 汽车电子、工业控制 |
| IS61LV25616AL | 512KB (256K × 16) | 16-bit | TSOP-44 | FPGA 开发板(如 DE2) |
| AS6C62256 | 32KB (32K × 8) | 8-bit | DIP/SOP | 嵌入式小系统 |
| 71V424 | 512KB (512K × 8) | 8-bit | TSOP | 网络设备缓存 |
| 类型 | 是否需时钟 | 刷新 | 访问延迟 | 控制复杂度 | 典型用途 |
|---|---|---|---|---|---|
| 异步 SRAM | 否 | 不需 | 极低(ns 级) | 简单 | 高速缓存、状态机存储 |
| 同步 SRAM (SSRAM) | 是 | 不需 | 低(1~2 CLK) | 中等 | 高带宽嵌入式系统 |
| SDRAM | 是 | 需定期刷新 | 较高(含潜伏期) | 复杂 | 主存(PC、手机) |
| 特性 | 说明 |
|---|---|
| 无需刷新 | 静态存储单元(6T 结构),只要通电数据就保持 |
| 无时钟依赖 | 所有操作由控制信号电平决定,响应快 |
| 确定性延迟 | 从地址稳定到数据有效的时间固定(如 t = 10 ns) |
| 高速访问 | 典型访问时间 8–15 ns,远快于 DRAM |
| 高功耗 & 高成本 | 单元面积大,不适合大容量主存 |
| 三态数据总线 | 支持多设备共享总线(高阻态隔离) |
| 信号 | 功能 |
|---|---|
| CE | 芯片使能:LOW 表示选中芯片 |
| WE | 写使能:LOW 表示写操作 |
| OE | 输出使能:LOW 表示允许读出数据 |
| BLE | 低字节使能:LOW 表示操作 I/O0–I/O7 |
| BHE | 高字节使能:LOW 表示操作 I/O8–I/O15 |
这段 Verilog 代码实现了一个异步 SRAM(CY7C1041CV33,512KB×16 位)的控制器模块,核心作用是对接 CPU/FIFO 等上层逻辑与物理 SRAM 芯片:
// sram_controller.v // 注:CY7C1041CV33 是异步 SRAM 芯片,容量 512KB 字节(按 16 位宽算,共 2^18=262144 个存储单元); 前提假设:系统时钟频率足够高,能满足 SRAM 的时序要求(如地址访问时间 tAA、写周期 tWC) // 模块定义,带参数化配置(方便适配不同规格 SRAM) module sram_controller #( parameter ADDR_WIDTH = 18, // 地址位宽:2^18=262144 个存储单元,对应 512KB(512×1024) parameter DATA_WIDTH = 16 // 数据位宽:16 位(与 SRAM 的 16 位宽匹配) )( // 时钟与复位 input clk, // 系统时钟(控制器同步时钟) input rst_n, // 低电平有效的异步复位 // CPU/FIFO 上层接口(控制器的输入/输出) input req, // 读写请求有效信号(高电平表示有请求) input wr_en, // 写使能:1=写操作,0=读操作 input [ADDR_WIDTH-1:0] addr, // 读写地址 input [DATA_WIDTH-1:0] wdata, // 写数据(CPU/FIFO→SRAM) output reg [DATA_WIDTH-1:0] rdata, // 读数据(SRAM→CPU/FIFO) input byte_sel_low, // 低字节选择:1=操作低 8 位(I/O0-7) input byte_sel_high, // 高字节选择:1=操作高 8 位(I/O8-15) output reg ack, // 应答有效信号:高电平表示操作完成 // SRAM 物理引脚接口(直接连接 SRAM 芯片) output reg [ADDR_WIDTH-1:0] sram_addr, // SRAM 地址线 inout [DATA_WIDTH-1:0] sram_dq, // SRAM 双向数据总线(关键:inout 类型) output reg sram_ce_n, // SRAM 片选(低有效) output reg sram_oe_n, // SRAM 读使能(低有效) output reg sram_we_n, // SRAM 写使能(低有效) output reg sram_ble_n, // SRAM 低字节使能(低有效,对应 I/O0-7) output reg sram_bhe_n // SRAM 高字节使能(低有效,对应 I/O8-15) ); // Tri-state data bus:三态数据总线控制(核心!处理双向总线) // 逻辑:只有写操作、片选有效、写使能有效时,才把 wdata 输出到 sram_dq;否则总线置高阻(z) assign sram_dq = (wr_en && !sram_ce_n && !sram_we_n) ? wdata : {DATA_WIDTH{1'bz}}; // Internal state (simple 2-cycle: setup + access):内部状态机定义(简单 2 周期:建立 + 访问) reg [1:0] state; // 状态寄存器(2 位足够表示 3 个状态) // 状态常量定义(提高代码可读性) localparam IDLE = 2'b00, // 空闲态:无请求,所有 SRAM 控制信号置无效 SETUP = 2'b01, // 建立态:锁存地址、字节选择,置位片选和读写使能 ACCESS = 2'b10; // 访问态:读操作锁存数据,置位应答,完成一次交易 // 时序逻辑:状态机核心(时钟上升沿/复位下降沿触发) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin // 异步复位(低有效):所有信号置初始态 state <= IDLE; // 回到空闲态 ack <= 0; // 应答无效 sram_ce_n <= 1'b1; // 片选无效(高) sram_oe_n <= 1'b1; // 读使能无效(高) sram_we_n <= 1'b1; // 写使能无效(高) sram_ble_n <= 1'b1; // 低字节使能无效(高) sram_bhe_n <= 1'b1; // 高字节使能无效(高) sram_addr <= 0; // 地址置 0 end else begin // 非复位状态:状态机逻辑 ack <= 0; // 先默认应答无效(避免锁存,仅在 ACCESS 态置 1) case (state) IDLE: begin // 空闲态:等待请求 // 空闲态下,所有 SRAM 控制信号置无效(防止误操作) sram_ce_n <= 1'b1; sram_oe_n <= 1'b1; sram_we_n <= 1'b1; sram_ble_n <= 1'b1; sram_bhe_n <= 1'b1; // 检测到有效请求(req=1),进入建立态 if (req) begin sram_addr <= addr; // 锁存上层输入的地址 sram_ble_n <= ~byte_sel_low; // 字节使能:低有效,所以取反(sel=1→ble_n=0) sram_bhe_n <= ~byte_sel_high;// 同理,高字节选择→bhe_n 置低 state <= SETUP; // 进入建立态 end end SETUP: begin // 建立态:配置 SRAM 控制信号,为读写做准备 // Address and enables are already set:地址和字节使能已在 IDLE→SETUP 时锁存 // Assert CE and direction-specific enables:置位片选,并区分读写使能 sram_ce_n <= 1'b0; // 片选有效(低):选中 SRAM 芯片 if (wr_en) begin // 写操作 sram_we_n <= 1'b0; // 写使能有效(低) sram_oe_n <= 1'b1; // 读使能无效(避免读写冲突) end else begin // 读操作 sram_we_n <= 1'b1; // 写使能无效 sram_oe_n <= 1'b0; // 读使能有效(低) end state <= ACCESS; // 进入访问态 end ACCESS: begin // 访问态:完成读写,置位应答 // Sample read data or hold write data:读操作锁存数据,写操作保持数据 if (~wr_en) begin // 仅读操作时 rdata <= sram_dq; // 锁存 SRAM 输出的读数据到 rdata end ack <= 1'b1; // 应答有效:告知上层本次操作完成 state <= IDLE;// 回到空闲态,等待下一次请求 end default: state <= IDLE; // 异常状态:回到空闲态(提高鲁棒性) endcase end end endmodule
inout 类型表示;wdata 驱动到 sram_dq;读 SRAM 时,sram_dq 置高阻(z),由 SRAM 驱动数据;(wr_en && !sram_ce_n && !sram_we_n) 确保只有'写操作 + 片选有效 + 写使能有效'时才输出数据,避免总线冲突。`timescale 1ns / 1ps module sram_controller_tb; // ====================== 1. 参数定义 ====================== parameter ADDR_WIDTH = 18; parameter DATA_WIDTH = 16; parameter CLK_PERIOD = 20; // 50 MHz // ====================== 2. 信号声明 ====================== reg clk; reg rst_n; reg req; reg wr_en; reg [ADDR_WIDTH-1:0] addr; reg [DATA_WIDTH-1:0] wdata; reg byte_sel_low; reg byte_sel_high; wire [DATA_WIDTH-1:0] rdata; wire ack; wire [ADDR_WIDTH-1:0] sram_addr; wire [DATA_WIDTH-1:0] sram_dq; wire sram_ce_n; wire sram_oe_n; wire sram_we_n; wire sram_ble_n; wire sram_bhe_n; // SRAM 行为模型存储 reg [7:0] sram_mem [0:(1<<ADDR_WIDTH)-1][1:0]; // [addr][0=low, 1=high] reg [DATA_WIDTH-1:0] sram_dq_out; // ====================== 3. 时钟生成 ====================== initial begin clk = 1'b0; forever #(CLK_PERIOD/2) clk = ~clk; end // ====================== 4. 实例化 DUT ====================== sram #( .ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(DATA_WIDTH) ) u_dut ( .clk(clk), .rst_n(rst_n), .req(req), .wr_en(wr_en), .addr(addr), .wdata(wdata), .byte_sel_low(byte_sel_low), .byte_sel_high(byte_sel_high), .ack(ack), .rdata(rdata), .sram_addr(sram_addr), .sram_dq(sram_dq), .sram_ce_n(sram_ce_n), .sram_oe_n(sram_oe_n), .sram_we_n(sram_we_n), .sram_ble_n(sram_ble_n), .sram_bhe_n(sram_bhe_n) ); // ====================== 5. SRAM 行为模型 ====================== assign sram_dq = (!sram_ce_n && !sram_oe_n && sram_we_n) ? sram_dq_out : {DATA_WIDTH{1'bz}}; // 写操作:在 WE_n 下降沿锁存数据(按字节使能) always @(negedge sram_we_n or negedge rst_n) begin if (!rst_n) begin // 初始化数据 // integer i, j; // for (i = 0; i < (1 << ADDR_WIDTH); i = i + 1) begin // sram_mem[i][0] = 8'h00; // sram_mem[i][1] = 8'h00; // end end else if (!sram_ce_n) begin if (!sram_ble_n) sram_mem[sram_addr][0] = sram_dq[7:0]; if (!sram_bhe_n) sram_mem[sram_addr][1] = sram_dq[15:8]; end end // 读操作:在 OE_n 下降沿输出数据 always @(negedge sram_oe_n or negedge rst_n) begin if (!rst_n) begin sram_dq_out <= {DATA_WIDTH{1'b0}}; end else if (!sram_ce_n) begin sram_dq_out <= {16{1'b0}}; if (!sram_ble_n) sram_dq_out[7:0] <= sram_mem[sram_addr][0]; if (!sram_bhe_n) sram_dq_out[15:8] <= sram_mem[sram_addr][1]; end end // ====================== 6. 单次写入测试激励 ====================== initial begin // 初始化 rst_n = 1'b0; req = 1'b0; wr_en = 1'b0; addr = 0; wdata = 0; byte_sel_low = 1'b0; byte_sel_high = 1'b0; // 复位保持 2 个周期 repeat(2) @(posedge clk); rst_n = 1'b1; // === 单次写入:地址 0x1000,数据 0xABCD,全字节 === @(posedge clk); req = 1'b1; wr_en = 1'b1; addr = 18'h1000; wdata = 16'hABCD; byte_sel_low = 1'b1; // 使能低字节 byte_sel_high = 1'b1; // 使能高字节 wait(ack == 1'b1); // 等待写完成 @(posedge clk); req = 1'b0; // 撤销请求 // 仿真再跑几个周期以便观察波形 repeat(5) @(posedge clk); $finish; end endmodule
sram_mem[地址][0/1] 模拟 SRAM 存储阵列(0=低字节,1=高字节),支持按字节读写;sram_dq 处理:读操作时 SRAM 输出数据(sram_dq_out),写操作时 SRAM 接收数据并存储;sram_we_n(写使能)和 sram_oe_n(读使能)的低电平有效信号,模拟真实 SRAM 的读写时序。req:发起一次访问wr_en:1=写,0=读addr:18 位地址(A0–A17)wdata:要写入的数据(16 位)byte_sel_low/high:控制是否操作低/高字节(类似 ARM 的 strb)ack:操作完成标志(单周期脉冲)rdata:读取的数据(仅在读操作有效)_n 信号为低有效(符合芯片手册)sram_dq 为双向三态总线// 新增延时计数器参数 parameter WAIT_CYCLES = 2; // 可配置等待周期,适配不同 SRAM 时序 reg [3:0] wait_cnt; // 延时计数器 // 在 SETUP 态后增加 WAIT 态,计数器减到 0 再进入 ACCESS 态 localparam IDLE=0, SETUP=1, WAIT=2, ACCESS=3; always @(posedge clk) begin if(state == WAIT) begin wait_cnt <= wait_cnt - 1'b1; if(wait_cnt == 0) state <= ACCESS; end end
sram 控制器,自动生成 一次写操作(地址 0,数据 0x1234) ,紧接着执行 一次读操作(地址 0) ,将读回的数据输出到顶层端口(便于仿真观察)。SRAM 是易失性、无内部状态机的存储器,只要能正确完成'写入 → 读出 → 数据比对'流程,基本可判定芯片功能完好。// sramt.v // Top-level module to perform: WRITE(addr=0, data=0x1234) → READ(addr=0) // 模块 sramt 实现(先写后读地址 0) Uses the provided 'sram' controller module sramt ( input clk, input rst_n, // Debug output: read-back data from address 0 output reg [15:0] final_rdata, output reg done // High when both write and read are complete ); parameter ADDR_WIDTH = 18; parameter DATA_WIDTH = 16; // Internal signals for sram controller interface reg req; reg wr_en; reg [ADDR_WIDTH-1:0] addr; reg [DATA_WIDTH-1:0] wdata; reg byte_sel_low; reg byte_sel_high; wire [DATA_WIDTH-1:0] rdata; wire ack; // SRAM physical pins (not exposed at top level) wire [ADDR_WIDTH-1:0] sram_addr; wire [DATA_WIDTH-1:0] sram_dq; wire sram_ce_n; wire sram_oe_n; wire sram_we_n; wire sram_ble_n; wire sram_bhe_n; // State machine for test sequence typedef enum logic [1:0] { IDLE_ST, WRITE_REQ, WAIT_WRITE_ACK, READ_REQ, WAIT_READ_ACK, FINISHED } test_state_t; test_state_t test_state; // Instantiate the sram controller sram #( .ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(DATA_WIDTH) ) u_sram ( .clk(clk), .rst_n(rst_n), .req(req), .wr_en(wr_en), .addr(addr), .wdata(wdata), .byte_sel_low(byte_sel_low), .byte_sel_high(byte_sel_high), .rdata(rdata), .ack(ack), .sram_addr(sram_addr), .sram_dq(sram_dq), .sram_ce_n(sram_ce_n), .sram_oe_n(sram_oe_n), .sram_we_n(sram_we_n), .sram_ble_n(sram_ble_n), .sram_bhe_n(sram_bhe_n) ); // Test control logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin test_state <= IDLE_ST; req <= 1'b0; wr_en <= 1'b0; addr <= 18'd0; wdata <= 16'd0; byte_sel_low <= 1'b0; byte_sel_high <= 1'b0; final_rdata <= 16'd0; done <= 1'b0; end else begin req <= 1'b0; // default deassert request case (test_state) IDLE_ST: begin if (rst_n) begin test_state <= WRITE_REQ; end end WRITE_REQ: begin req <= 1'b1; wr_en <= 1'b1; addr <= 18'd0; // Address 0 wdata <= 16'h1234; // Write data byte_sel_low <= 1'b1; // Enable low byte byte_sel_high <= 1'b1; // Enable high byte test_state <= WAIT_WRITE_ACK; end WAIT_WRITE_ACK: begin if (ack) begin test_state <= READ_REQ; end end READ_REQ: begin req <= 1'b1; wr_en <= 1'b0; // Read operation addr <= 18'd0; // Address 0 byte_sel_low <= 1'b1; byte_sel_high <= 1'b1; test_state <= WAIT_READ_ACK; end WAIT_READ_ACK: begin if (ack) begin final_rdata <= rdata; // Capture read data done <= 1'b1; test_state <= FINISHED; end end FINISHED: begin done <= 1'b1; // Hold done high // Stay here forever end default: test_state <= IDLE_ST; endcase end end endmodule
| 特性 | 说明 |
|---|---|
| 目标地址 | 固定为 0(18'd0) |
| 写入数据 | 16'h1234(可修改) |
| 字节使能 | 全字(低 + 高字节都使能) |
| 操作顺序 | 写 → 等待 ack → 读 → 等待 ack → 输出结果 |
| 输出信号 | final_rdata:读回的数据;done:操作完成标志 |
| 复位安全 | 异步复位,初始状态可控 |

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online