之前一直没太搞懂这个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为例进行说明。其管脚定义如表所示。
本设计的硬件原理图如图所示。
图6.59 SRAM接口
对于SRAM的读操作时序,其波形如图所示。
对于SRAM的写操作时序,其波形如图所示。
代码如下:
top.v:
moduletop(ext_clk_25m,ext_rst_n,led, sram_cs_n,sram_we_n,sram_oe_n, sram_data,sram_addr ); inputext_clk_25m; inputext_rst_n; outputled; outputsram_cs_n; outputsram_we_n; outputsram_oe_n; output [14:0] sram_addr; inout [7:0] sram_data; wireclk_12m5; wireclk_25m; wireclk_50m; wireclk_65m; wireclk_108m; wireclk_130m; wiresys_rst_n; pll_controlleruut_pll_controller(//Clockinports .CLK_IN1(ext_clk_25m), //IN//Clockoutports .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//Statusandcontrolsignals .RESET(~ext_rst_n),//IN .LOCKED(sys_rst_n) ); //定时写sram测试模块wiresramwr_req; wiresramrd_req; wire [7:0] sramwr_data; wire [7:0] sramrd_data; wire [14:0] sramwr_addr; wire [14:0] sramrd_addr; test_timinguut_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_controlleruut_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
timing.v:
moduletest_timing(clk,rst_n,led,sramwr_req,sramrd_req,sramwr_data,sramrd_data,sramwr_addr,sramrd_addr ); inputclk;//输入时钟inputrst_n;//复位信号outputregled;//LED指示灯outputsramwr_req ;//SRAM写请求信号,高电位有效,用于状态机控制outputsramrd_req ;//SRAM读请求信号,高电位有效,用于状态机控制outputreg [7:0] sramwr_data;//SRAM写入数据寄存器input [7:0] sramrd_data;//SRAM读出数据寄存器outputreg [14:0]sramwr_addr;//SRAM写入地址寄存器outputreg [14:0]sramrd_addr;//SRAM读取地址寄存器//一秒定时reg[25:0] delay; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begindelay<=1'b0;endelseif(delay<26'd49_999_999)begindelay<=delay+1'b1;endelsebegindelay<=1'b0;endendassignsramwr_req=(delay==26'd1000);assignsramrd_req=(delay==26'd1100);//定时写入数据寄存器always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsramwr_data<=8'd0;endelseif(delay==26'd4000)beginsramwr_data<=sramrd_data+1'b1;endend//定时SRAM读和写地址寄存器always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsramwr_addr<=1'b0;endelseif(delay==26'd4000)beginsramwr_addr<=sramwr_addr+1'b1;endendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsramrd_addr<=1'b0;endelseif(delay==26'd4000)beginsramrd_addr<=sramrd_addr+1'b1;endend//比较数据always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginled<=1'b1;endelseif(delay==26'd3000)beginif(sramrd_data==sramwr_data)beginled<=1'b0;endelsebeginled<=1'b1;endendendendmodule
sram_controller.v:
modulesram_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 ); inputclk; inputrst_n; //读写控制信号inputsramwr_req;//SRAM写请求信号,高电位有效,用于状态机控制inputsramrd_req;//SRAM读请求信号,高电位有效,用于状态机控制input [7:0] sramwr_data;//SRAM写入数据寄存器outputreg [7:0]sramrd_data;//SRAM读出数据寄存器input [14:0] sramwr_addr;//SRAM写入地址寄存器input [14:0] sramrd_addr;//SRAM读取地址寄存器//FPGA与芯片的接口信号outputregsram_cs_n;//SRAM片选信号outputregsram_we_n;//SRAM写入信号outputregsram_oe_n;//SRAM输出选通信号outputreg [14:0] sram_addr;//地址总线inout [7:0] sram_data;//数据总线 `defineDELAY_00NS (cnt==3'd0) `defineDELAY_20NS (cnt==3'd1) `defineDELAY_40NS (cnt==3'd2) `defineDELAY_60NS (cnt==3'd3)parameterIDLE=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@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=1'b0;endelseif(state_c==IDLE)begincnt<=1'b0;endelsebegincnt<=cnt+1'b1;endend//SRAM读写状态机always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginstate_c<=IDLE; endelsebeginstate_c<=state_n; endendalways@(state_corsramwr_reqorsramrd_reqorcnt)begincase(state_c) IDLE:if(sramwr_req==1'b1)beginstate_n<=WRT0; endelseif(sramrd_req==1'b1)beginstate_n<=REA0; endelsebeginstate_n<=IDLE; endWRT0:if(`DELAY_60NS)beginstate_n<=WRT1; endelsebeginstate_n<=WRT0; endWRT1:state_n<=IDLE; REA0:if(`DELAY_60NS)beginstate_n<=REA1; endelsebeginstate_n<=REA0; endREA1:state_n<=IDLE; default:state_n<=IDLE; endcaseend//地址赋值always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsram_addr<=15'd0;endelseif(state_c==WRT0)beginsram_addr<=sramwr_addr; endelseif(state_c==WRT1)beginsram_addr<=15'd0;endelseif(state_c==REA0)beginsram_addr<=sramrd_addr; endelseif(state_c==REA1)beginsram_addr<=15'd0;endendregsdlink; //SRAM读写控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsramrd_data<=8'd0;endelseif((state_c==REA0)&&`DELAY_60NS)beginsramrd_data<=sram_data; endendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsdlink<=1'b0;endelseif(state_c==WRT0)beginsdlink<=1'b1;endelseif(state_c==WRT1)beginsdlink<=1'b0;endendassignsram_data=sdlink?sramwr_data:8'hzz;//SRAM片选控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsram_cs_n<=1'b1;endelseif(state_c==WRT0)beginif(`DELAY_00NS)beginsram_cs_n<=1'b1;endelsebeginsram_cs_n<=1'b0;endendelseif(state_c==REA0)beginsram_cs_n<=1'b0;endelsebeginsram_cs_n<=1'b1;endend//读选通控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsram_oe_n<=1'b1;endelseif(state_c==REA0)beginsram_oe_n<=1'b0;endelsebeginsram_oe_n<=1'b1;endend//写选通控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsram_we_n<=1'b1;endelseif(state_c==WRT0)beginif(`DELAY_20NS)beginsram_we_n<=1'b0;endelseif(`DELAY_60NS)beginsram_we_n<=1'b1;endendendendmodule