前言: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控制器
1 `timescale 1 ns / 100 ps 2 `define SIM 3 `define IS61LV25616AL_10TL 4 `define SYS_CLK 100000000 5 `define BURST 16 6 `define BURST_WIDTH 8 7 module sram_ctrl( 8 sys_clk, 9 sys_rst_n, 10 //read 11 sys_rd_addr_i, 12 rreq_i, 13 sys_data_o, 14 sram_rd_ack_o, 15 sram_rd_valid_o, 16 //write 17 wreq_i, 18 sys_wr_addr_i, 19 sys_data_i, 20 sram_wr_valid_o, 21 sram_wr_ack_o, 22 //sram 23 sram_ce_n, 24 sram_oe_n, 25 sram_we_n, 26 sram_lb_n, 27 sram_ub_n, 28 sram_addr, 29 sram_data 30 ); 31 `ifdef IS61LV25616AL_10TL 32 `define DSIZE 16 33 `define ASIZE 18 34 `endif 35 input sys_clk; 36 input sys_rst_n; 37 //read 38 input [`ASIZE-1:0] sys_rd_addr_i; 39 input rreq_i; 40 output [`DSIZE-1:0] sys_data_o; 41 output sram_rd_ack_o; 42 output sram_rd_valid_o; 43 //write 44 input [`ASIZE-1:0] sys_wr_addr_i; 45 input wreq_i; 46 input [`DSIZE-1:0] sys_data_i; 47 output sram_wr_ack_o; 48 output sram_wr_valid_o; 49 //sram 50 output sram_ce_n; 51 output sram_oe_n; 52 output sram_we_n; 53 output sram_lb_n; 54 output sram_ub_n; 55 output [`ASIZE-1:0] sram_addr; 56 inout [`DSIZE-1:0] sram_data; 57 //command 58 parameter CMD_NOP = 5'b01000, 59 CMD_READ = 5'b10000, 60 CMD_WRITE = 5'b00100; 61 reg [4:0] cmd_r = CMD_NOP; 62 assign {sram_we_n,sram_ce_n,sram_oe_n,sram_lb_n,sram_ub_n} = cmd_r; 63 //FSM PARAMS 64 `ifdef SIM 65 parameter ST_WIDTH = 40; 66 parameter IDLE = "IDLE.", 67 READ = "READ.", 68 RD = "RD...", 69 END = "END..", 70 WR = "WR..."; 71 `else 72 `define FSM 5 73 parameter ST_WIDTH = 5; 74 parameter IDLE = `FSM'b0_0001, 75 READ = `FSM'b0_0010, 76 RD = `FSM'b0_0100, 77 END = `FSM'b0_1000, 78 WR = `FSM'b1_0000; 79 `endif 80 //capture the posedge of rreq 81 reg rreq_r = 0; 82 always @ (posedge sys_clk) begin 83 if(sys_rst_n == 1'b0) rreq_r <= 0; 84 else rreq_r <= rreq_i; 85 end 86 wire do_rreq = rreq_i & ~rreq_r; 87 //generate the rd_start signal 88 reg rd_start = 0; 89 always @ (posedge sys_clk) begin 90 if(sys_rst_n == 1'b0) rd_start <= 0; 91 else if(sram_rd_ack_o == 1'b1) rd_start <= 0; 92 else if(do_rreq) rd_start <= 1; 93 else rd_start <= rd_start; 94 end 95 //capture the posedge of wreq 96 reg wreq_r = 0; 97 always @ (posedge sys_clk) begin 98 if(sys_rst_n == 1'b0) wreq_r <= 0; 99 else wreq_r <= wreq_i; 100 end 101 wire do_wreq = wreq_i & ~wreq_r; 102 //generate the rd_start signal 103 reg wr_start = 0; 104 always @ (posedge sys_clk) begin 105 if(sys_rst_n == 1'b0) wr_start <= 0; 106 else if(sram_wr_ack_o == 1'b1) wr_start <= 0; 107 else if(do_wreq) wr_start <= 1; 108 else wr_start <= wr_start; 109 end 110 //FSM register 111 reg [`BURST_WIDTH-1:0] bit_cnt = 0; 112 reg [ST_WIDTH-1:0] c_st = IDLE; 113 reg [ST_WIDTH-1:0] n_st = IDLE; 114 reg link = 0; //0:read while 1:write 115 116 reg [`ASIZE-1:0] sram_addr = 0; 117 //fsm-1 118 always @ (posedge sys_clk) begin 119 if(1'b0 == sys_rst_n) c_st <= IDLE; 120 else c_st <= n_st; 121 end 122 //fsm-2 123 always @ (*) begin 124 case(c_st) 125 IDLE:begin 126 if(rd_start == 1'b1) begin 127 n_st = READ;end 128 else if(wr_start == 1'b1) begin 129 n_st = WR;end 130 else begin 131 n_st = IDLE;end 132 end 133 READ:n_st = RD; 134 RD:n_st = (bit_cnt == `BURST)?END:RD; 135 END:n_st = IDLE; 136 WR:n_st = (bit_cnt == `BURST)?END:WR; 137 default:n_st = IDLE; 138 endcase 139 end 140 //fsm-3 141 always @ (posedge sys_clk) begin 142 if(sys_rst_n == 1'b0) begin 143 bit_cnt <= 0; 144 link <= 0; 145 sram_addr <= `ASIZE'h3FFFF; 146 cmd_r <= CMD_NOP; 147 end 148 else begin 149 case(n_st) 150 IDLE:begin 151 bit_cnt <= 0; 152 link <= 0; 153 sram_addr <= sram_addr; 154 cmd_r <= CMD_NOP; 155 end 156 READ:begin 157 bit_cnt <= bit_cnt; 158 sram_addr <= sys_rd_addr_i; 159 link <=0; 160 cmd_r <= CMD_READ; 161 end 162 RD:begin 163 bit_cnt <= (bit_cnt == `BURST)?`BURST_WIDTH'd0:bit_cnt + 1'd1; 164 link <= 0; 165 sram_addr <= (bit_cnt == `BURST-1)?sram_addr:sram_addr + 1'd1; 166 cmd_r <= CMD_READ; 167 end 168 END:begin 169 bit_cnt <= 0; 170 link <= 0; 171 sram_addr <= sram_addr; 172 cmd_r <= CMD_NOP; 173 end 174 WR:begin 175 bit_cnt <= (bit_cnt == `BURST)?`BURST_WIDTH'd0:bit_cnt + 1'd1; 176 sram_addr <= (bit_cnt == `BURST)?sram_addr:sram_addr + 1'd1; 177 link <=1; 178 cmd_r <= CMD_WRITE; 179 end 180 default:begin 181 bit_cnt <= 0; 182 link <= 0; 183 sram_addr <= `ASIZE'h3FFFF; 184 cmd_r <= CMD_NOP;end 185 endcase 186 end 187 end 188 //generate sys_data_o 189 reg [`DSIZE-1:0] sys_data_o = 0; 190 always @ (*) begin 191 if(c_st == RD) sys_data_o <= sram_data; 192 else sys_data_o <= sys_data_o; 193 end 194 //generate sram_data_r 195 reg [`DSIZE-1:0] sram_data_r = 0; 196 always @ (*) begin 197 if(c_st == WR) sram_data_r <= sys_data_i; 198 else sram_data_r <= sram_data_r; 199 end 200 //assign 201 assign sram_data = (link == 1'b1)?sram_data_r:16'hzzzz; 202 assign sram_rd_ack_o = ((c_st == END)&&(rd_start == 1'b1))?1'b1:1'b0; 203 assign sram_rd_valid_o = (c_st == RD)?1'b1:1'b0; 204 assign sram_wr_ack_o = ((c_st == END)&&(wr_start == 1'b1))?1'b1:1'b0; 205 assign sram_wr_valid_o = (c_st == WR)?1'b1:1'b0; 206 207 endmodule
源码2:读驱动
1 `timescale 1 ns / 100 ps 2 `define BURST 16 3 `define BURST_WIDTH 8 4 `define ASIZE 18 5 module sram_rd_driver( 6 sys_clk, 7 sys_rst_n, 8 key_n, 9 sram_rd_valid_i, 10 rreq_o, 11 sys_rd_addr_o 12 ); 13 input sys_clk; 14 input sys_rst_n; 15 input key_n; 16 input sram_rd_valid_i; 17 output rreq_o; 18 output [`ASIZE-1:0] sys_rd_addr_o; 19 //generate the rreq_o 20 reg key_r = 1; 21 reg rreq_o = 0; 22 always @ (posedge sys_clk) begin 23 if(1'b0 == sys_rst_n) key_r <= 1; 24 else key_r <= key_n; 25 end 26 27 wire rd_trigger = ~key_n & key_r; 28 always @ (posedge sys_clk) begin 29 if(1'b0 == sys_rst_n) rreq_o <= 0; 30 else if(rd_trigger) rreq_o <= 1; 31 else rreq_o <= 0; 32 end 33 34 //generate the sys_rd_addr_o 35 reg [`ASIZE-1:0] sys_rd_addr_o = 0; 36 always @ (posedge sys_clk) begin 37 if(1'b0 == sys_rst_n) sys_rd_addr_o <= 0; 38 else if(sram_rd_valid_i) sys_rd_addr_o <= sys_rd_addr_o + 1'd1; 39 else sys_rd_addr_o <= sys_rd_addr_o; 40 end 41 42 43 endmodule
源码3:写驱动
1 `timescale 1 ns / 100 ps 2 `define BURST 16 3 `define BURST_WIDTH 8 4 `define ASIZE 18 5 `define DSIZE 16 6 module sram_wr_driver( 7 sys_clk, 8 sys_rst_n, 9 wr_key_n, 10 sram_wr_valid_i, 11 wreq_o, 12 sys_wr_addr_o, 13 sys_data_o 14 ); 15 input sys_clk; 16 input sys_rst_n; 17 input wr_key_n; 18 input sram_wr_valid_i; 19 output wreq_o; 20 output [`ASIZE-1:0] sys_wr_addr_o; 21 output [`DSIZE-1:0] sys_data_o; 22 23 //capture negedge of wr_key_n 24 reg wr_key_r = 1; 25 always @ (posedge sys_clk) begin 26 if(sys_rst_n == 1'b0) wr_key_r <= 1; 27 else wr_key_r <= wr_key_n; 28 end 29 //generate wreq_o 30 reg wreq_o = 0; 31 wire wr_trigger = ~wr_key_n & wr_key_r; 32 always @ (posedge sys_clk) begin 33 if(1'b0 == sys_rst_n) wreq_o <= 0; 34 else if(wr_trigger) wreq_o <= 1; 35 else wreq_o <= 0; 36 end 37 //generate sys_data_o and sys_wr_addr_o 38 reg [`ASIZE-1:0] sys_wr_addr_o = 0; 39 reg [`DSIZE-1:0] sys_data_o = 0; 40 41 always @ (posedge sys_clk) begin 42 if(sys_rst_n == 1'b0) begin 43 sys_wr_addr_o <= 0; 44 sys_data_o <= 0;end 45 else if(sram_wr_valid_i) begin 46 sys_wr_addr_o <= sys_wr_addr_o + 1'd1; 47 sys_data_o <= sys_data_o + 1'd1;end 48 else begin 49 sys_wr_addr_o <= sys_wr_addr_o; 50 sys_data_o <= sys_data_o;end 51 end 52 53 endmodule
源码4:顶层例化
1 `timescale 1 ns / 100 ps 2 `define ASIZE 18 3 `define DSIZE 16 4 module sram( 5 sys_clk, 6 sys_rst_n, 7 key_n, 8 wr_key_n, 9 //sram 10 sram_ce_n, 11 sram_oe_n, 12 sram_we_n, 13 sram_lb_n, 14 sram_ub_n, 15 sram_data, 16 sram_addr 17 ); 18 input sys_clk; 19 input sys_rst_n; 20 input key_n; 21 input wr_key_n; 22 //SRAM 23 output sram_ce_n; 24 output sram_oe_n; 25 output sram_we_n; 26 output sram_lb_n; 27 output sram_ub_n; 28 inout [`DSIZE-1:0] sram_data; 29 output [`ASIZE-1:0] sram_addr; 30 31 wire rreq; 32 wire sram_rd_ack; 33 wire sram_rd_valid; 34 wire [`ASIZE-1:0] sys_rd_addr; //from driver module 35 wire [`DSIZE-1:0] sys_data_o; 36 37 wire wreq; 38 wire sram_wr_ack; 39 wire sram_wr_valid; 40 wire [`ASIZE-1:0] sys_wr_addr; 41 wire [`DSIZE-1:0] sys_data_i; 42 43 //for hardware 44 45 wire sys_clk100; 46 pll100 pll100_inst ( 47 .inclk0 ( sys_clk ), 48 .c0 ( sys_clk100 ) 49 ); 50 51 sram_ctrl inst_sram_ctrl( 52 .sys_clk(sys_clk100), 53 .sys_rst_n(sys_rst_n), 54 //read 55 .sys_rd_addr_i(sys_rd_addr), 56 .rreq_i(rreq), 57 .sys_data_o(sys_data_o), 58 .sram_rd_ack_o(sram_rd_ack), 59 .sram_rd_valid_o(sram_rd_valid), 60 ////write 61 .wreq_i(wreq), 62 .sys_wr_addr_i(sys_wr_addr), 63 .sys_data_i(sys_data_i), 64 .sram_wr_valid_o(sram_wr_valid), 65 .sram_wr_ack_o(sram_wr_ack), 66 //sram 67 .sram_ce_n(sram_ce_n), 68 .sram_oe_n(sram_oe_n), 69 .sram_we_n(sram_we_n), 70 .sram_lb_n(sram_lb_n), 71 .sram_ub_n(sram_ub_n), 72 .sram_addr(sram_addr), 73 .sram_data(sram_data) 74 ); 75 76 sram_wr_driver inst_sram_wr_driver( 77 .sys_clk(sys_clk100), 78 .sys_rst_n(sys_rst_n), 79 .wr_key_n(wr_key_n), 80 .sram_wr_valid_i(sram_wr_valid), 81 .wreq_o(wreq), 82 .sys_wr_addr_o(sys_wr_addr), 83 .sys_data_o(sys_data_i) 84 ); 85 86 sram_rd_driver inst_sram_rd_driver( 87 .sys_clk(sys_clk100), 88 .sys_rst_n(sys_rst_n), 89 .key_n(key_n), 90 .sram_rd_valid_i(sram_rd_valid), 91 .rreq_o(rreq), 92 .sys_rd_addr_o(sys_rd_addr) 93 ); 94 95 endmodule