Xilinx VIVADO中DDR3 IP核的使用(2)

项目简述

该项目的描述是,FPGA向DDR3芯片写入数据,然后再读出数据,从而验证读写模块的正确性。该项目具有一定的实际意义,就是我们新制作的一块FPGA板卡,最有可能出问题的部分就是DDR芯片,因为DDR的实际属于高速设计,然后我们将对应的循环测试的程序下载进去,验证我们硬件板卡的正确性。通过本项目,我们可以学到VIVADO MIG的读写DDR3的方法,便可以掌握VIVADO 操作DDR3的操作流程。
本次实验所用到的软件环境:
1、VIVADO2019.1软件开发环境
2、modelsim仿真环境
3、米联客MA7035FA

MIG接口的简单描述

对于生成的MIG IP核,我们现在对其接口信号做出相应的描述,以便于大家可以充分理解信号的作用,

mig_7series_0 mig_7series_0_inst (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr                      ),  // output [13: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 [31:0]     ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n                     ),  // inout [3:0]       ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p                     ),  // inout [3: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 [3:0]     ddr3_dm
    .ddr3_odt                       (ddr3_odt                       ),  // output [0:0]        ddr3_odt
    // Application interface ports
    .app_addr                       (                               ),  // input [27:0]        app_addr
    .app_cmd                        (                               ),  // input [2:0]      app_cmd
    .app_en                         (                               ),  // input             app_en
    .app_wdf_data                   (                               ),  // input [255:0]       app_wdf_data
    .app_wdf_end                    (                               ),  // input                app_wdf_end
    .app_wdf_wren                   (                               ),  // input               app_wdf_wren
    .app_rd_data                    (                               ),  // output [255:0]       app_rd_data
    .app_rd_data_end                (                               ),  // output           app_rd_data_end
    .app_rd_data_valid              (                               ),  // output         app_rd_data_valid
    .app_rdy                        (                               ),  // output           app_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                  (                               ),  // output         app_sr_active
    .app_ref_ack                    (                               ),  // output           app_ref_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 [31:0]        app_wdf_mask
    // System Clock Ports
    .sys_clk_i                      (clk_200m                       ),
    .sys_rst                        (locked                         ) // input sys_rst


    );

查阅技术手册,我们对上面的信号做系列陈述:
1、所有前缀是ddr3的信号,都是与DDR硬件连接的信号,具体含义参考DDR的数据手册,相信如果大家学过SDRAM控制器,对下面的信号很熟悉:
ddr3_addr
ddr3_ba
ddr3_cas_n
ddr3_ck_n
ddr3_ck_p
ddr3_cke
ddr3_ras_n
ddr3_reset_n
ddr3_we_n
ddr3_dq
ddr3_dqs_n
ddr3_dqs_p
init_calib_complete
ddr3_cs_n
ddr3_dm
ddr3_odt
2、init_calib_complete信号,MIG IP核的初始化信号,MIG自我配置成功之后,该信号拉高,对DDR的操作必须等到该位拉高之后进行
3、app_addr信号,提供给我们的地址信号,注意这里与ISE中的不太一样,ISE中的是字节地址,而vivado对应DDR3的实际地址
4、app_cmd信号,用户给DDR芯片的读写命令信号,0是写命令,1是读命令
5、app_en信号,命令路径的使能信号,该信号有效时,app_cmd、app_addr信号才有效,其余的时刻信号无效
6、app_wdf_data信号、数据路径的数据信号
7、app_wdf_end信号,数据一次突发结束信号,4:1模式下与app_wdf_wren相同,2:1模式下app_wdf_wren每两个app_wdf_end使能一次
8、app_wdf_wren信号,写路径数据的有效信号
9、app_wdf_rdy信号,MIG信号给用户的信号,在该信号与app_wdf_wren信号同时有效时,数据被写入DDR芯片
10、app_rd_data信号,DDR3芯片给用户的数据信号
11、app_rd_data_end信号,DDR3给用户读命令结束信号
12、app_rd_data_valid信号,DDR3芯片给用户数据有效信号
13、app_rdy信号,命令路径准备好接受用户的命令信号,与app_en有效时命令有效
14、app_sr_req 、app_ref_req、app_zq_req信号,一系列的请求信号,一般为0代表用户对MIG IP没有强力干预
15、app_sr_active、app_ref_ack、app_zq_ack信号,上面请求的响应信号
16、ui_clk信号,MIG给用户使用的时钟,用户对MIG IP核的操作必须使用该时钟
17、ui_clk_sync_rst信号,MIG给用户使用的复位信号,用户对MIG IP核的操作必须使用该复位信号
18、app_wdf_mask信号,写数据的掩码
19、sys_clk_i信号,MIG的系统时钟,在MIG的选项中选择了200MHz
20、sys_rst信号,MIG IP核的复位信号,与系统时钟相关联

