主要写了SDRAM的初始化模块,注重文档信息的查找,时序图的设计,SDRAM仿真插件的使用。
文档信息:
根据文档说明,SDRAM在使用之前必须先进行初始化
初始化之前要进行100us的延迟,在100us内除了INHIBIT和NOP命令,其他命令都不可以执行,
时序图如下:
CLK为系统时钟,根据时序图,在100us的延迟后执行precharge命令,在经过trp时间后进行auto refresh命令 ,经过trc时间后再执行一次auto refresh,再经过trc时间后惊醒寄存器配置命令mode register,到此初始化完成。
阅读手册:
发现Nop模式下 cs_n.ras_n,cas_n.we_n的数据分别为0111/1xxx,同理precharge为0010,auto_ref为0001,
trc的最小时间间隔为63ns,4个周期(80ns——50hz/20ns),
trp的最小时间间隔为20ns,1个周期
配置模式寄存器:选择配置 A0-A11 分别为0100_0110_0000
根据文档说明画出时序图:
为了稳定设置延迟时间为200us,200us后flag200us拉高,命令计数器cnt_cmd开始计数(计时钟周期数),一开始进行precharge(周期0),进行autoref命令(周期1,5),进行mest(周期9)命令。初始化完成。
cmd_reg:用来进行命令的寄存,当cmd_cnt计数到相应周期的时候写入相应的配置。
sdram_addr:选择地址A0-A11
flag_init_end:当初始化任务完成后拉高点评,标志此时初始化完成
根据时序图编写verilog:
module sdram_init(
input sclk,
input srst,
output reg [3:0] cmd_reg, //片选信号
output wire [11:0] sdram_addr, //A0-A11
output wire flag_init_end
);
//==========================================================
//======= define parameter and internal signal ========
//==========================================================
localparam delay_200us = 10000;
// sdram command
localparam nop = 4'b0111;
localparam pre = 4'b0010;
localparam aref = 4'b0001;
localparam mest = 4'b0000;
reg [13:0] cnt_200us ;
wire flag_200us ;
reg [3:0] cnt_cmd ;
//==========================================================
//==================== main code ====================
//==========================================================
// cnt_200us
always@(posedge sclk or negedge srst) begin
if(srst == 1'b0)
cnt_200us <= 'd0;
else if(flag_200us == 1'b0)
cnt_200us <= cnt_200us + 1'b1;
end
//cnt_cmd
always@(posedge sclk or negedge srst) begin
if(srst == 1'b0)
cnt_cmd <= 'd0;
else if(flag_200us == 1'b1 && flag_init_end == 1'b0)
cnt_cmd <= cnt_cmd + 1'b1; //最后不需要归零,保持下去也可
end
//cmd_reg
always@(posedge sclk or negedge srst) begin
if(srst == 1'b0)
cmd_reg <= nop ;
else if(flag_200us == 1'b1)
case(cnt_cmd)
0: cmd_reg <= pre ;
1: cmd_reg <= aref;
5: cmd_reg <= aref;
9: cmd_reg <= mest;
default:cmd_reg <= nop;
endcase
end
assign flag_init_end = (cnt_cmd >= 'd10) ? 1'b1:1'b0;
assign sdram_addr = (cmd_reg == mest) ? 12'b0000_0011_0010:12'b0100_0000_0000;
assign flag_200us = (cnt_200us >= delay_200us)? 1'b1:1'b0;
endmodule
根据文档说明编写SDRAM顶层模块:
根据文档引脚描述:
clk为系统时钟输入,cke输出时钟使能信号,设置为高电平使SDRAM处于一直工作状态,cs,ras,cas,we,A0-A11,BA0-BA1,dqm(udqm和ldqm)均为输出,D0-D15为输入输出,vss/vdd/vssq/vddq为电源。
顶层模块代码:
module sdram_top(
input sclk,
input srst,
//sdram interface
output wire sdram_clk,
output wire sdram_cke,
output wire sdram_cs_n,
output wire sdram_cas_n,
output wire sdram_ras_n,
output wire sdram_we_n,
output wire [1:0] sdram_bank,
output wire [11:0] sdram_addr,
output wire [1:0] sdram_dqm,
inout [15:0] sdram_dq
);
//==========================================================
//======= define parameter and internal signal ========
//==========================================================
wire flag_init_end;
wire [3:0] init_cmd;
wire [11:0] init_addr;
//==========================================================
//==================== main code ====================
//==========================================================
assign sdram_cke = 1'b1;
assign sdram_addr = init_addr;
assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = init_cmd;
assign sdram_dqm = 2'b00;
assign sdram_clk = ~sclk; //内部时钟上升沿采集命令,命令又是由系统时钟上升沿产生的??(为了保证采样时刻处在数据中间时刻)
sdram_init sdram_init_inst(
.sclk (sclk) ,
.srst (srst) ,
.cmd_reg (init_cmd) ,
.sdram_addr (init_addr) ,
.flag_init_end (flag_init_end)
);
endmodule
注意:在代码中设置了一个sdram_clk,它是系统时钟sclk的反相,sdram_clk连接到SDRAM的clk端口,是为了在中间时刻读取传输过来的数据,因为系统时钟上升沿从FPGA中传输数据到SDRAM,如果SDRAM的clk和系统clk保持一致,则在数据传输的一开始就开始写入SDRAM,可能数据传输仍然处在不稳定状态,反相之后可以保证在数据传输的中间时刻写入,保证稳定性。
测试模块代码:
例化了顶层模块,使用了sdram的插件(模仿SDRAM功能)
`timescale 1ns/1ns
module tb_sdram_top;
reg sclk;
reg srst;
//----------------------------------------
wire sdram_clk;
wire sdram_cke;
wire sdram_cs_n;
wire sdram_cas_n;
wire sdram_ras_n;
wire sdram_we_n;
wire [1:0] sdram_bank;
wire [11:0] sdram_addr;
wire [1:0] sdram_dqm;
wire [15:0] sdram_dq;
//----------------------------------------
initial begin
sclk = 1;
srst <= 0;
#100
srst <=1;
end
always #10 sclk = ~sclk;
defparam sdram_model_plus_inst.addr_bits = 12;
defparam sdram_model_plus_inst.data_bits = 16;
defparam sdram_model_plus_inst.col_bits = 9;
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024;//1 M
sdram_top sdram_top_inst(
.sclk (sclk ),
.srst (srst ),
.sdram_clk (sdram_clk ),
.sdram_cke (sdram_cke ),
.sdram_cs_n (sdram_cs_n ),
.sdram_cas_n (sdram_cas_n),
.sdram_ras_n (sdram_ras_n),
.sdram_we_n (sdram_we_n ),
.sdram_bank (sdram_bank ),
.sdram_addr (sdram_addr ),
.sdram_dqm (sdram_dqm ),
.sdram_dq (sdram_dq )
);
sdram_model_plus sdram_model_plus_inst(
.Dq (sdram_dq) ,
.Addr (sdram_addr),
.Ba (sdram_bank),
.Clk (sdram_clk),
.Cke (sdram_cke),
.Cs_n (sdram_cs_n),
.Ras_n (sdram_ras_n),
.Cas_n (sdram_cas_n),
.We_n (sdram_we_n),
.Dqm (sdram_dqm),
.Debug (1'b1)
);
endmodule
SDRAM仿真代码:
/***************************************************************************************
作者: 李晟
2003-08-27 V0.1 李晟
添加内存模块倒空功能,在外部需要创建事件:sdram_r ,本SDRAM的内容将会按Bank 顺序damp out 至文件
sdram_data.txt 中
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
//2004-03-04 陈乃奎 修改原程序中将BANK的数据转存入TXT文件的格式
//2004-03-16 陈乃奎 修改SDRAM 的初始化数据
//2004/04/06 陈乃奎 将SDRAM的操作命令以字符形式表示,以便用MODELSIM监视
//2004/04/19 陈乃奎 修改参数 parameter tAC = 8;
//2010/09/17 罗瑶 修改sdram的大小,数据位宽,dqm宽度;
/****************************************************************************************
*
* File Name: sdram_model.V
* Version: 0.0f
* Date: July 8th, 1999
* Model: BUS Functional
* Simulator: Model Technology (PC version 5.2e PE)
*
* Dependencies: None
*
* Author: Son P. Huynh
* Email: sphuynh@micron.com
* Phone: (208) 368-3825
* Company: Micron Technology, Inc.
* Model: sdram_model (1Meg x 16 x 4 Banks)
*
* Description: 64Mb SDRAM Verilog model
*
* Limitation: - Doesn't check for 4096 cycle refresh
*
* Note: - Set simulator resolution to "ps" accuracy
* - Set Debug = 0 to disable $display messages
*
* Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
* WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
* A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
*
* Copyright ?1998 Micron Semiconductor Products, Inc.
* All rights researved
*
* Rev Author Phone Date Changes
* ---- ---------------------------- ---------- ---------------------------------------
* 0.0f Son Huynh 208-368-3825 07/08/1999 - Fix tWR = 1 Clk + 7.5 ns (Auto)
* Micron Technology Inc. - Fix tWR = 15 ns (Manual)
* - Fix tRP (Autoprecharge to AutoRefresh)
*
* 0.0a Son Huynh 208-368-3825 05/13/1998 - First Release (from 64Mb rev 0.0e)
* Micron Technology Inc.
****************************************************************************************/
`timescale 1ns / 100ps
module sdram_model_plus (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm,Debug);
parameter addr_bits = 13;
parameter data_bits = 16;
parameter col_bits = 9;
parameter mem_sizes = 4*1024*1024 -1;//1 Meg
inout [data_bits - 1 : 0] Dq;
input [addr_bits - 1 : 0] Addr;
input [1 : 0] Ba;
input Clk;
input Cke;
input Cs_n;
input Ras_n;
input Cas_n;
input We_n;
input [1 : 0] Dqm; //高低各8bit
//added by xzli
input Debug;
reg [data_bits - 1 : 0] Bank0 [0 : mem_sizes];//存储器类型数据
reg [data_bits - 1 : 0] Bank1 [0 : mem_sizes];
reg [data_bits - 1 : 0] Bank2 [0 : mem_sizes];
reg [data_bits - 1 : 0] Bank3 [0 : mem_sizes];
reg [1 : 0] Bank_addr [0 : 3]; // Bank Address Pipeline
reg [col_bits - 1 : 0] Col_addr [0 : 3]; // Column Address Pipeline
reg [3 : 0] Command [0 : 3]; // Command Operation Pipeline
reg [3 : 0] Dqm_reg0, Dqm_reg1; // DQM Operation Pipeline
reg [addr_bits - 1 : 0] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr;
reg [addr_bits - 1 : 0] Mode_reg;
reg [data_bits - 1 : 0] Dq_reg, Dq_dqm;
reg [col_bits - 1 : 0] Col_temp, Burst_counter;
reg Act_b0, Act_b1, Act_b2, Act_b3; // Bank Activate
reg Pc_b0, Pc_b1, Pc_b2, Pc_b3; // Bank Precharge
reg [1 : 0] Bank_precharge [0 : 3]