目录
实验任务
对 DDR3 进行初始化测试,通过前面调取的 MIG IP核共同完成测试。
实验环境
开发环境:Vivado 2018.2
FPGA 芯片型号:xc7a100tffg484-2
DDR3 型号:MT41J256M16HA-125
实验介绍
由于在使用 DDR3 控制器 MIG 时,在刚上电的时候不能立即进行读写操作,而是要等待一段时间(大概100us),等待 DDR3 控制器 MIG IP核初始化完成后,才可以开始进行读写操作,这个实验的目的就是对 DDR3 控制器进行初始化测试。
程序设计
创建顶层文件
需要注意的是,由于板子上提供的时钟为 50MHz,而在 MIG IP 配置时,输入的系统系统时钟为 200MHz,因此需要添加一个 PLL IP 核对输入的时钟进行倍频到 200MHz。
配置如下,调用并在顶层文件中对其进行例化。
具体代码如下:
暂时不用的信号比如读使能、地址等信号可以直接给赋值即可。
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Engineer : Linest-5
/* File : top_ddr3_init.v
/* Create : 2022-09-15 09:58:59
/* Revise : 2022-09-25 11:27:52
/* Module Name : top_ddr3_init
/* Description : ddr3初始化顶层模块
/* Editor : sublime text3, tab size (2)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module top_ddr3_init(
// Inouts
inout [15:0] ddr3_dq,
inout [1:0] ddr3_dqs_n,
inout [1:0] ddr3_dqs_p,
// Outputs
output [14:0] ddr3_addr,
output [2:0] ddr3_ba,
output ddr3_ras_n,
output ddr3_cas_n,
output ddr3_we_n,
output ddr3_reset_n,
output [0:0] ddr3_ck_p,
output [0:0] ddr3_ck_n,
output [0:0] ddr3_cke,
output [0:0] ddr3_cs_n,
output [1:0] ddr3_dm,
output [0:0] ddr3_odt,
// Inputs
// Differential system clocks
input sys_clk,
input rst_n
);
wire init_calib_complete;
wire ui_clk;
wire ui_clk_sync_rst;
ddr3_clock ddr3_clock_inst(
// Clock out ports
.clk_out1(sys_clk_in), // output clk_out1
// Clock in ports
.clk_in1(sys_clk)
); // input clk_in1
ddr3_init u_ddr3_init (
// Memory interface ports
.ddr3_addr (ddr3_addr), // output [14:0] ddr3_addr
.ddr3_ba (ddr3_ba), // output [2:0] ddr3_ba
.ddr3_cas_n (ddr3_cas_n), // output ddr3_cas_n
.ddr3_ck_n (ddr3_ck_n), // output [0:0] ddr3_ck_n
.ddr3_ck_p (ddr3_ck_p), // output [0:0] ddr3_ck_p
.ddr3_cke (ddr3_cke), // output [0:0] ddr3_cke
.ddr3_ras_n (ddr3_ras_n), // output ddr3_ras_n
.ddr3_reset_n (ddr3_reset_n), // output ddr3_reset_n
.ddr3_we_n (ddr3_we_n), // output ddr3_we_n
.ddr3_dq (ddr3_dq), // inout [15:0] ddr3_dq
.ddr3_dqs_n (ddr3_dqs_n), // inout [1:0] ddr3_dqs_n
.ddr3_dqs_p (ddr3_dqs_p), // inout [1:0] ddr3_dqs_p
.init_calib_complete (init_calib_complete), // output init_calib_complete
.ddr3_cs_n (ddr3_cs_n), // output [0:0] ddr3_cs_n
.ddr3_dm (ddr3_dm), // output [1:0] ddr3_dm
.ddr3_odt (ddr3_odt), // output [0:0] ddr3_odt
// Application interface ports
.app_addr (app_addr), // input [28:0] app_addr
.app_cmd (app_cmd), // input [2:0] app_cmd
.app_en (1'b0), // input app_en
.app_wdf_data (app_wdf_data), // input [127:0] app_wdf_data
.app_wdf_end (1'b0), // input app_wdf_end
.app_wdf_wren (1'b0), // input app_wdf_wren
.app_rd_data (app_rd_data), // output [127:0] app_rd_data
.app_rd_data_end (app_rd_data_end), // output app_rd_data_end
.app_rd_data_valid (app_rd_data_valid), // output app_rd_data_valid
.app_rdy (app_rdy), // output app_rdy
.app_wdf_rdy (app_wdf_rdy), // output app_wdf_rdy
.app_sr_req (1'b0), // input app_sr_req
.app_ref_req (1'b0), // input app_ref_req
.app_zq_req (1'b0), // input app_zq_req
.app_sr_active (app_sr_active), // output app_sr_active
.app_ref_ack (app_ref_ack), // output app_ref_ack
.app_zq_ack (app_zq_ack), // output app_zq_ack
.ui_clk (ui_clk), // output ui_clk
.ui_clk_sync_rst (ui_clk_sync_rst), // output ui_clk_sync_rst
.app_wdf_mask (app_wdf_mask), // input [15:0] app_wdf_mask
// System Clock Ports
.sys_clk_i (sys_clk_in), // input sys_clk_i
.sys_rst (rst_n) // input sys_rst
);
endmodule
testbench 代码
在 example design 中 调用 DDR3 的仿真模型,将这两个文件放到仿真文件中,并在 Vivado 添加调用。
以下为测试代码,主要就是例化顶层文件,产生时钟和复位激励,并需要例化 DDR3 的仿真模型,否则仿真无法实现!
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Engineer : Linest-5
// File : tb_top_ddr3_init.v
// Create : 2022-09-25 15:20:55
// Revise : 2022-09-25 15:20:57
// Module Name : tb_top_ddr3_init
// Description : ddr3初始化顶层测试模块
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns / 1ps
module tb_top_ddr3_init();
reg sys_clk;
reg rst_n;
wire [15:0] ddr3_dq;
wire [1:0] ddr3_dqs_n;
wire [1:0] ddr3_dqs_p;
wire [14:0] ddr3_addr;
wire [2:0] ddr3_ba;
wire ddr3_ras_n;
wire ddr3_cas_n;
wire ddr3_we_n;
wire ddr3_reset_n;
wire [0:0] ddr3_ck_p;
wire [0:0] ddr3_ck_n;
wire [0:0] ddr3_cke;
wire [0:0] ddr3_cs_n;
wire [1:0] ddr3_dm;
wire [0:0] ddr3_odt;
initial begin
sys_clk = 'd1;
rst_n <= 'd0;
#200
rst_n <= 'd1;
end
always #10 sys_clk = ~sys_clk;
top_ddr3_init inst_top_ddr3_init (
.ddr3_dq (ddr3_dq),
.ddr3_dqs_n (ddr3_dqs_n),
.ddr3_dqs_p (ddr3_dqs_p),
.ddr3_addr (ddr3_addr),
.ddr3_ba (ddr3_ba),
.ddr3_ras_n (ddr3_ras_n),
.ddr3_cas_n (ddr3_cas_n),
.ddr3_we_n (ddr3_we_n),
.ddr3_reset_n (ddr3_reset_n),
.ddr3_ck_p (ddr3_ck_p),
.ddr3_ck_n (ddr3_ck_n),
.ddr3_cke (ddr3_cke),
.ddr3_cs_n (ddr3_cs_n),
.ddr3_dm (ddr3_dm),
.ddr3_odt (ddr3_odt),
.sys_clk (sys_clk),
.rst_n (rst_n)
);
ddr3_model u_comp_ddr3 (
.rst_n (ddr3_reset_n),
.ck (ddr3_ck_p),
.ck_n (ddr3_ck_n),
.cke (ddr3_cke),
.cs_n (ddr3_cs_n),
.ras_n (ddr3_ras_n),
.cas_n (ddr3_cas_n),
.we_n (ddr3_we_n),
.dm_tdqs ({ddr3_dm[1],ddr3_dm[0]}),
.ba (ddr3_ba),
.addr (ddr3_addr),
.dq (ddr3_dq[15:0]),
.dqs ({ddr3_dqs_p[1],
ddr3_dqs_p[0]}),
.dqs_n ({ddr3_dqs_n[1],
ddr3_dqs_n[0]}),
.tdqs_n (),
.odt (ddr3_odt)
);
endmodule
仿真测试
利用 Vivado 自带的仿真对初始化进行测试,进行行为仿真测试,将top模块的信号添加到波形窗口中。
下图为仿真波形,可以看到 init_calib_complete 信号拉高就表示 DDR 控制器 MIG 核初始化成功,就可以进行读写操作了。其他信号可以暂时不管。