UDP--DDR--SFP,FPGA实现之模块梳理及AXI读写DDR读写上板测试
模块梳理介绍
在之前的几篇文章中,笔者详细介绍了整个项目的框架结构以及部分关键模块的实现细节。这些模块包括UDP协议栈、UDP指令监测、数据跨时钟域处理、DDR读写控制、内存读取控制以及DDR AXI控制器等。这些模块共同构成了项目的基础架构,每个模块都经过精心设计和实现,以确保系统的稳定性和高效性。
鉴于后续的GT收发器功能模块配置相对简单,而之前的模块已经形成了一定的体系规模,笔者现在将对这些模块进行功能联调,以实现全面的仿真测试。功能联调是确保各个模块能够协同工作的重要步骤,通过仿真测试可以验证模块之间的接口是否匹配,数据传输是否准确,以及整体系统是否能够按照预期运行。
而对于UDP协议栈的仿真,由于在之前的专栏已经较为详尽,在本章节中,便不再进行仿真,而是直接模拟UDP数据的发送,对于MIG核笔者同样不进行仿真,考虑到移植仿真文件比较麻烦,不如在验证AXI的正确性后,直接进行上板验证。
模块整体结构代码
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读写控制模块,进行文件循环读取
- 仿真激励代码如下
`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 begini_udp_rst = 1;i_sfp_rst = 1;i_ui_rst = 1;#100@(i_sfp_clk) begini_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) beginif (w_read_cmd) beginddr_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 : datainteger i;i_udp_data = 8'd0;i_udp_valid = 1'd0;@(posedge i_udp_clk);for(i = 0;i < byte_len ;i = i + 1)begini_udp_data <= i_udp_data + 1'b1;i_udp_valid <= 1'b1;@(posedge i_udp_clk);endi_udp_data <= 8'd0;i_udp_valid <= 1'd0;
end
endtasktask udp_cmd(input [63:0] i_cmd);begin : cmdinteger i;i_udp_data = 8'd0;i_udp_valid = 1'd0;@(posedge i_udp_clk);for(i = 0;i < 8 ;i = i + 1)begini_udp_data <= i_cmd[63:56];i_cmd <= {i_cmd[55:0],8'h0};i_udp_valid <= 1'b1;@(posedge i_udp_clk);endi_udp_data <= 8'd0;i_udp_valid <= 1'd0;
end
endtasktask ddr_data(input [15:0] byte_len);begin : ddrinteger i;r_read_data = 32'd0;r_read_valid = 1 'd0;@(posedge i_ui_clk);for(i = 0;i < 256 ;i = i + 1)beginr_read_data <= r_read_data + 1'b1;r_read_valid <= 1'b1;@(posedge i_ui_clk);endr_read_data = 32'd0;r_read_valid = 1 'd0;
end
endtaskendmodule
上述测试流程实际是对之前文章的测试进行了总结,所以在此,便不进行贴图展示结果了。
接下来,将进行AXI读写DDR的上板测试,如下所示,是笔者写的一个DDR模块顶层代码,实际是,将AXI读写DDR的控制器的op总线部分交互变为一与个可控模块进行交互,通过vio控制可控模块进行数据总线输出,读写DDR。
AXI接口的MIG核读写DDR上板测试
`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
`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) beginif(i_rst) beginri_wcmd <= 1'b0;ri_rcmd <= 1'b0;ri_op_ready <= 1'b0;endelse beginri_wcmd <= i_wcmd;ri_rcmd <= i_rcmd;ri_op_ready <= i_op_ready;end
endalways @(posedge i_clk,posedge i_rst) beginif(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;
endalways @(posedge i_clk,posedge i_rst) beginif(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;
endalways @(posedge i_clk,posedge i_rst) beginif(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;
endalways @(posedge i_clk,posedge i_rst) beginif(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;
endalways @(posedge i_clk,posedge i_rst) beginif(i_rst) beginro_write_data <= 32'd0;ro_write_valid <= 1'b0 ;endelse if(r_write_cnt == 'd4095) beginro_write_data <= 32'd0;ro_write_valid <= 1'b0 ;endelse if((~ro_op_valid && wcmd_pos) || ro_write_valid) beginro_write_data <= ro_write_data + 1'b1;ro_write_valid <= 1'b1;end
endalways @(posedge i_clk,posedge i_rst) beginif(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;
endendmodule
接下来,笔者便进行上板测试
由下图可知,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收发器的使用讲解,关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。