MIG IP的读写时序

我们从技术手册中查找写时序的图形如下:
在这里插入图片描述
当用户逻辑 app_en 信号有效并且 app_rdy 信号有效时,命令被 接受并写入 FIFO。
当 app_rdy 被取消置位时,用户逻辑需要将 app_en 保持为高电平以及有效的命
令和地址值,直到 app_rdy 有效。
在这里插入图片描述
此图描述了 app_wdf_data , app_wdf_wren 和 app_wdf_end 信号的三种场景,
如下所示:
1.写入数据以及相应的写入命令( BL8 的下半部分)。
2.写入数据在相应的写入命令之前。
3.写入数据在相应的写命令之后,不应超过两个时钟周期的限制。
对于在写入命令后输出的写入数据,如注 3 所示,最大延迟为两个时钟周期。
上面的模式时no-back-back模式,当是back-back模式的情况下,没有最大延迟的限制
在这里插入图片描述
上面便是back-back模式,通俗来讲就是命令是连续的。
在这里插入图片描述
读时序如上图,读取的数据由 MIG以请求的顺序返回,并且在 app_rd_data_valid 有效时数据有效。app_rd_data_end 信号表示每个读命令脉冲串的结束,在用户逻辑中不需要。

MIG IP循环校验设计时序

读写设计的时序如下图,以下两张图是一个模块的时序设计图,为了观看方便我们截了两张图片:
在这里插入图片描述
在这里插入图片描述
有了上面的时序图,我们可以比较方便的设计出响应的逻辑代码。

MIG IP的读写循环代码

