前言:sram顾名思义静态随机存储器,分为asram异步型和ssram同步型。这里驱动DE2上一块ISSI公司的512KB的asram。
设计思路:因为实际应用中单字节读写效率不高,所以本设计中仿照sdram的页突发读写,提高sram的效率。因为sram不像sdram需要定期刷新以及行列地址复用,因此省却很多麻烦。拿到手册以后主要关注的就是其最快运行时钟以及数据稳定的建立时间和保持时间,以及控制线的时间参数,这些参数可以由datasheet的时序参数的min time和max time确定,通过这些参数可以简化后续的读写的时序图。
注意事项:
(a)在读操作中,读指令有效到数据有效输出有一个CLK的延迟,即latency;
(b)为了避免读写操作过程中,数据与地址之间的时钟差,其中sys_data_o与sdram_data_r寄存器直接用latch建模,综合后出现的警告;
(c)模块时钟工作在100MHz,移植过程中pll视情况而定,pll工作于normal模式即可l;
总结:以上代码结果仿真和硬件测试,并未做超频测试。这里附出源码。
源码1:sram控制器
`timescale ns / ps
`define SIM
`define IS61LV25616AL_10TL
`define SYS_CLK
`define BURST
`define BURST_WIDTH
module sram_ctrl(
sys_clk,
sys_rst_n,
//read
sys_rd_addr_i,
rreq_i,
sys_data_o,
sram_rd_ack_o,
sram_rd_valid_o,
//write
wreq_i,
sys_wr_addr_i,
sys_data_i,
sram_wr_valid_o,
sram_wr_ack_o,
//sram
sram_ce_n,
sram_oe_n,
sram_we_n,
sram_lb_n,
sram_ub_n,
sram_addr,
sram_data
);
`ifdef IS61LV25616AL_10TL
`define DSIZE
`define ASIZE
`endif
input sys_clk;
input sys_rst_n;
//read
input [`ASIZE-:] sys_rd_addr_i;
input rreq_i;
output [`DSIZE-:] sys_data_o;
output sram_rd_ack_o;
output sram_rd_valid_o;
//write
input [`ASIZE-:] sys_wr_addr_i;
input wreq_i;
input [`DSIZE-:] sys_data_i;
output sram_wr_ack_o;
output sram_wr_valid_o;
//sram
output sram_ce_n;
output sram_oe_n;
output sram_we_n;
output sram_lb_n;
output sram_ub_n;
output [`ASIZE-:] sram_addr;
inout [`DSIZE-:] sram_data;
//command
parameter CMD_NOP = 'b01000,
CMD_READ = 'b10000,
CMD_WRITE = 'b00100;
reg [:] cmd_r = CMD_NOP;
assign {sram_we_n,sram_ce_n,sram_oe_n,sram_lb_n,sram_ub_n} = cmd_r;
//FSM PARAMS
`ifdef SIM
parameter ST_WIDTH = ;
parameter IDLE = "IDLE.",
READ = "READ.",
RD = "RD...",
END = "END..",
WR = "WR...";
`else
`define FSM
parameter ST_WIDTH = ;
parameter IDLE = `FSM'b0_0001,
READ = `FSM'b0_0010,
RD = `FSM'b0_0100,
END = `FSM'b0_1000,
WR = `FSM'b1_0000;
`endif
//capture the posedge of rreq
reg rreq_r = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) rreq_r <= 0;
else rreq_r <= rreq_i;
end
wire do_rreq = rreq_i & ~rreq_r;
//generate the rd_start signal
reg rd_start = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) rd_start <= 0;
else if(sram_rd_ack_o == 'b1) rd_start <= 0;
else if(do_rreq) rd_start <= ;
else rd_start <= rd_start;
end
//capture the posedge of wreq
reg wreq_r = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wreq_r <= 0;
else wreq_r <= wreq_i;
end
wire do_wreq = wreq_i & ~wreq_r;
//generate the rd_start signal
reg wr_start = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wr_start <= 0;
else if(sram_wr_ack_o == 'b1) wr_start <= 0;
else if(do_wreq) wr_start <= ;
else wr_start <= wr_start;
end
//FSM register
reg [`BURST_WIDTH-:] bit_cnt = ;
reg [ST_WIDTH-:] c_st = IDLE;
reg [ST_WIDTH-:] n_st = IDLE;
reg link = ; //0:read while 1:write reg [`ASIZE-:] sram_addr = ;
//fsm-1
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) c_st <= IDLE;
else c_st <= n_st;
end
//fsm-2
always @ (*) begin
case(c_st)
IDLE:begin
if(rd_start == 'b1) begin
n_st = READ;end
else if(wr_start == 'b1) begin
n_st = WR;end
else begin
n_st = IDLE;end
end
READ:n_st = RD;
RD:n_st = (bit_cnt == `BURST)?END:RD;
END:n_st = IDLE;
WR:n_st = (bit_cnt == `BURST)?END:WR;
default:n_st = IDLE;
endcase
end
//fsm-3
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
bit_cnt <= ;
link <= ;
sram_addr <= `ASIZE'h3FFFF;
cmd_r <= CMD_NOP;
end
else begin
case(n_st)
IDLE:begin
bit_cnt <= ;
link <= ;
sram_addr <= sram_addr;
cmd_r <= CMD_NOP;
end
READ:begin
bit_cnt <= bit_cnt;
sram_addr <= sys_rd_addr_i;
link <=;
cmd_r <= CMD_READ;
end
RD:begin
bit_cnt <= (bit_cnt == `BURST)?`BURST_WIDTH'd0:bit_cnt + 1'd1;
link <= ;
sram_addr <= (bit_cnt == `BURST-)?sram_addr:sram_addr + 'd1;
cmd_r <= CMD_READ;
end
END:begin
bit_cnt <= ;
link <= ;
sram_addr <= sram_addr;
cmd_r <= CMD_NOP;
end
WR:begin
bit_cnt <= (bit_cnt == `BURST)?`BURST_WIDTH'd0:bit_cnt + 1'd1;
sram_addr <= (bit_cnt == `BURST)?sram_addr:sram_addr + 'd1;
link <=;
cmd_r <= CMD_WRITE;
end
default:begin
bit_cnt <= ;
link <= ;
sram_addr <= `ASIZE'h3FFFF;
cmd_r <= CMD_NOP;end
endcase
end
end
//generate sys_data_o
reg [`DSIZE-:] sys_data_o = ;
always @ (*) begin
if(c_st == RD) sys_data_o <= sram_data;
else sys_data_o <= sys_data_o;
end
//generate sram_data_r
reg [`DSIZE-:] sram_data_r = ;
always @ (*) begin
if(c_st == WR) sram_data_r <= sys_data_i;
else sram_data_r <= sram_data_r;
end
//assign
assign sram_data = (link == 'b1)?sram_data_r:16'hzzzz;
assign sram_rd_ack_o = ((c_st == END)&&(rd_start == 'b1))?1'b1:'b0;
assign sram_rd_valid_o = (c_st == RD)?'b1:1'b0;
assign sram_wr_ack_o = ((c_st == END)&&(wr_start == 'b1))?1'b1:'b0;
assign sram_wr_valid_o = (c_st == WR)?'b1:1'b0; endmodule
源码2:读驱动
`timescale ns / ps
`define BURST
`define BURST_WIDTH
`define ASIZE
module sram_rd_driver(
sys_clk,
sys_rst_n,
key_n,
sram_rd_valid_i,
rreq_o,
sys_rd_addr_o
);
input sys_clk;
input sys_rst_n;
input key_n;
input sram_rd_valid_i;
output rreq_o;
output [`ASIZE-:] sys_rd_addr_o;
//generate the rreq_o
reg key_r = ;
reg rreq_o = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) key_r <= 1;
else key_r <= key_n;
end wire rd_trigger = ~key_n & key_r;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) rreq_o <= 0;
else if(rd_trigger) rreq_o <= ;
else rreq_o <= ;
end //generate the sys_rd_addr_o
reg [`ASIZE-:] sys_rd_addr_o = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) sys_rd_addr_o <= 0;
else if(sram_rd_valid_i) sys_rd_addr_o <= sys_rd_addr_o + 'd1;
else sys_rd_addr_o <= sys_rd_addr_o;
end endmodule
源码3:写驱动
`timescale ns / ps
`define BURST
`define BURST_WIDTH
`define ASIZE
`define DSIZE
module sram_wr_driver(
sys_clk,
sys_rst_n,
wr_key_n,
sram_wr_valid_i,
wreq_o,
sys_wr_addr_o,
sys_data_o
);
input sys_clk;
input sys_rst_n;
input wr_key_n;
input sram_wr_valid_i;
output wreq_o;
output [`ASIZE-:] sys_wr_addr_o;
output [`DSIZE-:] sys_data_o; //capture negedge of wr_key_n
reg wr_key_r = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wr_key_r <= 1;
else wr_key_r <= wr_key_n;
end
//generate wreq_o
reg wreq_o = ;
wire wr_trigger = ~wr_key_n & wr_key_r;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) wreq_o <= 0;
else if(wr_trigger) wreq_o <= ;
else wreq_o <= ;
end
//generate sys_data_o and sys_wr_addr_o
reg [`ASIZE-:] sys_wr_addr_o = ;
reg [`DSIZE-:] sys_data_o = ; always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
sys_wr_addr_o <= ;
sys_data_o <= ;end
else if(sram_wr_valid_i) begin
sys_wr_addr_o <= sys_wr_addr_o + 'd1;
sys_data_o <= sys_data_o + 'd1;end
else begin
sys_wr_addr_o <= sys_wr_addr_o;
sys_data_o <= sys_data_o;end
end endmodule
源码4:顶层例化
`timescale ns / ps
`define ASIZE
`define DSIZE
module sram(
sys_clk,
sys_rst_n,
key_n,
wr_key_n,
//sram
sram_ce_n,
sram_oe_n,
sram_we_n,
sram_lb_n,
sram_ub_n,
sram_data,
sram_addr
);
input sys_clk;
input sys_rst_n;
input key_n;
input wr_key_n;
//SRAM
output sram_ce_n;
output sram_oe_n;
output sram_we_n;
output sram_lb_n;
output sram_ub_n;
inout [`DSIZE-:] sram_data;
output [`ASIZE-:] sram_addr; wire rreq;
wire sram_rd_ack;
wire sram_rd_valid;
wire [`ASIZE-:] sys_rd_addr; //from driver module
wire [`DSIZE-:] sys_data_o; wire wreq;
wire sram_wr_ack;
wire sram_wr_valid;
wire [`ASIZE-:] sys_wr_addr;
wire [`DSIZE-:] sys_data_i; //for hardware wire sys_clk100;
pll100 pll100_inst (
.inclk0 ( sys_clk ),
.c0 ( sys_clk100 )
); sram_ctrl inst_sram_ctrl(
.sys_clk(sys_clk100),
.sys_rst_n(sys_rst_n),
//read
.sys_rd_addr_i(sys_rd_addr),
.rreq_i(rreq),
.sys_data_o(sys_data_o),
.sram_rd_ack_o(sram_rd_ack),
.sram_rd_valid_o(sram_rd_valid),
////write
.wreq_i(wreq),
.sys_wr_addr_i(sys_wr_addr),
.sys_data_i(sys_data_i),
.sram_wr_valid_o(sram_wr_valid),
.sram_wr_ack_o(sram_wr_ack),
//sram
.sram_ce_n(sram_ce_n),
.sram_oe_n(sram_oe_n),
.sram_we_n(sram_we_n),
.sram_lb_n(sram_lb_n),
.sram_ub_n(sram_ub_n),
.sram_addr(sram_addr),
.sram_data(sram_data)
); sram_wr_driver inst_sram_wr_driver(
.sys_clk(sys_clk100),
.sys_rst_n(sys_rst_n),
.wr_key_n(wr_key_n),
.sram_wr_valid_i(sram_wr_valid),
.wreq_o(wreq),
.sys_wr_addr_o(sys_wr_addr),
.sys_data_o(sys_data_i)
); sram_rd_driver inst_sram_rd_driver(
.sys_clk(sys_clk100),
.sys_rst_n(sys_rst_n),
.key_n(key_n),
.sram_rd_valid_i(sram_rd_valid),
.rreq_o(rreq),
.sys_rd_addr_o(sys_rd_addr)
); endmodule