調取 DDR3 IP核后,是不能直接進行讀寫測試的,必須先進行初始化操作,對 IP 核進行校驗。本篇采用 Modelsim 軟件配合 DDR3 IP核生成的仿真模型,搭建出 IP核的初始化過程。
一、頂層文件
1、生成 DDR3 IP 核后,在 Source 界面空白處右鍵點擊 Add Source,添加頂層文件。
2、在 DDR3_HDMI\DDR3_HDMI.srcs\sources_1\ip\ddr3_ctrl\ddr3_ctrl\user_design\rtl\ddr3_ctrl.v 可得到 top_ddr3_hdmi 需要的輸入輸出端口,將其復制過來。
//========================< 端口 >========================================== ( //system ---------------------------------------- input wire sclkin , //50Mhz input wire srst_n , //復位,低電平有效 //DDR3 ------------------------------------------ inout wire [15:0] ddr3_dq , inout wire [ 1:0] ddr3_dqs_n , inout wire [ 1:0] ddr3_dqs_p , output wire [13:0] ddr3_addr , output wire [ 2:0] ddr3_ba , output wire ddr3_ras_n , output wire ddr3_cas_n , output wire ddr3_we_n , output wire ddr3_reset_n , output wire [ 0:0] ddr3_ck_p , output wire [ 0:0] ddr3_ck_n , output wire [ 0:0] ddr3_cke , output wire [ 0:0] ddr3_cs_n , output wire [ 1:0] ddr3_dm , output wire [ 0:0] ddr3_odt );
3、對頂層模塊進行編寫,可以進入 IP Source 的 ddr3_ctrl.veo文件找到接口復制過來例化,並根據需求更改部分信號,仿真時希望app接口不工作,所有輸入接口連接為 0
//DDR3_IP核 ----------------------------------------------------------------- ddr3_ctrl u_ddr3_ctrl //輸入為200Mhz,芯片需400Mhz,內部速率為4:1 = 100Mhz ( // Memory interface ports ---------------------------------------- .ddr3_addr (ddr3_addr ), // output [13:0] .ddr3_ba (ddr3_ba ), // output [ 2:0] .ddr3_cas_n (ddr3_cas_n ), // output .ddr3_ck_n (ddr3_ck_n ), // output .ddr3_ck_p (ddr3_ck_p ), // output .ddr3_cke (ddr3_cke ), // output .ddr3_ras_n (ddr3_ras_n ), // output .ddr3_reset_n (ddr3_reset_n ), // output .ddr3_we_n (ddr3_we_n ), // output .ddr3_dq (ddr3_dq ), // inout [15:0] .ddr3_dqs_n (ddr3_dqs_n ), // inout [ 1:0] .ddr3_dqs_p (ddr3_dqs_p ), // inout [ 1:0] .init_calib_complete (init_calib_complete ), // output .ddr3_cs_n (ddr3_cs_n ), // output .ddr3_dm (ddr3_dm ), // output [ 1:0] .ddr3_odt (ddr3_odt ), // output // Application interface ports ----------------------------------- .app_addr ( ), // input [27:0] .app_cmd ( ), // input [ 2:0] .app_en ( ), // input .app_wdf_data ( ), // input [127:0] .app_wdf_end ( ), // input .app_wdf_wren ( ), // input .app_rd_data ( ), // output [127:0] .app_rd_data_end ( ), // output .app_rd_data_valid ( ), // output .app_rdy ( ), // output .app_wdf_rdy ( ), // output .app_sr_req ( ), // input .app_ref_req ( ), // input .app_zq_req ( ), // input .app_sr_active ( ), // output .app_ref_ack ( ), // output .app_zq_ack ( ), // output .ui_clk ( ), // output 100Mhz .ui_clk_sync_rst ( ), // output .app_wdf_mask ( ), // input [15:0] // System Clock Ports -------------------------------------------- .sys_clk_i (sysclk ), // input 200Mhz .sys_rst (srst_n ) // input 系統復位 );
4、調取 DDR3 IP 核時,選擇了對此 IP 核輸入一個200 Mhz 的時鍾,由於板卡晶振生成的時鍾為 50Mhz,所以還得用一個 IP 核來生出 200 Mhz 時鍾。
5、生成時鍾后同樣找到 .veo 文件接口復制過來例化。
//時鍾_IP核 ---------------------------------------------------------------- ddr3_clk_gen u_ddr3_clk_gen ( .clk_in1 (sclkin ), // input clk_in1 .clk_out1 (sysclk ) // output clk_out1 );
7、有幾個信號是我們需要觀察的,用 wire 引出來吧。
//========================< 連線 >========================================== //PLL ------------------------------------------- wire sysclk ; // ddr3 ip -------------------------------------- wire app_rdy ; wire app_wdf_rdy ; wire app_en ; wire [27:0] app_addr ; wire [ 2:0] app_cmd ; wire [15:0] app_wdf_mask ; wire app_wdf_wren ; wire [127:0] app_wdf_data ; wire app_wdf_end ; wire [127:0] app_rd_data ; wire app_rd_data_valid ; wire app_rd_data_end ; wire ui_clk ; wire ui_clk_sync_rst ; wire init_calib_complete ;
二、測試文件
1、在 Simulation Sources 右鍵選擇 Add Sources,創建 testbench 文件。
2、首先還是把輸入輸出接口和 top 模塊接口在 testbench 中寫好。
1 `timescale 1ns/1ps //時間精度 2 `define Clock 20 //時鍾周期 3 4 module top_ddr3_hdmi_tb; 5 //========================< 端口 >========================================== 6 reg clk ; 7 reg rst_n ; 8 wire [15:0] ddr3_dq ; 9 wire [ 1:0] ddr3_dqs_n ; 10 wire [ 1:0] ddr3_dqs_p ; 11 wire [13:0] ddr3_addr ; 12 wire [ 2:0] ddr3_ba ; 13 wire ddr3_ras_n ; 14 wire ddr3_cas_n ; 15 wire ddr3_we_n ; 16 wire ddr3_reset_n ; 17 wire [ 0:0] ddr3_ck_p ; 18 wire [ 0:0] ddr3_ck_n ; 19 wire [ 0:0] ddr3_cke ; 20 wire [ 0:0] ddr3_cs_n ; 21 wire [ 1:0] ddr3_dm ; 22 wire [ 0:0] ddr3_odt ; 23 24 //========================================================================== 25 //== 模塊例化 26 //========================================================================== 27 //頂層模塊 28 top_ddr3_hdmi u_top_ddr3_hdmi 29 ( 30 .ddr3_dq (ddr3_dq ), 31 .ddr3_dqs_n (ddr3_dqs_n ), 32 .ddr3_dqs_p (ddr3_dqs_p ), 33 .ddr3_addr (ddr3_addr ), 34 .ddr3_ba (ddr3_ba ), 35 .ddr3_ras_n (ddr3_ras_n ), 36 .ddr3_cas_n (ddr3_cas_n ), 37 .ddr3_we_n (ddr3_we_n ), 38 .ddr3_reset_n (ddr3_reset_n ), 39 .ddr3_ck_p (ddr3_ck_p ), 40 .ddr3_ck_n (ddr3_ck_n ), 41 .ddr3_cke (ddr3_cke ), 42 .ddr3_cs_n (ddr3_cs_n ), 43 .ddr3_dm (ddr3_dm ), 44 .ddr3_odt (ddr3_odt ), 45 .sclkin (clk ), 46 .srst_n (rst_n ) 47 );
3、DDR3 控制器非常復雜,手寫 testbench 是非常困難的。我們上一講調取 DDR3 IP 核時說過,它已經生成了仿真模型供我們測試。位置在 DDR3_HDMI\DDR3_HDMI.srcs\sources_1\ip\ddr3_ctrl\ddr3_ctrl\example_design\sim,ddr3_model.sv 和 ddr3_model_parameters.vh 即是我們需要的仿真模型,將其復制到 DDR3_HDMI\DDR3_HDMI.srcs\sim_1\new 中,和 top_ddr3_hdmi_tb 文件放在一起。此外還可以看到剛剛那個文件夾中有一個 sim_tb_top 文件,打開它翻到500多行,即可看到該仿真模型的接口模塊,我們將其復制到 testbench 中,並根據此次設計情況,更改部分參數。
1 //仿真模型 2 ddr3_model u_ddr3_model 3 ( 4 .rst_n (ddr3_reset_n ), 5 .ck (ddr3_ck_p ), 6 .ck_n (ddr3_ck_n ), 7 .cke (ddr3_cke ), 8 .cs_n (ddr3_cs_n ), 9 .ras_n (ddr3_ras_n ), 10 .cas_n (ddr3_cas_n ), 11 .we_n (ddr3_we_n ), 12 .dm_tdqs ({ddr3_dm[1],ddr3_dm[0]} ), //ddr3_dm為2位 13 .ba (ddr3_ba ), 14 .addr (ddr3_addr ), 15 .dq (ddr3_dq[15:0] ), //ddr3_dq為16位 16 .dqs ({ddr3_dqs_p[1],ddr3_dqs_p[0]} ), //ddr3_dqs_p為2位 17 .dqs_n ({ddr3_dqs_n[1],ddr3_dqs_n[0]} ), //ddr3_dqs_n為2位 18 .tdqs_n ( ), 19 .odt (ddr3_odt ) 20 );
3、此外還需要產生一個 50 Mhz 時鍾和低電平有效的復位信號。
1 //========================================================================== 2 //== 時鍾信號和復位信號 3 //========================================================================== 4 initial begin 5 clk = 0; 6 forever 7 #(`Clock/2) clk = ~clk; 8 end 9 10 initial begin 11 rst_n = 0; #(`Clock*20+1); 12 rst_n = 1; 13 end
4、回到 Vivado,發現仿真模型文件已經出現了,但是處於問號狀態,我們選中它,右鍵 Add Sources,將 ddr3_model.sv 和 ddr3_model_parameters.vh 添加進來即可。
三、啟動 Modelsim 驗證 DDR3 IP核
1、使用 Modelsim 進行仿真前,需要先編譯 Vivado 和 Modelsim 之間的關聯庫,具體步驟請另行搜索。
2、點擊 Vivado 的 Setting 進行設置,Target simulator 選擇 ModelSim Simulator,仿真頂層文件選擇第二步的仿真文件,仿真庫則自動定位好了。
3、點擊 Vivado 左側菜單 Run Simulation --- Run Behavioral Simulation,Modelsim 就自動打開仿真了。
4、選取信號,跑一段時間,可以看到時鍾信號和復位信號正常, init_calib_complete 信號在拉低一段時間后拉高,表面本次 DDR3 IP核驗證成功。
以上。
參考資料:威三學院FPGA教程