模块梳理介绍
在之前的几篇文章中,笔者详细介绍了整个项目的框架结构以及部分关键模块的实现细节。这些模块包括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收发器的使用讲解,关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。