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

ISE 中基于mig IP完成DDR3的循环测试

  • 项目简述
  • MIG接口的简单描述
  • MIG IP的读写时序
  • MIG IP的读写循环代码
  • MIG IP的读写循环测试代码
  • 仿真结果
  • 总结

项目简述

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

MIG接口的简单描述

IP的FIFO结构图分别如下:
Xilinx ISE中DDR3 IP核的使用(2)_第1张图片
对于生成的MIG IP核,我们现在对其接口信号做出相应的描述,以便于大家可以充分理解信号的作用,

mig_39_2 # (
    .C3_P0_MASK_SIZE                    (8                              ),
    .C3_P0_DATA_PORT_SIZE               (64                             ),
    .C3_P1_MASK_SIZE                    (8                              ),
    .C3_P1_DATA_PORT_SIZE               (64                             ),
    .DEBUG_EN                           (0                              ),
    .C3_MEMCLK_PERIOD                   (3200                           ),
    .C3_CALIB_SOFT_IP                   ("TRUE"                         ),
    .C3_SIMULATION                      ("TURE"                         ),
    .C3_RST_ACT_LOW                     (0                              ),
    .C3_INPUT_CLK_TYPE                  ("SINGLE_ENDED"                 ),
    .C3_MEM_ADDR_ORDER                  ("BANK_ROW_COLUMN"              ),
    .C3_NUM_DQ_PINS                     (16                             ),
    .C3_MEM_ADDR_WIDTH                  (13                             ),
    .C3_MEM_BANKADDR_WIDTH              (3                              )
)
u_mig_39_2 (

    .c3_sys_clk                         (c3_sys_clk                     ),
    .c3_sys_rst_i                       (c3_sys_rst_i                   ),                        
    
    .mcb3_dram_dq                       (mcb3_dram_dq                   ),  
    .mcb3_dram_a                        (mcb3_dram_a                    ),  
    .mcb3_dram_ba                       (mcb3_dram_ba                   ),
    .mcb3_dram_ras_n                    (mcb3_dram_ras_n                ),                        
    .mcb3_dram_cas_n                    (mcb3_dram_cas_n                ),                        
    .mcb3_dram_we_n                     (mcb3_dram_we_n                 ),                          
    .mcb3_dram_odt                      (mcb3_dram_odt                  ),
    .mcb3_dram_cke                      (mcb3_dram_cke                  ),                          
    .mcb3_dram_ck                       (mcb3_dram_ck                   ),                          
    .mcb3_dram_ck_n                     (mcb3_dram_ck_n                 ),       
    .mcb3_dram_dqs                      (mcb3_dram_dqs                  ),                          
    .mcb3_dram_dqs_n                    (mcb3_dram_dqs_n                ),
    .mcb3_dram_udqs                     (mcb3_dram_udqs                 ),    // for X16 parts                        
    .mcb3_dram_udqs_n                   (mcb3_dram_udqs_n               ),  // for X16 parts
    .mcb3_dram_udm                      (mcb3_dram_udm                  ),     // for X16 parts
    .mcb3_dram_dm                       (mcb3_dram_dm                   ),
    .mcb3_dram_reset_n                  (mcb3_dram_reset_n              ),
    .mcb3_rzq                           (mcb3_rzq                       ),  
    .mcb3_zio                           (mcb3_zio                       ),
    
    .c3_clk0                            (c3_clk0                        ),
    .c3_rst0                            (c3_rst0                        ),
    .c3_calib_done                      (c3_calib_done                  ),
     
    .c3_p0_cmd_clk                      (c3_p0_cmd_clk                  ),
    .c3_p0_cmd_en                       (c3_p0_cmd_en                   ),
    .c3_p0_cmd_instr                    (c3_p0_cmd_instr                ),
    .c3_p0_cmd_bl                       (c3_p0_cmd_bl                   ),
    .c3_p0_cmd_byte_addr                (c3_p0_cmd_byte_addr            ),
    .c3_p0_cmd_empty                    (c3_p0_cmd_empty                ),
    .c3_p0_cmd_full                     (c3_p0_cmd_full                 ),
    .c3_p0_wr_clk                       (c3_p0_wr_clk                   ),
    .c3_p0_wr_en                        (c3_p0_wr_en                    ),
    .c3_p0_wr_mask                      (c3_p0_wr_mask                  ),
    .c3_p0_wr_data                      (c3_p0_wr_data                  ),
    .c3_p0_wr_full                      (c3_p0_wr_full                  ),
    .c3_p0_wr_empty                     (c3_p0_wr_empty                 ),
    .c3_p0_wr_count                     (c3_p0_wr_count                 ),
    .c3_p0_wr_underrun                  (c3_p0_wr_underrun              ),
    .c3_p0_wr_error                     (c3_p0_wr_error                 ),
    .c3_p0_rd_clk                       (c3_p0_rd_clk                   ),
    .c3_p0_rd_en                        (c3_p0_rd_en                    ),
    .c3_p0_rd_data                      (c3_p0_rd_data                  ),
    .c3_p0_rd_full                      (c3_p0_rd_full                  ),
    .c3_p0_rd_empty                     (c3_p0_rd_empty                 ),
    .c3_p0_rd_count                     (c3_p0_rd_count                 ),
    .c3_p0_rd_overflow                  (c3_p0_rd_overflow              ),
    .c3_p0_rd_error                     (c3_p0_rd_error                 ),

    .c3_p1_cmd_clk                      (c3_p1_cmd_clk                  ),
    .c3_p1_cmd_en                       (c3_p1_cmd_en                   ),
    .c3_p1_cmd_instr                    (c3_p1_cmd_instr                ),
    .c3_p1_cmd_bl                       (c3_p1_cmd_bl                   ),
    .c3_p1_cmd_byte_addr                (c3_p1_cmd_byte_addr            ),
    .c3_p1_cmd_empty                    (c3_p1_cmd_empty                ),
    .c3_p1_cmd_full                     (c3_p1_cmd_full                 ),
    .c3_p1_wr_clk                       (c3_p1_wr_clk                   ),
    .c3_p1_wr_en                        (c3_p1_wr_en                    ),
    .c3_p1_wr_mask                      (c3_p1_wr_mask                  ),
    .c3_p1_wr_data                      (c3_p1_wr_data                  ),
    .c3_p1_wr_full                      (c3_p1_wr_full                  ),
    .c3_p1_wr_empty                     (c3_p1_wr_empty                 ),
    .c3_p1_wr_count                     (c3_p1_wr_count                 ),
    .c3_p1_wr_underrun                  (c3_p1_wr_underrun              ),
    .c3_p1_wr_error                     (c3_p1_wr_error                 ),
    .c3_p1_rd_clk                       (c3_p1_rd_clk                   ),
    .c3_p1_rd_en                        (c3_p1_rd_en                    ),
    .c3_p1_rd_data                      (c3_p1_rd_data                  ),
    .c3_p1_rd_full                      (c3_p1_rd_full                  ),
    .c3_p1_rd_empty                     (c3_p1_rd_empty                 ),
    .c3_p1_rd_count                     (c3_p1_rd_count                 ),
    .c3_p1_rd_overflow                  (c3_p1_rd_overflow              ),
    .c3_p1_rd_error                     (c3_p1_rd_error                 )
);

