Xilinx MIG 控制器使用详解(三)

想要自己学习MIG控制器已经很久了,刚开始学习的时候也是在网上到处搜索MIG控制器的资料,深知学习过程的不容易。因此本系列的教程一定会详细的写出关于MIG控制器的相关知识,方便大家一起学习。有问题的朋友可以在下方留言,一起学习和讨论。


 关于DDR3的基本知识在这里我就不详细说了,只有在相关的地方会提上一嘴。本教程的目的只是教会大家如何使用MIG控制器,大家一定不要觉得MIG控制器有多难,其实很简单的,跟着我在心里默念“MIG就像BRAM一样简单”。确实哈,当你回过头来看,MIG控制器的使用基本和BRAM的使用方法很像。
 

VIVADO版本:2016.4

芯片:zynq7035

读写测试总模块如下图:

外部晶振输入的是100MHz,但是MIG需要400MHz的输入,所以需要经过一个始终管理模块进行倍频到400MHz。DDR_CTRL的主要作用就是产生第二节中说明的那些读写控制信号。

代码结构如下:

现在让我们来分析分析代码吧,先从top.v开始。

top.v

`timescale 1ns / 1ps

module top(
    inout           [31:0]              ddr3_dq                 ,
    inout           [3:0]               ddr3_dqs_n              ,
    inout           [3:0]               ddr3_dqs_p              ,

    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                              ddr3_ck_p               ,
    output                              ddr3_ck_n               ,
    output                              ddr3_cke                ,
    output                              ddr3_cs_n               ,
    output          [3:0]               ddr3_dm                 ,
    output                              ddr3_odt                ,

    input                               sys_clk_i   //外部输入的100MHz时钟            
    );


    wire                                clk400;
    wire                                rst_n;
    clk_wiz_0           clk_wiz_0(
        .clk_out1               (       clk400                  ), 
        .locked                 (       rst_n                   ), 
        .clk_in1                (       sys_clk_i               )
    );




    (*keep = "true"*)(*mark_debug = "true"*)wire            [28:0]              app_addr                ;
    (*keep = "true"*)(*mark_debug = "true"*)wire            [2:0]               app_cmd                 ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_en                  ;
    (*keep = "true"*)(*mark_debug = "true"*)wire            [255:0]             app_wdf_data            ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_wdf_end             ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_wdf_wren            ;
    (*keep = "true"*)(*mark_debug = "true"*)wire            [255:0]             app_rd_data             ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_rd_data_end         ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_rd_data_valid       ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_rdy                 ;
    (*keep = "true"*)(*mark_debug = "true"*)wire                                app_wdf_rdy             ;

    (*keep = "true"*)(*mark_debug = "true"*)wire                                ddrdata_test_err        ;


    wire            [31:0]              app_wdf_mask            ;
    wire                                app_sr_req              ;
    wire                                app_ref_req             ;
    wire                                app_zq_req              ;
    wire                                app_sr_active           ;
    wire                                app_ref_ack             ;
    wire                                app_zq_ack              ;
    wire                                ui_clk                  ;
    wire                                ui_clk_sync_rst         ;

    wire                                init_calib_complete     ;




//例化ddr_ctrl模块
    ddr_ctrl        ddr_ctrl(
        .clk                     (      ui_clk                  ),
        .rst_n                   (      rst_n                   ),

        .app_addr                (      app_addr                ),     
        .app_cmd                 (      app_cmd                 ),
        .app_en                  (      app_en                  ),
        .app_wdf_data            (      app_wdf_data            ),
        .app_wdf_mask            (      app_wdf_mask            ), 

        .app_rd_data             (      app_rd_data             ),
        .app_rd_data_end         (      app_rd_data_end         ),
        .app_rd_data_valid       (      app_rd_data_valid       ),

        .app_rdy                 (      app_rdy                 ),
        .app_wdf_rdy             (      app_wdf_rdy             ),
        .app_wdf_end             (      app_wdf_end             ),
        .app_wdf_wren            (      app_wdf_wren            ),

        .init_calib_complete     (      init_calib_complete     ),
        .ddrdata_test_err        (      ddrdata_test_err        )
    );





//例化MIG控制器

    mig_7series_0       u_mig_7series_0 (
        // 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 [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 [28: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                     (0),  // input         app_sr_req
        .app_ref_req                    (0),  // input            app_ref_req
        .app_zq_req                     (0),  // 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 [31:0]        app_wdf_mask
        // System Clock Ports
        .sys_clk_i                       (clk400),
        // Reference Clock Ports
        .clk_ref_i                      (clk400),
        .sys_rst                        (rst_n) // input sys_rst
    );

endmodule

ddr_ctrl.v模块

`timescale 1ns / 1ps

