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收发器的使用讲解,关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。

相关推荐
糖糖单片机设计6 小时前
基于STM32的空气污染检测与报警系统设计与实现
stm32·单片机·嵌入式硬件
盛世宏博北京6 小时前
工业环境稳定采集:配电室 IP 温湿度变送器 TCP/UDP 通信部署指南
单片机·tcp/ip·udp
comyccccc7 小时前
自制多路输出DCDC电源板,3.3V-12V可调 学习笔记
单片机·嵌入式硬件·硬件工程
Zwawa7 小时前
把 AO 接回来:黑线和白底之间到底差了多少
c语言·单片机·嵌入式
硅基手札7 小时前
【串口技术系列文档 07】UART控制器寄存器详解
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
甜甜的大香瓜8 小时前
【MT32F006】MT32F006之TM1621C驱动LCD
单片机
硅基手札8 小时前
【串口技术系列文档 09】FIFO管理与流控
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
硅基手札8 小时前
【串口技术系列文档 08】中断驱动vs轮询vs DMA
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
不会代码的小猴8 小时前
认识HAL库
单片机·嵌入式硬件
北城笑笑8 小时前
FPGA 55 ,FPGA 行业 2026 发展分析与报告
fpga开发·fpga