查阅技术手册,我们对上面的信号做系列陈述:
因为我们再MIG的设置中选择了P0与P1两个64位读写通道,为了简洁起见,我们只对P0通道的数据信号进行讲解
1、C3_P0_MASK_SIZE:设置掩码的数目,一般是数据位宽的字节数
2、C3_P0_DATA_PORT_SIZE:MIG读写通信数据的位宽
3、DEBUG_EN:MIG的debug信号,我们不使用它的debug,想调试自己设置ila进行调试,一般设置为0
4、C3_MEMCLK_PERIOD:MIG IP工作的时钟周期3200ps
5、C3_CALIB_SOFT_IP:与DDR的初始化完成有关,选择TURE
6、C3_SIMULATION :仿真的时候选择TURE,下板的时候选择false即可
7、RST_ACT_LOW:1为MIG IP低复位,0为MIG IP高复位
8、C3_INPUT_CLK_TYPE:输入时钟,我们这里选择单端信号
9、C3_MEM_ADDR_ORDER:MIG中的地址与DDR硬件地址的对应
10、C3_NUM_DQ_PINS:DDR芯片数据位的数目
11、C3_MEM_ADDR_WIDTH:DDR芯片地址的位宽
12、C3_MEM_BANKADDR_WIDTH :DDR芯片bank的数目
上面的设置都与我们上篇文章中MIG的设置有关
13、c3_sys_clk:系统的参考时钟
14、c3_sys_rst_i:MIG对应的复位信号
15、所有带mcb的信号都是与DDR硬件连接的信号,具体含义参考DDR的数据手册,相信如果大家学过SDRAM控制器,对下面的信号很熟悉:
mcb3_dram_dq
mcb3_dram_a
mcb3_dram_ba
mcb3_dram_ras_n
mcb3_dram_cas_n
mcb3_dram_we_n
mcb3_dram_odt
mcb3_dram_cke
mcb3_dram_ck
mcb3_dram_ck_n
mcb3_dram_dqs
mcb3_dram_dqs_n
mcb3_dram_udqs
mcb3_dram_udqs_n
mcb3_dram_udm
mcb3_dram_dm
mcb3_dram_reset_n
mcb3_rzq
mcb3_zio
16、c3_clk0 :MIG给用户提供的时钟,可用可不用,但是vivado中相应的时钟必须使用同步
17、c3_rst0:MIG给用户提供的复位,可用可不用,但是vivado中相应的复位必须使用同步
18、c3_calib_done:MIG自我配置成功之后,该信号拉高,对DDR的操作必须等到该位拉高之后进行
19、c3_p0_cmd_clk:P0通道命令FIFO的时钟接口
20、c3_p0_cmd_en:P0通道命令FIFO的写使能端口
21、c3_p0_cmd_instr:P0通道命令FIFO的写数据,不同的编码代表不同的操作的命令
22、c3_p0_cmd_bl:P0通道每一个命令,数据FIFO突发的长度
23、c3_p1_cmd_byte_addr:DDR命令操作的起始地址,在c3_p0_cmd_en有效的时候被锁存
24、c3_p0_cmd_empty:P0通道命令FIFO的空标志
25、c3_p0_cmd_full:P0通道命令FIFO的满标志
26、c3_p0_wr_clk:P0通道数据写FIFO的时钟
27、c3_p0_wr_en:P0通道数据写FIFO的使能信号
28、c3_p0_wr_mask:P0通道数据写FIFO的数据掩码
29、c3_p0_wr_data:P0通道数据写FIFO的数据
30、c3_p0_wr_full:P0通道数据写FIFO的满信号
31、c3_p0_wr_empty:P0通道数据写FIFO的空信号
32、c3_p0_wr_count:P0通道数据写FIFO写数据计数信号
33、c3_p0_wr_underrun:高电平表示写数据FIFO中没有足够的空间供写入数据
34、c3_p0_wr_error:这个信号表明写入数据FIFO错误发生了,因为FIFO指针没有同步。需要MCB复位才能从这种情况中恢复
35、c3_p0_rd_clk:P0通道读数据FIFO的时钟接口
36、c3_p0_rd_en: P0通道数据读FIFO的使能信号
37、c3_p0_rd_data :P0通道数据读FIFO的数据
38、c3_p0_rd_full:P0通道数据读FIFO的满信号
39、c3_p0_rd_empty:P0通道数据读FIFO的空信号
40、c3_p0_rd_count:P0通道数据读FIFO读数据计数信号
41、c3_p0_rd_overflow:高电平表示读数据FIFO中没有足够的空间供写入数据
42、c3_p0_rd_error:这个信号表明读出数据FIFO错误发生了,因为FIFO指针没有同步。需要MCB复位才能从这种情况中恢复