ddr3_top模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : ddr3_top.v
// Create Time  : 2020-02-27 23:16:16
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module ddr3_top(
    //System Interfaces
    input                       sclk                    ,
    input                       rst_n                   ,
    //DDR3 Interfaces           
    output  wire    [13:0]      ddr3_addr               ,
    output  wire    [ 2:0]      ddr3_ba                 ,
    output  wire                ddr3_cas_n              ,
    output  wire                ddr3_ck_n               ,
    output  wire                ddr3_ck_p               ,
    output  wire                ddr3_cke                ,
    output  wire                ddr3_ras_n              ,
    output  wire                ddr3_reset_n            ,
    output  wire                ddr3_we_n               ,
    inout           [31:0]      ddr3_dq                 ,
    inout           [ 3:0]      ddr3_dqs_n              ,
    inout           [ 3:0]      ddr3_dqs_p              ,
    output  wire    [ 0:0]      ddr3_cs_n               ,
    output  wire    [ 3:0]      ddr3_dm                 ,
    output  wire    [ 0:0]      ddr3_odt                
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
wire                            locked                  ;
wire                            clk_200m                ; 
//mig_7series_0_inst 
wire                            init_calib_complete     ;  
wire                [27:0]      app_addr                ;
wire                [ 2:0]      app_cmd                 ;
wire                            app_en                  ;
wire                [255:0]     app_wdf_data            ;
wire                            app_wdf_end             ;
wire                            app_wdf_wren            ;
wire                [255:0]     app_rd_data             ;
wire                            app_rd_data_end         ;
wire                            app_rd_data_valid       ;
wire                            app_rdy                 ;
wire                            app_wdf_rdy             ;
wire                [31:0]      app_wdf_mask            ;
wire                            ui_clk                  ;
wire                            ui_clk_sync_rst         ;
//Debug
wire                            test_start              ;
wire                            test_busy               ;
wire                [63:0]      error_num               ;
wire                            error_done              ;
wire                            test                    ;
reg                             test_r                  ;
reg                             test_r2                 ;
reg                             test_r3                 ;        
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/

clk_wiz_0 clk_wiz_0_inst(
    // Clock out ports
    .clk_out1                       (clk_200m                       ),     // output clk_out1
    // Status and control signals
    .reset                          (~rst_n                         ), // input reset
    .locked                         (locked                         ),       // output locked
    // Clock in ports
    .clk_in1                        (sclk                           )
);      // input clk_in1

mig_7series_0 mig_7series_0_inst (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr                      ),  // output [13: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 [31:0]     ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n                     ),  // inout [3:0]       ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p                     ),  // inout [3: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 [3:0]     ddr3_dm
    .ddr3_odt                       (ddr3_odt                       ),  // output [0:0]        ddr3_odt
    // Application interface ports
    .app_addr                       (app_addr                       ),  // input [27:0]        app_addr
    .app_cmd                        (app_cmd                        ),  // input [2:0]      app_cmd
    .app_en                         (app_en                         ),  // input             app_en
    .app_wdf_data                   (app_wdf_data                   ),  // input [255:0]       app_wdf_data
    .app_wdf_end                    (app_wdf_end                    ),  // input                app_wdf_end
    .app_wdf_wren                   (app_wdf_wren                   ),  // input               app_wdf_wren
    .app_rd_data                    (app_rd_data                    ),  // output [255: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                  (                               ),  // output         app_sr_active
    .app_ref_ack                    (                               ),  // output           app_ref_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 [31:0]        app_wdf_mask
    // System Clock Ports
    .sys_clk_i                      (clk_200m                       ),
    .sys_rst                        (locked                         ) // input sys_rst
    );

ddr3_drive ddr3_drive_inst(
    //DDR3 Interfaces
    .ui_clk                         (ui_clk                         ),
    .ui_clk_sync_rst                ((~ui_clk_sync_rst) && init_calib_complete),
    .app_addr                       (app_addr                       ),
    .app_cmd                        (app_cmd                        ),
    .app_en                         (app_en                         ),
    .app_rdy                        (app_rdy                        ),
    .app_wdf_data                   (app_wdf_data                   ),
    .app_wdf_mask                   (app_wdf_mask                   ),
    .app_wdf_rdy                    (app_wdf_rdy                    ),
    .app_wdf_wren                   (app_wdf_wren                   ),
    .app_wdf_end                    (app_wdf_end                    ),
    .app_rd_data                    (app_rd_data                    ),
    .app_rd_data_valid              (app_rd_data_valid              ),
    //Debug
    .test_start                     (test_start                     ),
    .test_busy                      (test_busy                      ),
    .error_num                      (error_num                      ),
    .error_done                     (error_done                     )

);
 
//========================================================================================\
//*******************************     Debug    **********************************
//========================================================================================/
always @(posedge sclk)begin
    test_r              <=      test;
    test_r2             <=      test_r;
    test_r3             <=      test_r2;
end
assign      test_start      =       ~test_r3 && test_r2;
    
vio_0 vio_0_inst (
    .clk                                (ui_clk                         ),                // input wire clk
    .probe_out0                         (test                           )  // output wire [0 : 0] probe_out0
);

