之前一直没太搞懂这个SRAM 是用来做什么的,现在做完了vga的觉得这个SRAM的作用很大,说白了这就是个储存器,而在我vga的字符的读取显示中,难度最大的也是在存储器上,之前有人建议我在做的时候改用ram可以实现字符的动态显示而不是局限于自己独自开辟的显示区域,下面我就先从SRAM入手,好好的介绍下这几个存储器(最近更ROM RAM SRAM )
在有数据传输的地方就会有存储器
SRAM(static RAM):异步传输易失存储器
优点:读写传输迅速,控制时序不复杂(这里我用的特权的板子就直接把他们写的东西拿来用了)
找来任何一颗SRAM芯片的datasheet,会发现它们的时序操作大同小异,在这里总结一些它们共性的东西,也提一些用Verilog简单的快速操作SRAM的技巧。SRAM内部的结构如图所示,
1、要访问实际的Momory区域,FPGA必须送地址(A0-A14)和控制信号(CE \OE \WE ),
2、SRAM内部有与此对应的地址译码(decoder)
3、控制处理电路(control circuit)。
这样,数据总线(I/O0-I/O7)上的数据就可以相应的读或写了。
这里就以本实验使用的IS62LV256-45U为例进行说明。其管脚定义如表所示。
序号 |
管脚 |
方向 |
描述 |
1 |
A0-A14 |
Input |
地址总线。 |
2 |
CEn |
Input |
芯片使能输入,低有效。 |
3 |
OEn |
Input |
输出使能输入,低有效。 |
4 |
WEn |
Input |
写使能输入,低有效。 |
5 |
I/O0-I/O7 |
Inout |
数据输入/输出总线。 |
6 |
VCC |
Input |
电源。 |
7 |
GND |
Input |
数字地。 |
本设计的硬件原理图如图所示。
图6.59 SRAM接口
对于SRAM的读操作时序,其波形如图所示。
对于SRAM的写操作时序,其波形如图所示。
代码如下:
module top(ext_clk_25m,ext_rst_n,led,
sram_cs_n,sram_we_n,sram_oe_n,
sram_data,sram_addr
);
input ext_clk_25m;
input ext_rst_n;
output led;
output sram_cs_n;
output sram_we_n;
output sram_oe_n;
output [14:0] sram_addr;
inout [7:0] sram_data;
wire clk_12m5;
wire clk_25m;
wire clk_50m;
wire clk_65m;
wire clk_108m;
wire clk_130m;
wire sys_rst_n;
pll_controller uut_pll_controller
(// Clock in ports
.CLK_IN1(ext_clk_25m), // IN
// Clock out ports
.CLK_OUT1(clk_12m5), // OUT
.CLK_OUT2(clk_25m), // OUT
.CLK_OUT3(clk_50m), // OUT
.CLK_OUT4(clk_65m), // OUT
.CLK_OUT5(clk_108m), // OUT
.CLK_OUT6(clk_130m), // OUT
// Status and control signals
.RESET(~ext_rst_n),// IN
.LOCKED(sys_rst_n)
);
//定时写sram测试模块
wire sramwr_req;
wire sramrd_req;
wire [7:0] sramwr_data;
wire [7:0] sramrd_data;
wire [14:0] sramwr_addr;
wire [14:0] sramrd_addr;
test_timing uut_test_timing(
.clk(clk_50m),
.rst_n(sys_rst_n),
.led(led),
.sramwr_req(sramwr_req),
.sramrd_req(sramrd_req),
.sramwr_data(sramwr_data),
.sramrd_data(sramrd_data),
.sramwr_addr(sramwr_addr),
.sramrd_addr(sramrd_addr)
);
//sram基本读写模块
sram_controller uut_sram_controller(
.clk(clk_50m),
.rst_n(sys_rst_n),
.sramwr_req(sramwr_req),
.sramrd_req(sramrd_req),
.sramwr_data(sramwr_data),
.sramrd_data(sramrd_data),
.sramwr_addr(sramwr_addr),
.sramrd_addr(sramrd_addr),
.sram_cs_n(sram_cs_n),
.sram_we_n(sram_we_n),
.sram_oe_n(sram_oe_n),
.sram_addr(sram_addr),
.sram_data(sram_data)
);
endmodule
module test_timing(clk,rst_n,led,sramwr_req,sramrd_req,sramwr_data,sramrd_data,sramwr_addr,sramrd_addr
);
input clk;//输入时钟
input rst_n;//复位信号
output reg led;//LED指示灯
output sramwr_req ;//SRAM写请求信号,高电位有效,用于状态机控制
output sramrd_req ;//SRAM读请求信号,高电位有效,用于状态机控制
output reg [7:0] sramwr_data;//SRAM写入数据寄存器
input [7:0] sramrd_data;//SRAM读出数据寄存器
output reg [14:0]sramwr_addr;//SRAM写入地址寄存器
output reg [14:0]sramrd_addr;//SRAM读取地址寄存器
//一秒定时
reg[25:0] delay;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
delay<=1'b0;
end
else if(delay<26'd49_999_999)begin
delay<=delay+1'b1;
end
else begin
delay<=1'b0;
end
end
assign sramwr_req =(delay==26'd1000);
assign sramrd_req =(delay==26'd1100);
//定时写入数据寄存器
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sramwr_data<=8'd0;
end
else if(delay==26'd4000)begin
sramwr_data<=sramrd_data+1'b1;
end
end
//定时SRAM读和写地址寄存器
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sramwr_addr<=1'b0;
end
else if(delay==26'd4000)begin
sramwr_addr<=sramwr_addr+1'b1;
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sramrd_addr<=1'b0;
end
else if(delay==26'd4000)begin
sramrd_addr<=sramrd_addr+1'b1;
end
end
//比较数据
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
led<=1'b1;
end
else if(delay==26'd3000)begin
if(sramrd_data==sramwr_data)begin
led<=1'b0;
end
else begin
led<=1'b1;
end
end
end
endmodule
module sram_controller(clk,rst_n,
sramwr_req,sramrd_req,sramwr_data,sramrd_data,sramwr_addr,sramrd_addr,
sram_cs_n,sram_we_n,sram_oe_n,sram_addr,sram_data
);
input clk;
input rst_n;
//读写控制信号
input sramwr_req;//SRAM写请求信号,高电位有效,用于状态机控制
input sramrd_req;//SRAM读请求信号,高电位有效,用于状态机控制
input [7:0] sramwr_data;//SRAM写入数据寄存器
output reg [7:0]sramrd_data;//SRAM读出数据寄存器
input [14:0] sramwr_addr;//SRAM写入地址寄存器
input [14:0] sramrd_addr;//SRAM读取地址寄存器
//FPGA与芯片的接口信号
output reg sram_cs_n;//SRAM片选信号
output reg sram_we_n;//SRAM写入信号
output reg sram_oe_n;//SRAM输出选通信号
output reg [14:0] sram_addr;//地址总线
inout [7:0] sram_data;//数据总线
`define DELAY_00NS (cnt==3'd0)
`define DELAY_20NS (cnt==3'd1)
`define DELAY_40NS (cnt==3'd2)
`define DELAY_60NS (cnt==3'd3)
parameter IDLE = 4'd0,
WRT0 = 4'd1,
WRT1 = 4'd2,
REA0 = 4'd3,
REA1 = 4'd4;
reg [3:0]state_c;
reg [3:0]state_n;
reg [2:0] cnt;
//延时计数器
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt<=1'b0;
end
else if(state_c==IDLE)begin
cnt<=1'b0;
end
else begin
cnt<=cnt+1'b1;
end
end
//SRAM读写状态机
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
state_c<=IDLE;
end
else begin
state_c<=state_n;
end
end
always@(state_c or sramwr_req or sramrd_req or cnt)begin
case(state_c)
IDLE:if(sramwr_req==1'b1)begin
state_n<=WRT0;
end
else if(sramrd_req==1'b1)begin
state_n<=REA0;
end
else begin
state_n<=IDLE;
end
WRT0:if(`DELAY_60NS)begin
state_n<=WRT1;
end
else begin
state_n<=WRT0;
end
WRT1:state_n<=IDLE;
REA0:if(`DELAY_60NS)begin
state_n<=REA1;
end
else begin
state_n<=REA0;
end
REA1:state_n<=IDLE;
default:state_n<=IDLE;
endcase
end
//地址赋值
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sram_addr<=15'd0;
end
else if(state_c==WRT0)begin
sram_addr<=sramwr_addr;
end
else if(state_c==WRT1)begin
sram_addr<=15'd0;
end
else if(state_c==REA0)begin
sram_addr<=sramrd_addr;
end
else if(state_c==REA1)begin
sram_addr<=15'd0;
end
end
reg sdlink;
//SRAM读写控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sramrd_data<=8'd0;
end
else if((state_c==REA0)&&`DELAY_60NS)begin
sramrd_data<=sram_data;
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sdlink<=1'b0;
end
else if(state_c==WRT0)begin
sdlink<=1'b1;
end
else if(state_c==WRT1)begin
sdlink<=1'b0;
end
end
assign sram_data = sdlink?sramwr_data:8'hzz;
//SRAM片选控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sram_cs_n<=1'b1;
end
else if(state_c==WRT0)begin
if(`DELAY_00NS)begin
sram_cs_n<=1'b1;
end
else begin
sram_cs_n<=1'b0;
end
end
else if(state_c==REA0)begin
sram_cs_n<=1'b0;
end
else begin
sram_cs_n<=1'b1;
end
end
//读选通控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sram_oe_n<=1'b1;
end
else if(state_c==REA0)begin
sram_oe_n<=1'b0;
end
else begin
sram_oe_n<=1'b1;
end
end
//写选通控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sram_we_n<=1'b1;
end
else if(state_c==WRT0)begin
if(`DELAY_20NS)begin
sram_we_n<=1'b0;
end
else if(`DELAY_60NS)begin
sram_we_n<=1'b1;
end
end
end
endmodule