MIG IP的读写时序

我们从技术手册中查找写时序的图形如下:
命令FIFO的时序图:
Xilinx ISE中DDR3 IP核的使用(2)_第2张图片
写数据的时序图:
Xilinx ISE中DDR3 IP核的使用(2)_第3张图片
写数据与写命令一般按照如下顺序:
1、在执行写命令之前,一般要确保写数据FIFO中有数据
2、由1可知,先向写FIFO写完相应的数据,再向命令FIFO送写命令
读数据的时序图:
Xilinx ISE中DDR3 IP核的使用(2)_第4张图片
读数据与读命令一般按照如下顺序:
1、在执行读数据之前,一般要确保写数据FIFO中有数据
2、由1可知,先给命令FIFO读命令,再给出相应的读数据FIFO信号
一次循环测试的简要时序图
Xilinx ISE中DDR3 IP核的使用(2)_第5张图片
整个DDR芯片的循环测试
Xilinx ISE中DDR3 IP核的使用(2)_第6张图片

MIG IP的读写循环代码

由于ISE 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-21 22:56:59
// 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                       c3_sys_clk              ,
    input                       c3_sys_rst_i            ,
    // DDR3 Interfaces
    inout           [15:0]      mcb3_dram_dq            ,
    output  wire    [12:0]      mcb3_dram_a             , 
    output  wire    [02:0]      mcb3_dram_ba            ,
    output  wire                mcb3_dram_ras_n         ,
    output  wire                mcb3_dram_cas_n         ,
    output  wire                mcb3_dram_we_n          ,
    output  wire                mcb3_dram_odt           ,
    output  wire                mcb3_dram_reset_n       ,
    output  wire                mcb3_dram_cke           ,
    output  wire                mcb3_dram_dm            ,
    inout                       mcb3_dram_udqs          ,
    inout                       mcb3_dram_udqs_n        ,
    inout                       mcb3_rzq                ,
    inout                       mcb3_zio                ,
    output  wire                mcb3_dram_udm           ,
    inout                       mcb3_dram_dqs           ,
    inout                       mcb3_dram_dqs_n         ,
    output  wire                mcb3_dram_ck            ,
    output  wire                mcb3_dram_ck_n          ,
    //Debug 
    input                       test_trig               ,
    output  wire        [63:0]  err_cnt                 ,
    output  wire                err_done            
);

 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