ila_0 ila_0_inst (
    .clk                                (ui_clk                         ), // input wire clk

    .probe0                             (app_addr                       ), // input wire [27:0]  probe0  
    .probe1                             (app_cmd                        ), // input wire [2:0]  probe1 
    .probe2                             (app_en                         ), // input wire [0:0]  probe2 
    .probe3                             (app_rdy                        ), // input wire [0:0]  probe3 
    .probe4                             (app_wdf_data                   ), // input wire [255:0]  probe4 
    .probe5                             (app_wdf_mask                   ), // input wire [31:0]  probe5 
    .probe6                             (app_wdf_rdy                    ), // input wire [0:0]  probe6 
    .probe7                             (app_wdf_wren                   ), // input wire [0:0]  probe7 
    .probe8                             (app_wdf_end                    ), // input wire [0:0]  probe8 
    .probe9                             (app_rd_data                    ), // input wire [255:0]  probe9 
    .probe10                            (app_rd_data_valid              ), // input wire [0:0]  probe10 
    .probe11                            (test_start                     ), // input wire [0:0]  probe11 
    .probe12                            (test_busy                      ), // input wire [0:0]  probe12 
    .probe13                            (error_num                      ), // input wire [63:0]  probe13 
    .probe14                            (error_done                     ) // input wire [0:0]  probe14
);

endmodule

ddr3_drive模块

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : ddr3_drive.v
// Create Time  : 2020-02-28 22:10:02
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module ddr3_drive(
    //DDR3 Interfaces
    input                   ui_clk                  ,
    input                   ui_clk_sync_rst         ,
    output  wire    [27:0]  app_addr                ,
    output  reg     [ 2:0]  app_cmd                 ,
    output  reg             app_en                  ,
    input                   app_rdy                 ,
    output  reg     [255:0] app_wdf_data            ,
    output  wire    [31:0]  app_wdf_mask            ,
    input                   app_wdf_rdy             ,
    output  reg             app_wdf_wren            ,
    output  wire            app_wdf_end             ,             
    input           [255:0] app_rd_data             ,
    input                   app_rd_data_valid       ,
    //Debug
    input                   test_start              ,
    output  reg             test_busy               ,
    output  reg     [63:0]  error_num               ,
    output  reg             error_done          

);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter   BL_NUM_END      =   1048576             ;
//parameter   BL_NUM_END      =   100                 ;
parameter   BL_LENGTH       =   16                  ;
parameter   CMD_WR          =   3'b000              ;
parameter   CMD_RD          =   3'b001              ;

