UDP--DDR--SFP,FPGA实现之模块梳理及AXI读写DDR读写上板测试

模块梳理介绍

在之前的几篇文章中,笔者详细介绍了整个项目的框架结构以及部分关键模块的实现细节。这些模块包括UDP协议栈、UDP指令监测、数据跨时钟域处理、DDR读写控制、内存读取控制以及DDR AXI控制器等。这些模块共同构成了项目的基础架构,每个模块都经过精心设计和实现,以确保系统的稳定性和高效性。

鉴于后续的GT收发器功能模块配置相对简单,而之前的模块已经形成了一定的体系规模,笔者现在将对这些模块进行功能联调,以实现全面的仿真测试。功能联调是确保各个模块能够协同工作的重要步骤,通过仿真测试可以验证模块之间的接口是否匹配,数据传输是否准确,以及整体系统是否能够按照预期运行。

而对于UDP协议栈的仿真,由于在之前的专栏已经较为详尽,在本章节中,便不再进行仿真,而是直接模拟UDP数据的发送,对于MIG核笔者同样不进行仿真,考虑到移植仿真文件比较麻烦,不如在验证AXI的正确性后,直接进行上板验证。

模块整体结构代码

c 复制代码
module k7325t_top(
    input               i_sysclk        ,
    /*sfp*/
    input               i_gtrefclk_p    ,
    input               i_gtrefclk_n    ,
    output              o_gt_tx_p       ,
    output              o_gt_tx_n       ,
    input               i_gt_rx_p       ,
    input               i_gt_rx_n       ,
    output  [1 :0]      o_sfp_disable   ,
    input               i_rxc           ,
    input   [3 :0]      i_rxd           ,
    input               i_rx_ctl        ,
    output              o_txc           ,
    output  [3 :0]      o_txd           ,
    output              o_tx_ctl        ,
    output              phy_rst         ,
    /*ddr*/
    output  [14:0]      ddr3_addr       ,
    output  [2 :0]      ddr3_ba         ,
    output		        ddr3_cas_n      ,
    output  [0 :0]      ddr3_ck_n       ,
    output  [0 :0]      ddr3_ck_p       ,
    output  [0 :0]      ddr3_cke        ,
    output		        ddr3_ras_n      ,
    output			    ddr3_reset_n    ,
    output			    ddr3_we_n       ,
    inout   [31:0]		ddr3_dq         ,
    inout   [3 :0]		ddr3_dqs_n      ,
    inout   [3 :0]		ddr3_dqs_p      ,
    output  [0 :0]		ddr3_cs_n       ,
    output  [3 :0]		ddr3_dm         ,
    output  [0 :0]		ddr3_odt        
    );
wire                    w_udp_clk       ;
wire                    w_udp_rst       ;
wire                    w_sfp_clk       ;
wire                    w_sfp_rst       ;
wire [15:0]             w_udp_len       ;
wire [7 :0]             w_udp_data      ;
wire                    w_udp_last      ;
wire                    w_udp_valid     ;
wire    [31:0]          w_send_data     ;
wire                    w_send_valid    ;
assign  phy_rst = 1'b1;
wire                    w_sys_clk       ;
wire                    w_ddr_clk       ;
wire                    w_locked        ;
wire                    w_ui_clk        ;
wire                    w_ui_rst        ;
wire    [1 :0]          w_op_cmd        ;
wire    [29:0]          w_op_waddr      ;
wire    [29:0]          w_op_raddr      ;
wire                    w_op_valid      ;
wire                    w_op_ready      ;
wire    [31:0]          w_write_data    ;
wire                    w_write_valid   ;
wire    [31:0]          w_read_data     ;
wire                    w_read_valid    ;

wire                    w_read_cmd       ;
wire    [7 :0]          w_store_udp_data ;
wire                    w_store_udp_valid;
wire                    w_store_done     ;
wire                    w_raddr_clear    ;
wire                    w_sync_clear     ;
wire    [15:0]          w_store_size     ;
wire                    w_read_back      ;
wire    [31:0]          w_sfp_data       ;
wire                    w_sfp_valid      ;

/*生成全局时钟*/
clk_gen clk_gen_u0(
    .clk_out2           (w_ddr_clk          ),
    .clk_out1           (w_sys_clk          ),
    .locked             (w_locked           ),
    .clk_in1            (i_sysclk           )
    );

/*UDP协议栈*/
udp_module udp_module_u0(
    .i_rxc              (i_rxc              ),
    .i_rxd              (i_rxd              ),
    .i_rx_ctl           (i_rx_ctl           ),
    .o_txc              (o_txc              ),
    .o_txd              (o_txd              ),
    .o_tx_ctl           (o_tx_ctl           ),
    .o_udp_clk          (w_udp_clk          ),
    .o_udp_rst          (w_udp_rst          ),
    .o_rec_len          (w_udp_len          ),
    .o_rec_data         (w_udp_data         ),
    .o_rec_last         (w_udp_last         ),
    .o_rec_valid        (w_udp_valid        )
);