wire                            c3_clk0                 ;
wire                            c3_rst0                 ;

wire                            c3_p0_cmd_clk           ;
wire                            c3_p0_cmd_en            ;
wire                    [ 2:0]  c3_p0_cmd_instr         ;
wire                    [29:0]  c3_p0_cmd_byte_addr     ;
wire                    [ 5:0]  c3_p0_cmd_bl            ;
wire                            c3_p0_wr_clk            ;
wire                            c3_p0_wr_en             ;
wire                    [ 7:0]  c3_p0_wr_mask           ;
wire                    [63:0]  c3_p0_wr_data           ;
wire                    [ 6:0]  c3_p0_wr_count          ;
wire                            c3_p1_cmd_clk           ;
wire                            c3_p1_cmd_en            ;
wire                    [ 2:0]  c3_p1_cmd_instr         ;
wire                    [29:0]  c3_p1_cmd_byte_addr     ;
wire                    [ 5:0]  c3_p1_cmd_bl            ;
wire                            c3_p1_rd_clk            ;
wire                            c3_p1_rd_en             ;
wire                    [63:0]  c3_p1_rd_data           ;
wire                    [ 6:0]  c3_p1_rd_count          ;

wire                            c3_calib_done           ;                      
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/


mig_39_2 # (
    .C3_P0_MASK_SIZE                    (8                              ),
    .C3_P0_DATA_PORT_SIZE               (64                             ),
    .C3_P1_MASK_SIZE                    (8                              ),
    .C3_P1_DATA_PORT_SIZE               (64                             ),
    .DEBUG_EN                           (0                              ),
    .C3_MEMCLK_PERIOD                   (3200                           ),
    .C3_CALIB_SOFT_IP                   ("TRUE"                         ),
    .C3_SIMULATION                      ("TURE"                         ),
    .C3_RST_ACT_LOW                     (0                              ),
    .C3_INPUT_CLK_TYPE                  ("SINGLE_ENDED"                 ),
    .C3_MEM_ADDR_ORDER                  ("BANK_ROW_COLUMN"              ),
    .C3_NUM_DQ_PINS                     (16                             ),
    .C3_MEM_ADDR_WIDTH                  (13                             ),
    .C3_MEM_BANKADDR_WIDTH              (3                              )
)
u_mig_39_2 (

    .c3_sys_clk                         (c3_sys_clk                     ),
    .c3_sys_rst_i                       (c3_sys_rst_i                   ),                        
    
    .mcb3_dram_dq                       (mcb3_dram_dq                   ),  
    .mcb3_dram_a                        (mcb3_dram_a                    ),  
    .mcb3_dram_ba                       (mcb3_dram_ba                   ),
    .mcb3_dram_ras_n                    (mcb3_dram_ras_n                ),                        
    .mcb3_dram_cas_n                    (mcb3_dram_cas_n                ),                        
    .mcb3_dram_we_n                     (mcb3_dram_we_n                 ),                          
    .mcb3_dram_odt                      (mcb3_dram_odt                  ),
    .mcb3_dram_cke                      (mcb3_dram_cke                  ),                          
    .mcb3_dram_ck                       (mcb3_dram_ck                   ),                          
    .mcb3_dram_ck_n                     (mcb3_dram_ck_n                 ),       
    .mcb3_dram_dqs                      (mcb3_dram_dqs                  ),                          
    .mcb3_dram_dqs_n                    (mcb3_dram_dqs_n                ),
    .mcb3_dram_udqs                     (mcb3_dram_udqs                 ),    // for X16 parts                        
    .mcb3_dram_udqs_n                   (mcb3_dram_udqs_n               ),  // for X16 parts
    .mcb3_dram_udm                      (mcb3_dram_udm                  ),     // for X16 parts
    .mcb3_dram_dm                       (mcb3_dram_dm                   ),
    .mcb3_dram_reset_n                  (mcb3_dram_reset_n              ),
    .mcb3_rzq                           (mcb3_rzq                       ),  
    .mcb3_zio                           (mcb3_zio                       ),
    
    .c3_clk0                            (c3_clk0                        ),
    .c3_rst0                            (c3_rst0                        ),
    .c3_calib_done                      (c3_calib_done                  ),
     
    .c3_p0_cmd_clk                      (c3_p0_cmd_clk                  ),
    .c3_p0_cmd_en                       (c3_p0_cmd_en                   ),
    .c3_p0_cmd_instr                    (c3_p0_cmd_instr                ),
    .c3_p0_cmd_bl                       (c3_p0_cmd_bl                   ),
    .c3_p0_cmd_byte_addr                (c3_p0_cmd_byte_addr            ),
    .c3_p0_cmd_empty                    (                               ),
    .c3_p0_cmd_full                     (                               ),
    .c3_p0_wr_clk                       (c3_p0_wr_clk                   ),
    .c3_p0_wr_en                        (c3_p0_wr_en                    ),
    .c3_p0_wr_mask                      (c3_p0_wr_mask                  ),
    .c3_p0_wr_data                      (c3_p0_wr_data                  ),
    .c3_p0_wr_full                      (                               ),
    .c3_p0_wr_empty                     (                               ),
    .c3_p0_wr_count                     (c3_p0_wr_count                 ),
    .c3_p0_wr_underrun                  (                               ),
    .c3_p0_wr_error                     (                               ),
    .c3_p0_rd_clk                       (1'b0                           ),
    .c3_p0_rd_en                        (1'b0                           ),
    .c3_p0_rd_data                      (                               ),
    .c3_p0_rd_full                      (                               ),
    .c3_p0_rd_empty                     (                               ),
    .c3_p0_rd_count                     (                               ),
    .c3_p0_rd_overflow                  (                               ),
    .c3_p0_rd_error                     (                               ),

    .c3_p1_cmd_clk                      (c3_p1_cmd_clk                  ),
    .c3_p1_cmd_en                       (c3_p1_cmd_en                   ),
    .c3_p1_cmd_instr                    (c3_p1_cmd_instr                ),
    .c3_p1_cmd_bl                       (c3_p1_cmd_bl                   ),
    .c3_p1_cmd_byte_addr                (c3_p1_cmd_byte_addr            ),
    .c3_p1_cmd_empty                    (                               ),
    .c3_p1_cmd_full                     (                               ),
    .c3_p1_wr_clk                       (1'b0                           ),
    .c3_p1_wr_en                        (1'b0                           ),
    .c3_p1_wr_mask                      (8'd0                           ),
    .c3_p1_wr_data                      (64'd0                          ),
    .c3_p1_wr_full                      (                               ),
    .c3_p1_wr_empty                     (                               ),
    .c3_p1_wr_count                     (                               ),
    .c3_p1_wr_underrun                  (                               ),
    .c3_p1_wr_error                     (                               ),
    .c3_p1_rd_clk                       (c3_p1_rd_clk                   ),
    .c3_p1_rd_en                        (c3_p1_rd_en                    ),
    .c3_p1_rd_data                      (c3_p1_rd_data                  ),
    .c3_p1_rd_full                      (                               ),
    .c3_p1_rd_empty                     (                               ),
    .c3_p1_rd_count                     (c3_p1_rd_count                 ),
    .c3_p1_rd_overflow                  (                               ),
    .c3_p1_rd_error                     (                               )
);

ddr3_drive ddr3_drive_inst(
    //System Interfaces
    .sclk                               (c3_clk0                        ),
    .rst_n                              (c3_calib_done		   			),
    //DDR3 Interfaces
    .c3_p0_cmd_clk                      (c3_p0_cmd_clk                  ),
    .c3_p0_cmd_en                       (c3_p0_cmd_en                   ),
    .c3_p0_cmd_instr                    (c3_p0_cmd_instr                ),
    .c3_p0_cmd_byte_addr                (c3_p0_cmd_byte_addr            ),
    .c3_p0_cmd_bl                       (c3_p0_cmd_bl                   ),
    .c3_p0_wr_clk                       (c3_p0_wr_clk                   ),
    .c3_p0_wr_en                        (c3_p0_wr_en                    ),
    .c3_p0_wr_mask                      (c3_p0_wr_mask                  ),
    .c3_p0_wr_data                      (c3_p0_wr_data                  ),
    .c3_p0_wr_count                     (c3_p0_wr_count                 ),

    .c3_p1_cmd_clk                      (c3_p1_cmd_clk                  ),
    .c3_p1_cmd_en                       (c3_p1_cmd_en                   ),
    .c3_p1_cmd_instr                    (c3_p1_cmd_instr                ),
    .c3_p1_cmd_byte_addr                (c3_p1_cmd_byte_addr            ),
    .c3_p1_cmd_bl                       (c3_p1_cmd_bl                   ),
    .c3_p1_rd_clk                       (c3_p1_rd_clk                   ),
    .c3_p1_rd_en                        (c3_p1_rd_en                    ),
    .c3_p1_rd_data                      (c3_p1_rd_data                  ),
    .c3_p1_rd_count                     (c3_p1_rd_count                 ),
    //Debug
    .test_trig                          (test_trig                      ),
    .err_cnt                            (err_cnt                        ),
    .err_done                           (err_done                       )
);


endmodule

ddr3_drive模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : ddr3_drive.v
// Create Time  : 2020-02-22 11:41:08
// 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(
    //System Interfaces
    input                   sclk                    ,
    input                   rst_n                   ,
    //DDR3 Interfaces
    output                  c3_p0_cmd_clk           ,
    output  wire            c3_p0_cmd_en            ,
    output  wire    [ 2:0]  c3_p0_cmd_instr         ,
    output  reg     [29:0]  c3_p0_cmd_byte_addr     ,
    output  wire    [ 5:0]  c3_p0_cmd_bl            ,
    output                  c3_p0_wr_clk            ,
    output  reg             c3_p0_wr_en             ,
    output  wire    [ 7:0]  c3_p0_wr_mask           ,
    output  reg     [63:0]  c3_p0_wr_data           ,
    input           [ 6:0]  c3_p0_wr_count          ,

    output                  c3_p1_cmd_clk           ,
    output  reg             c3_p1_cmd_en            ,
    output  wire    [ 2:0]  c3_p1_cmd_instr         ,
    output  reg     [29:0]  c3_p1_cmd_byte_addr     ,
    output  wire    [ 5:0]  c3_p1_cmd_bl            ,
    output                  c3_p1_rd_clk            ,
    output  reg             c3_p1_rd_en             ,
    input           [63:0]  c3_p1_rd_data           ,
    input           [ 6:0]  c3_p1_rd_count          ,
    //Debug
    input                   test_trig               ,
    output  reg     [63:0]  err_cnt                 ,
    output  reg             err_done            
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
//parameter   BURST_NUM       =   1048576             ;
parameter   BURST_NUM       =   1000 	            ;
parameter   BURST_LENFTH    =   6'd15               ;

reg                         flag_done               ;
reg                         test_trig_r             ;
reg                 [ 3:0]  wr_cnt                  ;
reg                         c3_p0_wr_en_r           ;
reg                         c3_p1_rd_en_r           ;
wire                        c3_p1_rd_en_nege        ;
reg                 [20:0]  burst_cnt               ;  
reg                         rd_flag                 ;
reg                         rd_cmd_flag             ;
reg                 [ 3:0]  rd_cnt                  ;  
reg                 [63:0]  check_data              ;     

 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign      c3_p0_cmd_instr     =       3'b000;
assign      c3_p0_cmd_bl        =       BURST_LENFTH;
assign      c3_p0_cmd_en        =       ~c3_p0_wr_en && c3_p0_wr_en_r;
assign      c3_p0_cmd_clk       =       sclk;
assign      c3_p0_wr_clk        =       sclk;
assign 		c3_p0_wr_mask 		= 		8'd0;

assign      c3_p1_cmd_instr     =       3'b001;
assign      c3_p1_cmd_bl        =       BURST_LENFTH;
assign      c3_p1_rd_en_nege    =       ~c3_p1_rd_en && c3_p1_rd_en_r;
assign      c3_p1_cmd_clk       =       sclk;
assign      c3_p1_rd_clk        =       sclk;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_done       <=      1'b0;
    else if(burst_cnt == BURST_NUM - 1'b1 && c3_p1_rd_en_nege == 1'b1)
        flag_done       <=      1'b0;
    else if(test_trig == 1'b1)
        flag_done       <=      1'b1;
    else
        flag_done       <=      flag_done;

always @(posedge sclk)
    test_trig_r         <=      test_trig;

always @(posedge sclk)
    c3_p1_rd_en_r       <=      c3_p1_rd_en;     

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        c3_p0_wr_en     <=      1'b0;
    else if(flag_done == 1'b1 && test_trig_r == 1'b1)
        c3_p0_wr_en     <=      1'b1;
    else if(c3_p1_rd_en_nege == 1'b1 && burst_cnt < BURST_NUM - 1'b1)
        c3_p0_wr_en     <=      1'b1;
    else if(wr_cnt == 4'd15)
        c3_p0_wr_en     <=      1'b0;
    else
        c3_p0_wr_en     <=      c3_p0_wr_en;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_cnt          <=      4'd0;
    else if(c3_p0_wr_en == 1'b1)
        wr_cnt          <=      wr_cnt + 1'b1;
    else
        wr_cnt          <=      4'd0;

always @(posedge sclk) 
    c3_p0_wr_en_r       <=      c3_p0_wr_en;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_cmd_flag     <=      1'b0;
    else if(c3_p0_cmd_en == 1'b1)
        rd_cmd_flag     <=      1'b1;
    else if(rd_flag == 1'b1 && c3_p0_wr_count == 7'd0) 
        rd_cmd_flag     <=      1'b0;
    else
        rd_cmd_flag     <=      rd_cmd_flag;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        c3_p1_cmd_en    <=      1'b0;
    else if(rd_cmd_flag == 1'b1 && c3_p0_wr_count == 7'd0) 
        c3_p1_cmd_en    <=      1'b1;
    else
        c3_p1_cmd_en    <=      1'b0;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_flag         <=      1'b0;
    else if(c3_p0_cmd_en == 1'b1)
        rd_flag         <=      1'b1;
    else if(rd_cnt == 4'd15)
        rd_flag         <=      1'b0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        c3_p1_rd_en     <=      1'b0;
    else if(rd_cnt == 4'd15)
        c3_p1_rd_en     <=      1'b0;
    else if(rd_flag == 1'b1 && c3_p1_rd_count == BURST_LENFTH + 1)
        c3_p1_rd_en 	<=      1'b1;
    else
        c3_p1_rd_en     <=      c3_p1_rd_en;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_cnt          <=      4'd0;
    else if(c3_p1_rd_en == 1'b1)
        rd_cnt          <=      rd_cnt + 1'b1;
    else 
        rd_cnt          <=      4'd0; 
    
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        c3_p0_wr_data   <=      64'd0;
    else if(c3_p0_wr_en == 1'b1 && flag_done == 1'b1)
        c3_p0_wr_data   <=      c3_p0_wr_data + 1'b1;
    else
        c3_p0_wr_data   <=      c3_p0_wr_data;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        check_data      <=      64'd0;  
    else if(c3_p1_rd_en == 1'b1 && flag_done == 1'b1)
        check_data      <=      check_data + 1'b1; 
    else
        check_data      <=      check_data;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        err_cnt         <=      21'd0;
    else if(test_trig == 1'b1)
        err_cnt         <=      21'd0;        
    else if(c3_p1_rd_en == 1'b1 && check_data != c3_p1_rd_data)
        err_cnt         <=      err_cnt + 1'b1;
    else
        err_cnt         <=      err_cnt;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        burst_cnt       <=      21'd0;
    else if(burst_cnt == BURST_NUM - 1'b1 && c3_p1_rd_en_nege == 1'b1)
        burst_cnt       <=      21'd0;
    else if(c3_p1_rd_en_nege == 1'b1)
        burst_cnt       <=      burst_cnt + 1'b1;  
    else
        burst_cnt       <=      burst_cnt;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        err_done        <=      1'b0;
    else if(burst_cnt == BURST_NUM - 1'b1 && c3_p1_rd_en_nege == 1'b1)
        err_done        <=      1'b1;
    else
        err_done        <=      1'b0;
		
always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		c3_p0_cmd_byte_addr 	<= 		30'd0;
	else if(burst_cnt == BURST_NUM - 1'b1 && c3_p0_cmd_en == 1'b1)
		c3_p0_cmd_byte_addr 	<= 		30'd0;
	else if(c3_p0_cmd_en == 1'b1)
		c3_p0_cmd_byte_addr 	<= 		c3_p0_cmd_byte_addr + 30'd128;
	else
		c3_p0_cmd_byte_addr 	<= 		c3_p0_cmd_byte_addr;

always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		c3_p1_cmd_byte_addr 	<= 		30'd0;
	else if(burst_cnt == BURST_NUM - 1'b1 && c3_p1_cmd_en == 1'b1)
		c3_p1_cmd_byte_addr 	<= 		30'd0;
	else if(c3_p1_cmd_en == 1'b1)
		c3_p1_cmd_byte_addr 	<= 		c3_p1_cmd_byte_addr + 30'd128;
	else
		c3_p1_cmd_byte_addr 	<= 		c3_p1_cmd_byte_addr;
          
    

endmodule

这里从ddr3_drive联合上面的时序内容与接口信号的描述,相信大家可以很快学会ISE中MIG的使用方法。

MIG IP的读写循环测试代码

tb_ddr3_top模块的代码:

`timescale 1ps / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : tb_ddr3_top.v
// Create Time  : 2020-02-21 23:21:37
// 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_top;

parameter C3_MEMCLK_PERIOD      =       3200                ;

wire        [12:0]              mcb3_dram_a                 ;
wire        [02:0]              mcb3_dram_ba                ;  
wire                            mcb3_dram_ck                ;  
wire                            mcb3_dram_ck_n              ;
wire        [15:0]              mcb3_dram_dq                ;   
wire                            mcb3_dram_dqs               ;  
wire                            mcb3_dram_dqs_n             ;
wire                            mcb3_dram_dm                ; 
wire                            mcb3_dram_ras_n             ; 
wire                            mcb3_dram_cas_n             ; 
wire                            mcb3_dram_we_n              ;  
wire                            mcb3_dram_cke               ; 
wire                            mcb3_dram_odt               ;
wire                            mcb3_dram_reset_n           ; 

wire                            mcb3_dram_udqs              ;    // for X16 parts
wire                            mcb3_dram_udqs_n            ;  // for X16 parts
wire                            mcb3_dram_udm               ;     // for X16 parts
wire                            mcb3_rzq                    ;   
wire                            mcb3_zio                    ;

reg                             c3_sys_clk                  ;
reg                             c3_sys_rst_i                ;

//Debug 
reg 	                        test_trig               	;
wire        [63:0]  			err_cnt                 	;
wire                			err_done            		;

initial         c3_sys_clk = 1'b0;
always #(C3_MEMCLK_PERIOD/2) c3_sys_clk = ~c3_sys_clk;

initial begin
    c3_sys_rst_i        <=          1'b1;
	test_trig 			<= 			1'b0; 
    #(100*C3_MEMCLK_PERIOD);
    c3_sys_rst_i        <=          1'b0;
	#(500_000_000);
	test_trig 			<= 			1'b1;
	#(6*C3_MEMCLK_PERIOD);
	test_trig 			<= 			1'b0;
	#(2_000_000_000);
	test_trig 			<= 			1'b1;
	#(6*C3_MEMCLK_PERIOD);
	test_trig 			<= 			1'b0;
	#(2_000_000_000);
	$stop;
end

PULLDOWN zio_pulldown3          (.O(mcb3_zio)                   );   
PULLDOWN rzq_pulldown3          (.O(mcb3_rzq)                   );

ddr3_top ddr3_top_inst(
    // DDR3 Interfaces
    .mcb3_dram_dq               (mcb3_dram_dq               	),
    .mcb3_dram_a                (mcb3_dram_a                	), 
    .mcb3_dram_ba               (mcb3_dram_ba               	),
    .mcb3_dram_ras_n            (mcb3_dram_ras_n            	),
    .mcb3_dram_cas_n            (mcb3_dram_cas_n            	),
    .mcb3_dram_we_n             (mcb3_dram_we_n             	),
    .mcb3_dram_odt              (mcb3_dram_odt              	),
    .mcb3_dram_reset_n          (mcb3_dram_reset_n          	),
    .mcb3_dram_cke              (mcb3_dram_cke              	),
    .mcb3_dram_dm               (mcb3_dram_dm               	),
    .mcb3_dram_udqs             (mcb3_dram_udqs             	),
    .mcb3_dram_udqs_n           (mcb3_dram_udqs_n           	),
    .mcb3_rzq                   (mcb3_rzq                   	),
    .mcb3_zio                   (mcb3_zio                   	),
    .mcb3_dram_udm              (mcb3_dram_udm              	),
    .c3_sys_clk                 (c3_sys_clk                 	),
    .c3_sys_rst_i               (c3_sys_rst_i               	),
    .mcb3_dram_dqs              (mcb3_dram_dqs              	),
    .mcb3_dram_dqs_n            (mcb3_dram_dqs_n            	),
    .mcb3_dram_ck               (mcb3_dram_ck               	),
    .mcb3_dram_ck_n             (mcb3_dram_ck_n             	),
//Debug 	
    .test_trig               	(test_trig               		),
    .err_cnt                 	(err_cnt                 		),
    .err_done            		(err_done            			)
);	
	
ddr3_model_c3 u_mem_c3(	
    .ck                         (mcb3_dram_ck               	),
    .ck_n                       (mcb3_dram_ck_n             	),
    .cke                        (mcb3_dram_cke              	),
    .cs_n                       (1'b0                       	),
    .ras_n                      (mcb3_dram_ras_n            	),
    .cas_n                      (mcb3_dram_cas_n            	),
    .we_n                       (mcb3_dram_we_n             	),
    .dm_tdqs                    ({mcb3_dram_udm,mcb3_dram_dm} 	),
    .ba                         (mcb3_dram_ba               	),
    .addr                       (mcb3_dram_a                	),
    .dq                         (mcb3_dram_dq               	),
    .dqs                        ({mcb3_dram_udqs,mcb3_dram_dqs}	),
    .dqs_n                      ({mcb3_dram_udqs_n,mcb3_dram_dqs_n}),
    .tdqs_n                     (                           	),
    .odt                        (mcb3_dram_odt              	),
    .rst_n                      (mcb3_dram_reset_n          	)
);

endmodule

这里DDR3模型文件和相应的配置文件的代码不再给出,这部分代码是从DDR3的示例工程中获得的,在上一篇文章中也给出了模型文件的代码。当然也可以进群获得。

仿真结果

Modelsim仿真结果图如下:
Xilinx ISE中DDR3 IP核的使用(2)_第7张图片

Xilinx ISE中DDR3 IP核的使用(2)_第8张图片
从图形中,我们可以看出我们读写测试了两次,均没有发生错误,这验证了我们程序的正确性。

总结

创作不易,认为文章有帮助的同学们可以关注点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

你可能感兴趣的:(FPGA)