reg                 [20:0]  bl_cnt                  ; 
reg                 [ 6:0]  cmd_cnt                 ; 
reg                 [27:0]  wr_addr                 ; 
reg                         app_en_r                ;
reg                 [ 6:0]  wr_cnt                  ;
reg                 [ 6:0]  rd_cnt                  ;
reg                 [27:0]  rd_addr                 ;
reg                 [255:0] check_data              ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign 	app_wdf_mask 		= 		32'd0; 	
assign  app_wdf_end         =       app_wdf_wren;
assign  app_addr            =       app_cmd == CMD_RD ? rd_addr : wr_addr;	

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        test_busy           <=      1'b0;
    else if(test_start == 1'b1)
        test_busy           <=      1'b1;
    else if(bl_cnt == (BL_NUM_END-1'b1) && rd_cnt == BL_LENGTH)
        test_busy           <=      1'b0;
    else
        test_busy           <=      test_busy;
   
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        app_en              <=      1'b0;          
    else if(test_busy == 1'b0 && test_start == 1'b1)
        app_en              <=      1'b1;
    else if(cmd_cnt == BL_LENGTH && wr_cnt == BL_LENGTH) 
        app_en              <=      1'b1;
    else if(bl_cnt < (BL_NUM_END-1'b1) && rd_cnt == BL_LENGTH)
        app_en              <=      1'b1;
    else if(cmd_cnt == (BL_LENGTH-1) && app_rdy == 1'b1)
        app_en              <=      1'b0;
    else
        app_en              <=      app_en;
        
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        app_cmd             <=      CMD_WR;    
    else if(test_busy == 1'b0 && test_start == 1'b1) 
        app_cmd             <=      CMD_WR;
    else if(cmd_cnt == BL_LENGTH && wr_cnt == BL_LENGTH)
        app_cmd             <=      CMD_RD;
    else if(rd_cnt == BL_LENGTH)
        app_cmd             <=      CMD_WR;
    else 
        app_cmd             <=      app_cmd;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        cmd_cnt             <=      7'd0;
    else if(cmd_cnt == BL_LENGTH && wr_cnt == BL_LENGTH) 
        cmd_cnt             <=      7'd0;
    else if(cmd_cnt == BL_LENGTH && rd_cnt == BL_LENGTH)
        cmd_cnt             <=      7'd0;
    else if(app_en == 1'b1 && app_rdy == 1'b1)
        cmd_cnt             <=      cmd_cnt + 1'b1;
    else
        cmd_cnt             <=      cmd_cnt;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        wr_addr             <=      28'd0;
    else if(test_start == 1'b1 && test_busy == 1'b0)
        wr_addr             <=      28'd0;
    else if(app_en == 1'b1 && app_rdy == 1'b1 && app_cmd == CMD_WR)
        wr_addr             <=      wr_addr + 8;
    else 
        wr_addr             <=      wr_addr; 

always @(posedge ui_clk)
    app_en_r                <=      app_en;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        app_wdf_wren        <=      1'b0;
    else if(wr_cnt == BL_LENGTH-1 && app_wdf_rdy == 1'b1)
        app_wdf_wren        <=      1'b0;
    else if(app_cmd == CMD_WR && app_en_r == 1'b1 && wr_cnt < BL_LENGTH)
        app_wdf_wren        <=      1'b1;
    else 
        app_wdf_wren        <=      app_wdf_wren;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        app_wdf_data        <=      256'd0;    
    else if(app_wdf_wren == 1'b1 && app_wdf_rdy == 1'b1)
        app_wdf_data        <=      app_wdf_data + 1'b1;
    else
        app_wdf_data        <=      app_wdf_data;
          
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        wr_cnt              <=      7'd0;
    else if(wr_cnt == BL_LENGTH && cmd_cnt == BL_LENGTH) 
        wr_cnt              <=      7'd0;
    else if(app_wdf_wren == 1'b1 && app_wdf_rdy == 1'b1)
        wr_cnt              <=      wr_cnt + 1'b1;
    else
        wr_cnt              <=      wr_cnt;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        rd_cnt              <=      7'd0;   
    else if(rd_cnt == BL_LENGTH)
        rd_cnt              <=      7'd0;
    else if(app_rd_data_valid == 1'b1)
        rd_cnt              <=      rd_cnt + 1'b1;
    else
        rd_cnt              <=      rd_cnt;
                  
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        rd_addr             <=      28'd0;    
    else if(test_start == 1'b1 && test_busy == 1'b0)
        rd_addr             <=      28'd0;
    else if(app_en == 1'b1 && app_rdy == 1'b1 && app_cmd == CMD_RD)
        rd_addr             <=      rd_addr + 8;
    else
        rd_addr             <=      rd_addr;
        
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        bl_cnt              <=      21'd0;    
    else if(bl_cnt == BL_NUM_END-1 && rd_cnt == BL_LENGTH)
        bl_cnt              <=      21'd0;
    else if(rd_cnt == BL_LENGTH)
        bl_cnt              <=      bl_cnt + 1'b1;
    else
        bl_cnt              <=      bl_cnt;
          
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        check_data          <=      256'd0;   
    else if(app_rd_data_valid == 1'b1)
        check_data          <=      check_data + 1'b1;
    else 
        check_data          <=      check_data;

always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        error_num           <=      64'd0;     
    else if(test_start == 1'b1)
        error_num           <=      64'd0;
    else if(app_rd_data_valid == 1'b1 && check_data != app_rd_data) 
        error_num           <=      error_num + 1'b1;
    else
        error_num           <=      error_num;
        
always @(posedge ui_clk or negedge ui_clk_sync_rst)
    if(ui_clk_sync_rst == 1'b0)
        error_done          <=      1'b0;    
    else if(bl_cnt == BL_NUM_END-1 && rd_cnt == BL_LENGTH) 
        error_done          <=      1'b1;
    else
        error_done          <=      1'b0;
                                                                                                              
endmodule

测试模块代码

tb_ddr3模块:

`timescale 1ns / 1ps
`define     CLOCK   20

// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : tb_ddr3.v
// Create Time  : 2020-02-27 23:36:46
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module tb_ddr3;

parameter  DQ_WIDTH             = 32;
localparam MEMORY_WIDTH         = 16;
localparam NUM_COMP             = DQ_WIDTH/MEMORY_WIDTH ;

reg                             sclk                    ;
reg                             rst_n                   ;

wire                [13:0]      ddr3_addr               ;
wire                [ 2:0]      ddr3_ba                 ;
wire                            ddr3_cas_n              ;
wire                            ddr3_ck_n               ;
wire                            ddr3_ck_p               ;
wire                            ddr3_cke                ;
wire                            ddr3_ras_n              ;
wire                            ddr3_reset_n            ;
wire                            ddr3_we_n               ;
wire                [31:0]      ddr3_dq                 ;
wire                [ 3:0]      ddr3_dqs_n              ;
wire                [ 3:0]      ddr3_dqs_p              ;
wire                            init_calib_complete     ;
wire                [ 0:0]      ddr3_cs_n               ;
wire                [ 3:0]      ddr3_dm                 ;
wire                [ 0:0]      ddr3_odt                ;

reg                             test_start              ;

initial begin
    sclk            =           1'b0;
    rst_n           <=          1'b0;
    test_start      <=          1'b0;
    #(100*`CLOCK);
    rst_n           <=          1'b1;
    @(posedge init_calib_complete)
    #(100*`CLOCK);
    test_start      <=          1'b1;
    #(10)
    test_start      <=          1'b0;
    #(100000)
    test_start      <=          1'b1;
    #(10)
    test_start      <=          1'b0;
end
always  #(`CLOCK/2)     sclk        =       ~sclk;

ddr3_top ddr3_top_inst(
    //System Interfaces
    .sclk                       (sclk                       ),
    .rst_n                      (rst_n                      ),
    //DDR3 Interfaces           
    .ddr3_addr                  (ddr3_addr                  ),
    .ddr3_ba                    (ddr3_ba                    ),
    .ddr3_cas_n                 (ddr3_cas_n                 ),
    .ddr3_ck_n                  (ddr3_ck_n                  ),
    .ddr3_ck_p                  (ddr3_ck_p                  ),
    .ddr3_cke                   (ddr3_cke                   ),
    .ddr3_ras_n                 (ddr3_ras_n                 ),
    .ddr3_reset_n               (ddr3_reset_n               ),
    .ddr3_we_n                  (ddr3_we_n                  ),
    .ddr3_dq                    (ddr3_dq                    ),
    .ddr3_dqs_n                 (ddr3_dqs_n                 ),
    .ddr3_dqs_p                 (ddr3_dqs_p                 ),
    .init_calib_complete        (init_calib_complete        ),
    .ddr3_cs_n                  (ddr3_cs_n                  ),
    .ddr3_dm                    (ddr3_dm                    ),
    .ddr3_odt                   (ddr3_odt                   ),
    .test_start                 (test_start                 )          
);

genvar i;

for (i = 0; i < NUM_COMP; i = i + 1) begin: gen_mem
    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[(2*(i+1)-1):(2*i)]         ),
        .ba                     (ddr3_ba                            ),
        .addr                   (ddr3_addr                          ),
        .dq                     (ddr3_dq[16*(i+1)-1:16*(i)]         ),
        .dqs                    (ddr3_dqs_p[(2*(i+1)-1):(2*i)]      ),
        .dqs_n                  (ddr3_dqs_n[(2*(i+1)-1):(2*i)]      ),
        .tdqs_n                 (                                   ),
        .odt                    (ddr3_odt                           )
    );
    end

endmodule

仿真现象

我们进行modelsim仿真,得到的实验结果入下:
在这里插入图片描述
从上图中,我们可以看到误码个数为零,从而证明了我们程序的正确性,其中上面给出的源码是下板实验的最终代码,只需要稍微调整便可以在moselsim中运行,讲test_start不由vio产生,有tb产生即可。

上板调试

我们将对应的程序下到开发板中,对应的现象如下图:
在这里插入图片描述
从上图中,我们可以看出没错错误的情况,从而验证了我们程序的正确性。

结束语

对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

发布了42 篇原创文章 · 获赞 23 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zhangningning1996/article/details/104562722