/*指令监测,输出监测后数据*/
udp_cmd_check udp_cmd_check_u0(
    .i_clk              (w_udp_clk          ),
    .i_rst              (w_udp_rst          ),
    .i_udp_data         (w_udp_data         ),
    .i_udp_valid        (w_udp_valid        ),
    .o_udp_data         (w_store_udp_data   ),
    .o_udp_valid        (w_store_udp_valid  ),
    .o_store_done       (w_store_done       ),
    .o_raddr_clear      (w_raddr_clear      )
    );

/*跨时钟域处理,1Byte-->4Bytes,udp-->ddr*/
ASYNC_BUF_DDR ASYNC_BUF_DDR_U0(
    .i_udp_clk          (w_udp_clk          ),
    .i_udp_rst          (w_udp_rst          ),
    .i_ui_clk           (w_ui_clk           ),
    .i_ui_rst           (w_ui_rst           ),
    .i_udp_data         (w_store_udp_data   ),
    .i_udp_valid        (w_store_udp_valid  ),
    .o_send_data        (w_send_data        ),
    .o_send_valid       (w_send_valid       )
    );

/*读取地址清除信号跨时钟*/
sync_s2f sync_s2f_u0(
    .i_clk_slow	        (w_udp_clk          ),
    .i_signal	        (w_raddr_clear      ),
    .i_clk_fast 	    (w_ui_clk           ),
    .o_sync		        (w_sync_clear       )
);

/*内存读取控制器*/
read_memory_ctrl read_memory_ctrl_u0(
    .i_ui_clk           (w_ui_clk           ),
    .i_ui_rst           (w_ui_rst           ),
    .i_sfp_clk          (w_sfp_clk          ),
    .i_sfp_rst          (w_sfp_rst          ),
    .i_store_done       (w_store_done       ),
    .i_store_size       (w_store_size       ),
    .i_raddr_clear      (w_sync_clear       ),
    .o_read_back        (w_read_back        ),
    .o_read_cmd         (w_read_cmd         ),
    .i_read_data        (w_read_data        ),
    .i_read_valid       (w_read_valid       ),
    .o_sfp_data         (w_sfp_data         ),
    .o_sfp_valid        (w_sfp_valid        )
    );

/*ddr读写控制器*/
ddr_rw_control ddr_rw_control_u0(
    .i_ui_clk           (w_ui_clk           ),
    .i_ui_rst           (w_ui_rst           ),
    .i_send_data        (w_send_data        ),
    .i_send_valid       (w_send_valid       ),
    .i_read_cmd         (w_read_cmd         ),
    .i_raddr_clear      (w_sync_clear       ),
    .i_read_back        (w_read_back        ),
    .o_store_size       (w_store_size       ),
    .o_op_cmd           (w_op_cmd           ),
    .o_op_waddr         (w_op_waddr         ),
    .o_op_raddr         (w_op_raddr         ),
    .o_op_valid         (w_op_valid         ),
    .i_op_ready         (w_op_ready         ),
    .o_write_data       (w_write_data       ),
    .o_write_valid      (w_write_valid      ),
    .i_read_data        (w_read_data        ),
    .i_read_valid       (w_read_valid       )
    );

/*ddr axi读写驱动*/
ddr_top ddr_top_u0(
    .i_ddr_clk          (w_ddr_clk          ),
    .i_ddr_rstn         (w_locked           ),
    .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         ),
    .ddr3_cs_n          (ddr3_cs_n          ),
    .ddr3_dm            (ddr3_dm            ),
    .ddr3_odt           (ddr3_odt           ),
    .ui_clk             (w_ui_clk           ),
    .ui_clk_sync_rst    (w_ui_rst           ),
    .i_op_cmd           (w_op_cmd           ),
    .i_op_waddr         (w_op_waddr         ),
    .i_op_raddr         (w_op_raddr         ),
    .i_op_valid         (w_op_valid         ),
    .o_op_ready         (w_op_ready         ),
    .i_write_data       (w_write_data       ),
    .i_write_valid      (w_write_valid      ),
    .o_read_data        (w_read_data        ),
    .o_read_valid       (w_read_valid       )
    );


/*光纤传输器*/
gt_one_top gt_one_top_u0(
    .i_sysclk            (w_sys_clk         ),
    .i_gtrefclk_p        (i_gtrefclk_p      ),
    .i_gtrefclk_n        (i_gtrefclk_n      ),
    .o_gt_tx_p           (o_gt_tx_p         ),
    .o_gt_tx_n           (o_gt_tx_n         ),
    .i_gt_rx_p           (i_gt_rx_p         ),
    .i_gt_rx_n           (i_gt_rx_n         ),
    .o_sfp_disable       (o_sfp_disable     ),
    .o_sfp_txclk         (w_sfp_clk         ),
    .o_sfp_txrst         (w_sfp_rst         ),
    .i_send_data         (w_sfp_data        ),
    .i_send_valid        (w_sfp_valid       )
    );

整体模块仿真(不包含GT收发器部分)