module ddr_ctrl(
    input                       clk                     ,
    input                       rst_n                   ,

    output      [28:0]          app_addr                ,     
    output  reg [2:0]           app_cmd                 ,
    output  reg                 app_en                  ,
    output  reg [255:0]         app_wdf_data            ,
    output      [31:0]          app_wdf_mask            , 
    
    input       [255:0]         app_rd_data             ,
    input                       app_rd_data_end         ,
    input                       app_rd_data_valid       ,
    
    input                       app_rdy                 ,
    input                       app_wdf_rdy             ,
    output                      app_wdf_end             ,
    output                      app_wdf_wren            ,
    input                       init_calib_complete     ,     // DDR3 鍒濆鍖栧畬鎴�
    output reg                  ddrdata_test_err        
  );


    reg         [3:0]           test_state              ;
    reg         [15:0]          send_cnt                ;
    reg         [28:0]          write_addr              ;
    reg         [28:0]          read_addr               ;
    reg         [255:0]         data_buff               ;
    
 
    assign  app_wdf_wren  = 	app_en & app_wdf_rdy & app_rdy & (app_cmd == 3'd0);
    assign  app_wdf_end   = 	app_wdf_wren;
    
    assign  app_addr      = 	(app_cmd == 3'd0) ? write_addr : read_addr;

    assign 	app_wdf_mask = 	32'd0;//这个直赋0



    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            test_state              <= 4'd0;
            send_cnt                <= 16'd0;
            write_addr              <= 29'd0;
            read_addr               <= 29'd0;
            app_cmd                 <= 3'd0;
            app_en                  <= 1'b0;
            app_wdf_data            <= 256'd0;
        end
        else
        begin
            case (test_state)
            4'd0 :                                              
            begin
                app_cmd             <= 3'd0;
                app_en              <= 1'b0;
                app_wdf_data        <= 256'd0;
                send_cnt            <= 16'd0;
                write_addr          <= 29'd0;
                read_addr           <= 29'd0;
                if(init_calib_complete)
                    test_state      <= 4'd1;  //如果DDR初始化完成就进入下一个状态
                else
                    test_state      <= 4'd0;  //否则等待DDR初始化完成
            end
            
            4'd1 :
            begin
                if(app_rdy & app_wdf_rdy) //等待这两个信号拉高就使命令有效
                begin
                    app_cmd         <= 3'd0;
                    app_en          <= 1'b1;
                    send_cnt        <= send_cnt + 1'b1;

                    test_state      <= 4'd2;
                end
            end
            
            4'd2 : 
            begin
                if(app_rdy & app_wdf_rdy)
                begin
                    if(send_cnt == 16'd199)   
                    begin
                        app_wdf_data    <=  256'd0;
                        write_addr      <=  29'd0;
                        send_cnt        <= 16'd0;
                        test_state      <= 4'd3;  //进入读状态
                        app_en          <= 1'b0;
                    end
                    else
                    begin
                        send_cnt        <= send_cnt + 1'b1;
                        app_cmd         <= 3'd0;
                        app_en          <= 1'b1;
                        write_addr      <= write_addr + 29'd8;            
                        app_wdf_data    <= app_wdf_data + 256'd1;//写入的数据,从1到198
                    end
                end
            end
            
            4'd3 : 
            begin
                if(app_rdy & app_wdf_rdy)
                begin
                    app_cmd         <= 3'd1;  //读命令有效,实际上这时候已经有数据出来了
                    app_en          <= 1'b1;
                    send_cnt        <= send_cnt + 1'b1;
                    test_state      <= 4'd4;
                end
            end
            
            4'd4 :
            begin
                if(app_rdy & app_wdf_rdy)
                begin
                    if(send_cnt == 16'd199)                 
                    begin
                        read_addr       <=  29'd0;
                        send_cnt        <= 16'd0;
                        test_state      <= 4'd5;
                        app_en          <= 1'b0;
                    end
                    else 
                    begin
                        send_cnt        <= send_cnt + 1'b1;
                        app_cmd         <= 3'd1;
                        app_en          <= 1'b1;
                        read_addr       <= read_addr + 29'd8;  //读地址             
                             
                    end
                end
            end
            
            4'd5 ://不读也不写
            begin
                app_cmd             <= 3'd0;
                app_en              <= 1'b0;
                send_cnt            <= send_cnt + 1'b1;
                if(send_cnt == 16'd200)
                begin
                    send_cnt        <= 16'd0;
                    test_state      <= 4'd1;
                end
            end
            
            default : test_state      <= 4'd0;
            
            endcase
        end
    end
   //比较写入与独处的数据是否相等
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            data_buff               <= 256'd0;
            ddrdata_test_err        <= 1'b0;
        end
        else if (test_state == 4'd3) 
        begin
            data_buff               <= 256'd0;
        end
        else
        begin
            if(app_rd_data_valid)
            begin
                data_buff           <= data_buff + 256'd1;
                if(data_buff != app_rd_data) //如果写入与独处的数据不相等就拉高
                    ddrdata_test_err    <= 1'b1;
            end
        end
    end

endmodule

到此程序已经分析完毕了,想到什么问题再补充吧。

工程代码。

猜你喜欢

转载自blog.csdn.net/MaoChuangAn/article/details/85270115