耗时一周,终于完成sdram简易控制器的所有代码设计,其中感谢开源骚客 – 邓堪文老师在b站发布的相关视频学习教材;其中仿真模块及所使用到的sdram仿真文件来源于开源骚客;
因为时间较为紧迫,其中就不做代码的一些注释;
在设计中,总结一哈要主要的几个问题:
1. 仲裁模块中if/else语句中的先后顺序很重要,其中根据仿真的时序图经过多次修改;
2. 仲裁模块决定刷新/写/读操作的重要部分,要重点理清楚各模块产生请求信号后产生使能信号的先后顺序;
3. 读/写状态结束后应及时赋予PRE命令,否则导致读数据有误(具体可查看芯片手册相关介绍);
本设计中采用写3行数据后进行数据的读取,代码如下:
初始化init模块:
module sdram_init(
sys_clk,
sys_rst_n,
init_cmd,
init_addr,
init_end
);
input sys_clk,sys_rst_n;
output reg [3:0] init_cmd;
output wire [12:0] init_addr;
output wire init_end;
reg [13:0] cnt_200us;
wire flag_200us;
reg [3:0] cnt_cmd;
localparam delay_200us = 10000; //200us
//SDRAM init_cmd//
localparam NOP = 4'b0111;
localparam PRE = 4'b0010;
localparam AREF = 4'b0001;
localparam MSET = 4'b0000;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
cnt_200us <= 0;
else if (flag_200us == 0)
cnt_200us <= cnt_200us+1;
end
assign flag_200us = (cnt_200us >= delay_200us) ? 1'b1:1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
cnt_cmd <= 0;
else if ((flag_200us == 1) && (init_end == 0))
cnt_cmd <= cnt_cmd+1;
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
init_cmd <= NOP ;
else if (flag_200us == 1)
case (cnt_cmd)
0: init_cmd <= PRE;
1: init_cmd <= AREF;
5: init_cmd <= AREF;
9: init_cmd <= MSET;
default:init_cmd <= NOP;
endcase
end
//sdram addr//
//always@(posedge sys_clk or negedge sys_rst_n)
//begin
// if(!sys_rst_n)
// init_addr <= 0;
// else if (flag_200us == 1)
// case (cnt_init_cmd)
assign init_addr = (init_cmd == MSET) ? 13'b0_0000_0011_0010:12'b0_0100_0000_0010;
assign init_end = (cnt_cmd >= 'd10) ? 1'b1:1'b0;
endmodule
刷新模块代码:
module sdram_aref(
sys_clk,
sys_rst_n,
init_end,
ref_en,
ref_req,
ref_end,
ref_cmd,
ref_addr
);
input sys_clk,sys_rst_n,ref_en,init_end;
output reg ref_req;
output wire ref_end;
output reg [3:0] ref_cmd;
output [12:0] ref_addr; //4M*4banks*16bit//
localparam Delay_15us = 399;
localparam NOP = 4'b0111;
localparam PRE = 4'b0010;
localparam AREF = 4'b0001;
reg [3:0] cnt_cmd;
reg [9:0] cnt_ref;
reg ref_flag;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if (!sys_rst_n)
cnt_ref <= 1'b0;
else if (cnt_ref == Delay_15us)
cnt_ref <= 1'b0;
else if (init_end == 1'b1)
cnt_ref <= cnt_ref + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if (!sys_rst_n)
ref_req <= 0;
else if (ref_en == 1 && ref_req == 1)
ref_req <= 0;
else if (cnt_ref >= Delay_15us)
ref_req <= 1;
end
//assign ref_req = (cnt_ref == Delay_15us) ? 1'b1:1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if (!sys_rst_n)
ref_flag <= 0;
else if (ref_en == 1)
ref_flag <= 1;
else if (ref_end == 1)
ref_flag <= 0;
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if (!sys_rst