那么接下来便进行仿真流程的梳理

  • 模拟UDP接收到500K数据,在数据文件下发前,发送擦除指令,在数据文件下发后,发送传输完成指令
  • UDP指令监测模块对输入的UDP模拟数据做解析,解析出指令或是数据
  • 数据跨时钟模块接收指令监测模块输出的数据,进行位宽转换和跨时钟处理
  • 单次输出1K数据到DDR读写控制模块,DDR读写控制模块传输数据至DDR_AXI控制器
  • DDR_AXI控制器转译OP总线指令,转换为AXI总线,进行文件数据写入
  • 内存读取控制模块监测文件传输完成指令,控制DDR读写控制模块,进行文件循环读取
  • 仿真激励代码如下
c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/05/09 09:32:42
// Design Name: 
// Module Name: tb_module
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_module(

    );

reg                 i_udp_clk       = 1'b0;
reg                 i_udp_rst       = 1'b0;
reg                 i_ui_clk        = 1'b0;
reg                 i_ui_rst        = 1'b0;
reg                 i_sfp_clk       = 1'b0;
reg                 i_sfp_rst       = 1'b0;
reg     [7 :0]      i_udp_data      = 8'd0;
reg                 i_udp_valid     = 1'd0;
reg                 i_rcmd          = 1'b0;
wire    [7 :0]      w_store_udp_data    ;
wire                w_store_udp_valid   ;
wire                w_store_done        ;
wire                w_raddr_clear       ;
wire                w_sync_clear        ;
wire                w_read_cmd          ;
reg     [31:0]      r_read_data     = 32'd0;
reg                 r_read_valid    = 1'd0 ;
wire    [31:0]      w_sfp_data          ; 
wire                w_sfp_valid         ;
wire    [31:0]      w_send_data         ;
wire                w_send_valid        ;
wire    [1 :0]      w_op_cmd            ;
wire    [29:0]      w_op_waddr          ;
wire    [29:0]      w_op_raddr          ;
wire                w_op_valid          ;
wire    [31:0]      w_write_data        ;
wire                w_write_valid       ;
wire    [15:0]      w_store_size        ;

integer i = 0;
integer j = 0;
always #4   i_udp_clk = ~i_udp_clk;
always #2.5 i_ui_clk  = ~i_ui_clk ;
always #2   i_sfp_clk = ~i_sfp_clk;
initial begin
    i_udp_rst = 1;
    i_sfp_rst = 1;
    i_ui_rst  = 1;
    #100
    @(i_sfp_clk) begin
        i_udp_rst <= 1'b0;
        i_sfp_rst <= 1'b0;
        i_ui_rst  <= 1'b0;
    end
    #100
    /*传输擦除指令*/
    @(posedge i_udp_clk)
        udp_cmd(64'HD5D5D5D5_FCFCFCFC);
    /*传输200KB*/
    @(posedge i_udp_clk)
    for(i = 0;i < 300; i = i + 1) begin
        @(posedge i_udp_clk)
            udp_send(1024);
        #500
        @(posedge i_udp_clk);
    end
    /*传输完成指令*/
    @(posedge i_udp_clk)
        udp_cmd(64'HA5A5A5A5_BCBCBCBC);
end

/*指令监测,输出监测后数据*/
udp_cmd_check udp_cmd_check_u0(
    .i_clk              (i_udp_clk          ),
    .i_rst              (i_udp_rst          ),
    .i_udp_data         (i_udp_data         ),
    .i_udp_valid        (i_udp_valid        ),
    .o_udp_data         (w_store_udp_data   ),
    .o_udp_valid        (w_store_udp_valid  ),
    .o_store_done       (w_store_done       ),
    .o_raddr_clear      (w_raddr_clear      )
    );

/*跨时钟域处理,1Byte-->4Bytes,udp-->ddr*/
ASYNC_BUF_DDR ASYNC_BUF_DDR_U0(
    .i_udp_clk          (i_udp_clk          ),
    .i_udp_rst          (i_udp_rst          ),
    .i_ui_clk           (i_ui_clk           ),
    .i_ui_rst           (i_ui_rst           ),
    .i_udp_data         (w_store_udp_data   ),
    .i_udp_valid        (w_store_udp_valid  ),
    .o_send_data        (w_send_data        ),
    .o_send_valid       (w_send_valid       )
    );

/*读取地址清除信号跨时钟*/
sync_s2f sync_s2f_u0(
    .i_clk_slow	        (i_udp_clk          ),
    .i_signal	        (w_raddr_clear      ),
    .i_clk_fast 	    (i_ui_clk           ),
    .o_sync		        (w_sync_clear       )
);

ddr_rw_control ddr_rw_control_u0(
    .i_ui_clk           (i_ui_clk           ),
    .i_ui_rst           (i_ui_rst           ),
    .i_send_data        (w_send_data        ),
    .i_send_valid       (w_send_valid       ),
    .i_read_cmd         (i_rcmd             ),
    .i_raddr_clear      (w_sync_clear       ),
    .i_read_back        (1'b0               ),
    .o_store_size       (w_store_size       ),
    .o_op_cmd           (w_op_cmd           ),
    .o_op_waddr         (w_op_waddr         ),
    .o_op_raddr         (w_op_raddr         ),
    .o_op_valid         (w_op_valid         ),
    .i_op_ready         (1'b1               ),
    .o_write_data       (w_write_data       ),
    .o_write_valid      (w_write_valid      ),
    .i_read_data        (32'd0              ),
    .i_read_valid       (1'b0               )
    );

always @(posedge i_ui_clk) begin
    if (w_read_cmd) begin
        ddr_data(256);
    end
end

/*内存读取控制器*/
read_memory_ctrl read_memory_ctrl_u0(
    .i_ui_clk           (i_ui_clk           ),
    .i_ui_rst           (i_ui_rst           ),
    .i_sfp_clk          (i_sfp_clk          ),
    .i_sfp_rst          (i_sfp_rst          ),
    .i_store_done       (w_store_done       ),
    .i_store_size       (w_store_size       ),
    .i_raddr_clear      (w_sync_clear       ),
    .o_read_cmd         (w_read_cmd         ),
    .i_read_data        (r_read_data        ),
    .i_read_valid       (r_read_valid       ),
    .o_sfp_data         (w_sfp_data         ),
    .o_sfp_valid        (w_sfp_valid        )
    );

task udp_send(input    [15:0]  byte_len);begin : data
    integer i;
    i_udp_data   = 8'd0;
    i_udp_valid  = 1'd0;
    @(posedge i_udp_clk);
    for(i = 0;i < byte_len ;i = i + 1)
    begin
        i_udp_data  <= i_udp_data + 1'b1;
        i_udp_valid <= 1'b1;
        @(posedge i_udp_clk);
    end
    i_udp_data   <= 8'd0;
    i_udp_valid  <= 1'd0;
end
endtask

task udp_cmd(input    [63:0]  i_cmd);begin : cmd
    integer i;
    i_udp_data   = 8'd0;
    i_udp_valid  = 1'd0;
    @(posedge i_udp_clk);
    for(i = 0;i < 8 ;i = i + 1)
    begin
        i_udp_data  <= i_cmd[63:56];
        i_cmd <= {i_cmd[55:0],8'h0};
        i_udp_valid <= 1'b1;
        @(posedge i_udp_clk);
    end
    i_udp_data   <= 8'd0;
    i_udp_valid  <= 1'd0;
end
endtask

task ddr_data(input    [15:0]  byte_len);begin : ddr
    integer i;
    r_read_data   = 32'd0;
    r_read_valid  = 1 'd0;
    @(posedge i_ui_clk);
    for(i = 0;i < 256 ;i = i + 1)
    begin
        r_read_data  <= r_read_data + 1'b1;
        r_read_valid <= 1'b1;
        @(posedge i_ui_clk);
    end
    r_read_data   = 32'd0;
    r_read_valid  = 1 'd0;
end
endtask

endmodule

上述测试流程实际是对之前文章的测试进行了总结,所以在此,便不进行贴图展示结果了。

接下来,将进行AXI读写DDR的上板测试,如下所示,是笔者写的一个DDR模块顶层代码,实际是,将AXI读写DDR的控制器的op总线部分交互变为一与个可控模块进行交互,通过vio控制可控模块进行数据总线输出,读写DDR。

AXI接口的MIG核读写DDR上板测试

c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/04/25 15:17:48
// Design Name: 
// Module Name: ddr_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ddr_top(
    // input               i_ddr_clk       ,
    // input               i_ddr_rstn      ,
    input               i_sysclk        ,
    output  [14:0]      ddr3_addr       ,
    output  [2 :0]      ddr3_ba         ,
    output		        ddr3_cas_n      ,
    output  [0 :0]      ddr3_ck_n       ,
    output  [0 :0]      ddr3_ck_p       ,
    output  [0 :0]      ddr3_cke        ,
    output		        ddr3_ras_n      ,
    output			    ddr3_reset_n    ,
    output			    ddr3_we_n       ,
    inout   [31:0]		ddr3_dq         ,
    inout   [3 :0]		ddr3_dqs_n      ,
    inout   [3 :0]		ddr3_dqs_p      ,
    output  [0 :0]		ddr3_cs_n       ,
    output  [3 :0]		ddr3_dm         ,
    output  [0 :0]		ddr3_odt        

    // output              ui_clk          ,
    // output              ui_clk_sync_rst ,
    // input   [1 :0]      i_op_cmd        ,
    // input   [29:0]      i_op_waddr      ,
    // input   [29:0]      i_op_raddr      ,
    // input               i_op_valid      ,
    // output              o_op_ready      ,
    // input   [31:0]      i_write_data    ,
    // input               i_write_valid   ,
    // output  [31:0]      o_read_data     ,
    // output              o_read_valid    
    );


(*mark_debug = "true"*)wire                    init_calib_complete ;
wire                    w_ui_clk_sync_rst   ;
wire    [3 :0]          M_AXI_AWID          ;
(*mark_debug = "true"*)wire    [29:0]          M_AXI_AWADDR        ;
(*mark_debug = "true"*)wire    [7 :0]          M_AXI_AWLEN         ;
wire    [2 :0]          M_AXI_AWSIZE        ;
wire    [1 :0]          M_AXI_AWBURST       ;
wire    [0 :0]          M_AXI_AWLOCK        ;
wire    [3 :0]          M_AXI_AWCACHE       ;
wire    [2 :0]          M_AXI_AWPROT        ;
wire    [3 :0]          M_AXI_AWQOS         ;
(*mark_debug = "true"*)wire                    M_AXI_AWVALID       ;
(*mark_debug = "true"*)wire                    M_AXI_AWREADY       ;
(*mark_debug = "true"*)wire    [31:0]          M_AXI_WDATA         ;
(*mark_debug = "true"*)wire    [3 :0]          M_AXI_WSTRB         ;
(*mark_debug = "true"*)wire                    M_AXI_WLAST         ;
(*mark_debug = "true"*)wire                    M_AXI_WVALID        ;
wire                    M_AXI_WREADY        ;
wire    [3 :0]          M_AXI_BID           ;
wire    [1 :0]          M_AXI_BRESP         ;
wire                    M_AXI_BVALID        ;
wire                    M_AXI_BREADY        ;
wire    [3 :0]          M_AXI_ARID          ;
(*mark_debug = "true"*)wire    [29:0]          M_AXI_ARADDR        ;
(*mark_debug = "true"*)wire    [7 :0]          M_AXI_ARLEN         ;
wire    [2 :0]          M_AXI_ARSIZE        ;
wire    [1 :0]          M_AXI_ARBURST       ;
wire    [0 :0]          M_AXI_ARLOCK        ;
wire    [3 :0]          M_AXI_ARCACHE       ;
wire    [2 :0]          M_AXI_ARPROT        ;
wire    [3 :0]          M_AXI_ARQOS         ;
(*mark_debug = "true"*)wire                    M_AXI_ARVALID       ;
(*mark_debug = "true"*)wire                    M_AXI_ARREADY       ;
wire    [3 :0]          M_AXI_RID           ;
(*mark_debug = "true"*)wire    [31:0]          M_AXI_RDATA         ;
(*mark_debug = "true"*)wire    [1 :0]          M_AXI_RRESP         ;
(*mark_debug = "true"*)wire                    M_AXI_RLAST         ;
(*mark_debug = "true"*)wire                    M_AXI_RVALID        ;
wire                    M_AXI_RREADY        ;

wire    [0 :0]          M_AXI_AWUSER        ;
wire    [0 :0]          M_AXI_WUSER         ;
wire    [0 :0]          M_AXI_BUSER         ;
wire    [0 :0]          M_AXI_ARUSER        ;
wire    [0 :0]          M_AXI_RUSER         ;
wire                    w_ddr_clk           ;
wire                    w_locked            ;
wire    [1 :0]          w_op_cmd            ;
wire    [29:0]          w_op_waddr          ;
wire    [29:0]          w_op_raddr          ;
wire                    w_op_valid          ;
wire                    w_op_ready          ;
wire    [31:0]          w_write_data        ;
wire                    w_write_valid       ;
wire    [31:0]          w_read_data         ;
wire                    w_read_valid        ;
/*生成全局时钟*/
clk_gen clk_gen_u0(
    .clk_out2           (w_ddr_clk          ),
    .clk_out1           (                   ),
    .locked             (w_locked           ),
    .clk_in1            (i_sysclk           )
    );
wire    ui_clk  ;
// assign  ui_clk_sync_rst = w_ui_clk_sync_rst;

wire    i_wcmd  ;
wire    i_rcmd  ;
vio_0 vio_0_u0 (
  .clk          (ui_clk),
  .probe_out0   (i_wcmd),
  .probe_out1   (i_rcmd) 
);

rw_fsm_gen rw_fsm_gen_u0(
    .i_clk                          (ui_clk             ),
    .i_rst                          (w_ui_clk_sync_rst  ),
    .i_wcmd                         (i_wcmd             ),
    .i_rcmd                         (i_rcmd             ),
    .o_can_cmd                      (),
    .o_op_cmd                       (w_op_cmd           ),
    .o_op_waddr                     (w_op_waddr         ),
    .o_op_raddr                     (w_op_raddr         ),
    .o_op_valid                     (w_op_valid         ),
    .i_op_ready                     (w_op_ready         ),
    .o_write_data                   (w_write_data       ),
    .o_write_valid                  (w_write_valid      ),
    .i_read_data                    (w_read_data        ),
    .i_read_valid                   (w_read_valid       )
    );

ddr_axi_rw#(
    .C_M_TARGET_SLAVE_BASE_ADDR     (32'h00000000       ),
    .C_M_AXI_BURST_LEN	            (256                ),
    .C_M_AXI_ID_WIDTH	            (3                  ),
    .C_M_AXI_ADDR_WIDTH	            (30                 ),
    .C_M_AXI_DATA_WIDTH	            (32                 ),
    .C_M_AXI_AWUSER_WIDTH           (1                  ),
    .C_M_AXI_ARUSER_WIDTH           (1                  ),
    .C_M_AXI_WUSER_WIDTH	        (1                  ),
    .C_M_AXI_RUSER_WIDTH	        (1                  ),
    .C_M_AXI_BUSER_WIDTH	        (1                  )
)ddr_axi_rw_u0(
    .init_calib_complete            (init_calib_complete),
    .i_op_cmd                       (w_op_cmd           ),
    .i_op_waddr                     (w_op_waddr         ),
    .i_op_raddr                     (w_op_raddr         ),
    .i_op_valid                     (w_op_valid         ),
    .o_op_ready                     (w_op_ready         ),
    .i_write_data                   (w_write_data       ),
    .i_write_valid                  (w_write_valid      ),
    .o_read_data                    (w_read_data        ),
    .o_read_valid                   (w_read_valid       ),
    .M_AXI_ACLK                     (ui_clk             ),
    .M_AXI_ARESETN                  (~w_ui_clk_sync_rst ),
    .M_AXI_AWID                     (M_AXI_AWID         ),
    .M_AXI_AWADDR                   (M_AXI_AWADDR       ),
    .M_AXI_AWLEN                    (M_AXI_AWLEN        ),
    .M_AXI_AWSIZE                   (M_AXI_AWSIZE       ),
    .M_AXI_AWBURST                  (M_AXI_AWBURST      ),
    .M_AXI_AWLOCK                   (M_AXI_AWLOCK       ),
    .M_AXI_AWCACHE                  (M_AXI_AWCACHE      ),
    .M_AXI_AWPROT                   (M_AXI_AWPROT       ),
    .M_AXI_AWQOS                    (M_AXI_AWQOS        ),
    .M_AXI_AWUSER                   (M_AXI_AWUSER       ),
    .M_AXI_AWVALID                  (M_AXI_AWVALID      ),
    .M_AXI_AWREADY                  (M_AXI_AWREADY      ),
    .M_AXI_WDATA                    (M_AXI_WDATA        ),
    .M_AXI_WSTRB                    (M_AXI_WSTRB        ),
    .M_AXI_WLAST                    (M_AXI_WLAST        ),
    .M_AXI_WUSER                    (M_AXI_WUSER        ),
    .M_AXI_WVALID                   (M_AXI_WVALID       ),
    .M_AXI_WREADY                   (M_AXI_WREADY       ),
    .M_AXI_BID                      (M_AXI_BID          ),
    .M_AXI_BRESP                    (M_AXI_BRESP        ),
    .M_AXI_BUSER                    (M_AXI_BUSER        ),
    .M_AXI_BVALID                   (M_AXI_BVALID       ),
    .M_AXI_BREADY                   (M_AXI_BREADY       ), 
    .M_AXI_ARID                     (M_AXI_ARID         ),
    .M_AXI_ARADDR                   (M_AXI_ARADDR       ),
    .M_AXI_ARLEN                    (M_AXI_ARLEN        ),
    .M_AXI_ARSIZE                   (M_AXI_ARSIZE       ),
    .M_AXI_ARBURST                  (M_AXI_ARBURST      ),
    .M_AXI_ARLOCK                   (M_AXI_ARLOCK       ),
    .M_AXI_ARCACHE                  (M_AXI_ARCACHE      ),
    .M_AXI_ARPROT                   (M_AXI_ARPROT       ),
    .M_AXI_ARQOS                    (M_AXI_ARQOS        ),
    .M_AXI_ARUSER                   (M_AXI_ARUSER       ),
    .M_AXI_ARVALID                  (M_AXI_ARVALID      ),
    .M_AXI_ARREADY                  (M_AXI_ARREADY      ),
    .M_AXI_RID                      (M_AXI_RID          ),
    .M_AXI_RDATA                    (M_AXI_RDATA        ),
    .M_AXI_RRESP                    (M_AXI_RRESP        ),
    .M_AXI_RLAST                    (M_AXI_RLAST        ),
    .M_AXI_RUSER                    (M_AXI_RUSER        ),
    .M_AXI_RVALID                   (M_AXI_RVALID       ),
    .M_AXI_RREADY                   (M_AXI_RREADY       ) 
    );

mig_7series_0 u_mig_axi (
    .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
	.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  
    .ui_clk                         (ui_clk                     ),  // output			ui_clk
    .ui_clk_sync_rst                (w_ui_clk_sync_rst          ),  // output			ui_clk_sync_rst
    .init_calib_complete            (init_calib_complete        ),  // output			init_calib_complete
    .mmcm_locked                    (                           ),  // output			mmcm_locked
    .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                  (                           ),  // output			app_sr_active
    .app_ref_ack                    (                           ),  // output			app_ref_ack
    .app_zq_ack                     (                           ),  // output			app_zq_ack
    .aresetn                        (~ui_clk_sync_rst           ),  // input			aresetn
    .s_axi_awid                     (M_AXI_AWID                 ),  // input [3:0]			s_axi_awid
    .s_axi_awaddr                   (M_AXI_AWADDR               ),  // input [29:0]			s_axi_awaddr
    .s_axi_awlen                    (M_AXI_AWLEN                ),  // input [7:0]			s_axi_awlen
    .s_axi_awsize                   (M_AXI_AWSIZE               ),  // input [2:0]			s_axi_awsize
    .s_axi_awburst                  (M_AXI_AWBURST              ),  // input [1:0]			s_axi_awburst
    .s_axi_awlock                   (M_AXI_AWLOCK               ),  // input [0:0]			s_axi_awlock
    .s_axi_awcache                  (M_AXI_AWCACHE              ),  // input [3:0]			s_axi_awcache
    .s_axi_awprot                   (M_AXI_AWPROT               ),  // input [2:0]			s_axi_awprot
    .s_axi_awqos                    (M_AXI_AWQOS                ),  // input [3:0]			s_axi_awqos
    .s_axi_awvalid                  (M_AXI_AWVALID              ),  // input			s_axi_awvalid
    .s_axi_awready                  (M_AXI_AWREADY              ),  // output			s_axi_awready
    .s_axi_wdata                    (M_AXI_WDATA                ),  // input [255:0]			s_axi_wdata
    .s_axi_wstrb                    (M_AXI_WSTRB                ),  // input [31:0]			s_axi_wstrb
    .s_axi_wlast                    (M_AXI_WLAST                ),  // input			s_axi_wlast
    .s_axi_wvalid                   (M_AXI_WVALID               ),  // input			s_axi_wvalid
    .s_axi_wready                   (M_AXI_WREADY               ),  // output			s_axi_wready
    .s_axi_bid                      (M_AXI_BID                  ),  // output [3:0]			s_axi_bid
    .s_axi_bresp                    (M_AXI_BRESP                ),  // output [1:0]			s_axi_bresp
    .s_axi_bvalid                   (M_AXI_BVALID               ),  // output			s_axi_bvalid
    .s_axi_bready                   (M_AXI_BREADY               ),  // input			s_axi_bready
    .s_axi_arid                     (M_AXI_ARID                 ),  // input [3:0]			s_axi_arid
    .s_axi_araddr                   (M_AXI_ARADDR               ),  // input [29:0]			s_axi_araddr
    .s_axi_arlen                    (M_AXI_ARLEN                ),  // input [7:0]			s_axi_arlen
    .s_axi_arsize                   (M_AXI_ARSIZE               ),  // input [2:0]			s_axi_arsize
    .s_axi_arburst                  (M_AXI_ARBURST              ),  // input [1:0]			s_axi_arburst
    .s_axi_arlock                   (M_AXI_ARLOCK               ),  // input [0:0]			s_axi_arlock
    .s_axi_arcache                  (M_AXI_ARCACHE              ),  // input [3:0]			s_axi_arcache
    .s_axi_arprot                   (M_AXI_ARPROT               ),  // input [2:0]			s_axi_arprot
    .s_axi_arqos                    (M_AXI_ARQOS                ),  // input [3:0]			s_axi_arqos
    .s_axi_arvalid                  (M_AXI_ARVALID              ),  // input			s_axi_arvalid
    .s_axi_arready                  (M_AXI_ARREADY              ),  // output			s_axi_arready
    .s_axi_rid                      (M_AXI_RID                  ),  // output [3:0]			s_axi_rid
    .s_axi_rdata                    (M_AXI_RDATA                ),  // output [255:0]			s_axi_rdata
    .s_axi_rresp                    (M_AXI_RRESP                ),  // output [1:0]			s_axi_rresp
    .s_axi_rlast                    (M_AXI_RLAST                ),  // output			s_axi_rlast
    .s_axi_rvalid                   (M_AXI_RVALID               ),  // output			s_axi_rvalid
    .s_axi_rready                   (M_AXI_RREADY               ),  // input			s_axi_rready
    .sys_clk_i                      (w_ddr_clk                  ),
    .clk_ref_i                      (w_ddr_clk                  ),
    .sys_rst                        (w_locked                   )   // input sys_rst 低有效
);
endmodule
c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/04/25 15:57:46
// Design Name: 
// Module Name: rw_fsm_gen
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module rw_fsm_gen(
    input               i_clk           ,
    input               i_rst           ,
    input               i_wcmd          ,
    input               i_rcmd          ,
    output              o_can_cmd       ,
    output  [1 :0]      o_op_cmd        ,
    output  [29:0]      o_op_waddr      ,
    output  [29:0]      o_op_raddr      ,
    output              o_op_valid      ,
    input               i_op_ready      ,
    output  [31:0]      o_write_data    ,
    output              o_write_valid   ,
    input   [31:0]      i_read_data     ,
    input               i_read_valid
    );

reg                     ri_wcmd         ;
reg                     ri_rcmd         ;
reg     [1 :0]          ro_op_cmd       ;
reg     [29:0]          ro_op_waddr     ;
reg     [29:0]          ro_op_raddr     ;
reg                     ro_op_valid     ;
reg                     ri_op_ready     ;
reg     [31:0]          ro_write_data   ;
reg                     ro_write_valid  ;
reg     [15:0]          r_write_cnt     ;
wire                    wcmd_pos        ;
wire                    rcmd_pos        ;

localparam      P_WADDR = 4*256         ;
localparam      P_RADDR = 4*256         ;

assign  wcmd_pos = ~ri_wcmd & i_wcmd    ;
assign  rcmd_pos = ~ri_rcmd & i_rcmd    ;
assign  o_op_cmd       = ro_op_cmd      ;
assign  o_op_waddr     = ro_op_waddr    ;
assign  o_op_raddr     = ro_op_raddr    ;
assign  o_op_valid     = ro_op_valid    ;   
assign  o_write_data   = ro_write_data  ;
assign  o_write_valid  = ro_write_valid ;
assign  o_can_cmd      = ~ro_write_valid & ~ i_read_valid;


always @(posedge i_clk,posedge i_rst) begin
    if(i_rst) begin
        ri_wcmd <= 1'b0;
        ri_rcmd <= 1'b0;
        ri_op_ready <= 1'b0;
    end
    else begin
        ri_wcmd <= i_wcmd;
        ri_rcmd <= i_rcmd;
        ri_op_ready <= i_op_ready;
    end
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        ro_op_cmd <= 2'b00;
    else if(wcmd_pos)
        ro_op_cmd <= 2'b01;
    else if(rcmd_pos)
        ro_op_cmd <= 2'b10;
    else if(ro_op_valid && ri_op_ready)
        ro_op_cmd <= 2'b00;
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        ro_op_valid <= 1'b0;
    else if(ro_op_valid && ri_op_ready)
        ro_op_valid <= 1'b0;
    else if(~ro_op_valid && wcmd_pos)
        ro_op_valid <= 1'b1;
    else if(~ro_op_valid && rcmd_pos)
        ro_op_valid <= 1'b1;
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        ro_op_waddr <= 'd0;
    else if(ro_op_valid && ri_op_ready && ro_op_cmd == 2'b01)
        ro_op_waddr <= ro_op_waddr + P_WADDR;
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        ro_op_raddr <= 'd0;
    else if(ro_op_valid && ri_op_ready && ro_op_cmd == 2'b10)
        ro_op_raddr <= ro_op_raddr + P_RADDR;
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst) begin
        ro_write_data  <= 32'd0;
        ro_write_valid <= 1'b0 ;
    end
    else if(r_write_cnt == 'd4095) begin
        ro_write_data  <= 32'd0;
        ro_write_valid <= 1'b0 ;
    end
    else if((~ro_op_valid && wcmd_pos) || ro_write_valid) begin
        ro_write_data  <= ro_write_data + 1'b1;
        ro_write_valid <= 1'b1;
    end
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst) 
        r_write_cnt <= 16'd0;
    else if(r_write_cnt == 'd4095)
        r_write_cnt <= 16'd0;
    else if(ro_write_valid)
        r_write_cnt <= r_write_cnt + 1'b1;
end

endmodule

接下来,笔者便进行上板测试

由下图可知,MIG核成功实现对DDR的初始化,init信号为高

首先通过vio进行两次写数据测试,vio控制输出逻辑为0~1的电平跳变,而代码中通过捕获上升沿,实现读或写指令的输出,写测试如下图所示:

图中展示的是第二次突发长度为256的写测试,注意写地址

AXI总线的地址最小操控单元为Byte,而笔者读写数据的位宽为4Byte,4*256 = 1Kbyte;对应地址即为0x0400,那么第二次写的地址即为0x0400,地址正确。

接下来进行读测试 ,以0地址为起始地址,突发长度256,读到的数据为1~256,与写入数据对应。

进行第二次读,读到的数据为257~512,与写入数据对应

经过上述仿真与上板测试,可以看出从UDP到DDR这条线路已经是ok的,接下来将进行GT收发器的使用讲解,关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。

相关推荐
2501_915909062 小时前
开发日常中的抓包工具经验谈:Charles 抓包工具与其它选项对比
websocket·网络协议·tcp/ip·http·网络安全·https·udp
XiaoCCCcCCccCcccC3 小时前
Linux 的 UDP 网络编程 -- 回显服务器,翻译服务器
linux·网络·udp
一只川页3 小时前
arduino平台读取鼠标光电传感器
驱动开发·单片机·嵌入式硬件·计算机外设
GateWorld3 小时前
深入浅出IIC协议 - 从总线原理到FPGA实战开发 -- 第一篇:I2C总线协议深度解剖
fpga开发·开源协议
利刃大大5 小时前
【网络编程】十、详解 UDP 协议
网络·网络协议·udp
一月千帆6 小时前
51单片机课设基于GM65模块的二维码加条形码识别
单片机·嵌入式硬件·51单片机
O。o.尊都假都7 小时前
STM32就业前景和下载KEIL软件(保姆级)
stm32·单片机·嵌入式硬件
「QT(C++)开发工程师」8 小时前
STM32 | FreeRTOS 消息队列
stm32·单片机·嵌入式硬件
sword devil9008 小时前
STM32烧录程序正常,但是运行异常
stm32·单片机·嵌入式硬件