10G/25G Ethernet Subsystem(4.1) IP理解和使用 Versal新版本IP
首先新建子系统IP到Block Design:



右键IP,打开example design,然后右键xxv_ethernet_0_exdes_support.bd点击Generate Output Products,这一步是为了产生仿真所需的文件,然后就可以仿真了

仿真大概56us的时候,就就开始产生信号了,

我们现在开始分析一下工程的原理,
我们主要需要关注的是如何应用,也就是说,我们需要理解顶层的链接方法,还有产生测试数据并比对的实现原理:
xxv_ethernet_0_exdes代码功能分析:
`timescale 1fs / 1fs
(* DowngradeIPIdentifiedWarnings="yes" *) // 降低IP核识别警告级别
module xxv_ethernet_0_exdes (
// 高速收发器差分接口
input wire [1-1:0] gt_rxp_in, // GT差分正输入(1通道)
input wire [1-1:0] gt_rxn_in, // GT差分负输入(1通道)
output wire [1-1:0] gt_txp_out, // GT差分正输出(1通道)
output wire [1-1:0] gt_txn_out, // GT差分负输出(1通道)
// 控制信号
input wire restart_tx_rx_0, // 收发器重启控制(触发复位序列)
input wire send_continous_pkts_0, // 连续数据包发送使能(测试模式)
// 状态指示
output wire rx_gt_locked_led_0, // GT时钟恢复锁定状态指示
output wire rx_block_lock_led_0, // 核心数据块锁定状态指示
output wire [4:0] completion_status, // 初始化完成状态码(0=成功)
output wire stat_reg_compare, // 寄存器配置校验结果
// 系统信号
input sys_reset, // 全局异步复位(高有效)
input gt_refclk_p, // GT参考时钟正端(高速时钟输入)
input gt_refclk_n, // GT参考时钟负端
input dclk // 数字逻辑时钟(用于控制逻辑)
);
parameter PKT_NUM = 20; // 测试模式数据包发送数量(影响性能测试)
// 用户接口就绪信号(bit0=TX就绪,bit1=RX就绪)
wire [31:0] ub_ready;
//// AXI4-Lite配置接口(寄存器访问)
wire s_axi_aclk_0; // AXI-Lite接口时钟(通常连接到dclk)
wire s_axi_aresetn_0; // AXI-Lite异步复位(低有效)
// 写地址通道信号
wire [31:0] s_axi_awaddr_0; // 写地址总线(32位地址)
wire s_axi_awvalid_0; // 写地址有效指示
wire s_axi_awready_0; // 写地址就绪响应
// 写数据通道信号
wire [31:0] s_axi_wdata_0; // 写数据总线(32位数据)
wire [ 3:0] s_axi_wstrb_0; // 字节使能信号(4位,每位对应1字节)
wire s_axi_wvalid_0; // 写数据有效指示
wire s_axi_wready_0; // 写数据就绪响应
// 写响应通道信号
wire [ 1:0] s_axi_bresp_0; // 写响应状态(00=OKAY)
wire s_axi_bvalid_0; // 写响应有效指示
wire s_axi_bready_0; // 写响应接收就绪
// 读地址通道信号
wire [31:0] s_axi_araddr_0; // 读地址总线(32位地址)
wire s_axi_arvalid_0; // 读地址有效指示
wire s_axi_arready_0; // 读地址就绪响应
// 读数据通道信号
wire [31:0] s_axi_rdata_0; // 读数据总线(32位数据)
wire [ 1:0] s_axi_rresp_0; // 读响应状态(00=OKAY)
wire s_axi_rvalid_0; // 读数据有效指示
wire s_axi_rready_0; // 读数据接收就绪
// 性能监控时钟(用于统计计数器)
wire pm_tick_0;
wire stat_reg_compare_0; // 寄存器配置校验结果(硬件校验)
wire gt_loopback_out_0; // GT环回模式状态指示
wire block_lock_led_0; // 数据通路块锁定状态
wire rx_core_clk_0; // 接收核心时钟(来自GT恢复时钟)
wire rx_clk_out_0; // 接收时钟输出(连接到外部时钟网络)
wire tx_clk_out_0; // 发送时钟输出(连接到外部时钟网络)
// 时钟连接(使用接收时钟作为核心时钟)
assign rx_core_clk_0 = rx_clk_out_0;
//// 接收模块信号
wire rx_reset_0; // 接收模块复位(同步到rx_core_clk)
wire user_rx_reset_0; // 用户域接收复位(跨时钟域同步后)
wire rxrecclkout_0; // 恢复时钟输出(来自GT的恢复时钟)
//// 接收AXIS接口(64位数据路径)
wire rx_axis_tvalid_0; // 接收数据有效指示
wire [63:0] rx_axis_tdata_0; // 接收数据总线(64位数据)
wire rx_axis_tlast_0; // 帧结束标志(TLAST有效时)
wire [ 7:0] rx_axis_tkeep_0; // 字节有效指示(8位,每位对应8字节)
wire rx_axis_tuser_0; // 用户信号(携带错误标志等)
wire [55:0] rx_preambleout_0; // 接收前导码输出(可选功能)
//// 接收状态统计信号(文档表24、41)
wire stat_rx_block_lock_0; // 数据块锁定状态(PCS层对齐)
// 帧错误检测
wire stat_rx_framing_err_valid_0; // 帧对齐错误有效指示
wire stat_rx_framing_err_0; // 帧对齐错误标志
// 物理层状态
wire stat_rx_hi_ber_0; // 高误码率告警(BER超过阈值)
wire stat_rx_valid_ctrl_code_0; // 有效控制字符检测
wire stat_rx_bad_code_0; // 无效控制字符检测
// 数据包统计(文档表89-90)
wire [ 1:0] stat_rx_total_packets_0; // 总接收包数(递增计数)
wire stat_rx_total_good_packets_0; // 有效包数(无错误)
wire [ 3:0] stat_rx_total_bytes_0; // 总字节数(低4位)
wire [13:0] stat_rx_total_good_bytes_0; // 有效字节数(高14位)
// 数据包尺寸统计
wire stat_rx_packet_small_0; // 过小包(<64字节)
wire stat_rx_jabber_0; // 过长包(>1518字节)
wire stat_rx_packet_large_0; // 大包(>1518字节)
wire stat_rx_oversize_0; // 超长包(>1518字节)
wire stat_rx_undersize_0; // 过小包(<64字节)
wire stat_rx_toolong_0; // 超长包(>9216字节)
wire stat_rx_fragment_0; // 碎片包(<64字节且FCS错误)
wire stat_rx_packet_64_bytes_0; // 64字节包
wire stat_rx_packet_65_127_bytes_0; // 65-127字节包
wire stat_rx_packet_128_255_bytes_0; // 128-255字节包
wire stat_rx_packet_256_511_bytes_0; // 256-511字节包
wire stat_rx_packet_512_1023_bytes_0; // 512-1023字节包
wire stat_rx_packet_1024_1518_bytes_0; // 1024-1518字节包
wire stat_rx_packet_1519_1522_bytes_0; // 1519-1522字节包(VLAN)
wire stat_rx_packet_1523_1548_bytes_0; // 1523-1548字节包
// FCS错误统计
wire [ 1:0] stat_rx_bad_fcs_0; // FCS错误包计数
wire stat_rx_packet_bad_fcs_0; // FCS错误包标志
wire [ 1:0] stat_rx_stomped_fcs_0; // 被覆盖的FCS错误
// 大尺寸包统计
wire stat_rx_packet_1549_2047_bytes_0; // 1549-2047字节包
wire stat_rx_packet_2048_4095_bytes_0; // 2048-4095字节包
wire stat_rx_packet_4096_8191_bytes_0; // 4096-8191字节包
wire stat_rx_packet_8192_9215_bytes_0; // 8192-9215字节包(Jumbo帧)
// 数据包类型统计
wire stat_rx_unicast_0; // 单播包
wire stat_rx_multicast_0; // 组播包
wire stat_rx_broadcast_0; // 广播包
wire stat_rx_vlan_0; // VLAN标记包
wire stat_rx_inrangeerr_0; // 长度/类型字段越界
// 物理层错误
wire stat_rx_bad_preamble_0; // 前导码错误
wire stat_rx_bad_sfd_0; // 帧起始定界符错误
wire stat_rx_got_signal_os_0; // 信号有序集检测
wire stat_rx_test_pattern_mismatch_0; // 测试模式匹配错误
wire stat_rx_truncated_0; // 截断包(接收缓冲溢出)
wire stat_rx_local_fault_0; // 本地故障状态(PCS层)
wire stat_rx_remote_fault_0; // 远端故障状态(来自链路伙伴)
wire stat_rx_internal_local_fault_0; // 内部本地故障
wire stat_rx_received_local_fault_0; // 接收到的本地故障
wire stat_rx_status_0; // 接收状态汇总
//// 发送模块信号
wire tx_reset_0; // 发送模块复位(同步到tx_clk_out)
wire user_tx_reset_0; // 用户域发送复位(跨时钟域同步后)
//// 发送AXIS接口(64位数据路径)
wire tx_axis_tready_0; // 发送就绪指示(背压信号)
wire tx_axis_tvalid_0; // 发送数据有效指示
wire [63:0] tx_axis_tdata_0; // 发送数据总线(64位数据)
wire tx_axis_tlast_0; // 帧结束标志
wire [ 7:0] tx_axis_tkeep_0; // 字节有效指示(8位)
wire tx_axis_tuser_0; // 用户信号(携带错误注入等)
wire tx_unfout_0; // 未完成帧输出(异常终止标志)
wire [55:0] tx_preamblein_0; // 自定义前导码输入
//// 发送控制信号(文档表23)
wire ctl_tx_send_lfi_0; // 发送本地故障指示(LFI优先级最高)
wire ctl_tx_send_rfi_0; // 发送远端故障指示(RFI)
wire ctl_tx_send_idle_0; // 发送空闲字符(链路维护)
//// 发送状态统计
wire stat_tx_total_packets_0; // 总发送包数
wire [ 3:0] stat_tx_total_bytes_0; // 总发送字节数(低4位)
wire stat_tx_total_good_packets_0; // 有效发送包数
wire [13:0] stat_tx_total_good_bytes_0; // 有效发送字节数(高14位)
// 数据包尺寸统计(与接收侧对应)
wire stat_tx_packet_64_bytes_0;
wire stat_tx_packet_65_127_bytes_0;
wire stat_tx_packet_128_255_bytes_0;
wire stat_tx_packet_256_511_bytes_0;
wire stat_tx_packet_512_1023_bytes_0;
wire stat_tx_packet_1024_1518_bytes_0;
wire stat_tx_packet_1519_1522_bytes_0;
wire stat_tx_packet_1523_1548_bytes_0;
wire stat_tx_packet_small_0;
wire stat_tx_packet_large_0;
wire stat_tx_packet_1549_2047_bytes_0;
wire stat_tx_packet_2048_4095_bytes_0;
wire stat_tx_packet_4096_8191_bytes_0;
wire stat_tx_packet_8192_9215_bytes_0;
// 数据包类型统计
wire stat_tx_unicast_0;
wire stat_tx_multicast_0;
wire stat_tx_broadcast_0;
wire stat_tx_vlan_0;
// 发送错误统计
wire stat_tx_bad_fcs_0; // FCS错误包
wire stat_tx_frame_error_0; // 帧格式错误
wire stat_tx_local_fault_0; // 本地故障状态
// GT状态信号
wire gtpowergood_out_0; // GT电源就绪指示
wire [ 2:0] txoutclksel_in_0; // 发送时钟选择(固定101)
wire [ 2:0] rxoutclksel_in_0; // 接收时钟选择(固定101)
assign txoutclksel_in_0 = 3'b101; // GT向导推荐配置
assign rxoutclksel_in_0 = 3'b101;
// 状态指示逻辑(组合逻辑)
assign rx_block_lock_led_0 = block_lock_led_0 & stat_rx_status_0;
// 用户寄存器接口
wire [31:0] user_reg0_0; // 用户自定义寄存器0
wire qpllreset_in_0; // QPLL复位控制(默认禁用)
assign qpllreset_in_0 = 1'b0;
// 内部信号
wire [4:0] completion_status_0; // 初始化状态码
wire gt_refclk_out; // GT参考时钟缓冲输出
wire [3:0] gt_txn_out_int_0; // GT差分输出内部信号
wire [3:0] gt_txp_out_int_0;
// 差分信号连接(单通道模式)
assign gt_txn_out = gt_txn_out_int_0[0];
assign gt_txp_out = gt_txp_out_int_0[0];
// 复位同步逻辑(文档图20、21)
wire user_rx_reset_int_0; // 用户域RX复位请求
wire user_tx_reset_int_0; // 用户域TX复位请求
wire rx_resetdone_out_0; // RX复位完成指示
wire tx_resetdone_out_0; // TX复位完成指示
// RX复位同步器(跨时钟域)
xxv_ethernet_0_cdc_sync_2stage #(
.WIDTH(1)
) i_xxv_ethernet_0_user_rx_reset_syncer (
.clk (rx_core_clk_0), // 目标时钟域:接收核心时钟
.signal_in (user_rx_reset_int_0), // 源信号(异步复位)
.signal_out(user_rx_reset_0) // 同步后的复位信号
);
// TX复位同步器(跨时钟域)
xxv_ethernet_0_cdc_sync_2stage #(
.WIDTH(1)
) i_xxv_ethernet_0_user_tx_reset_syncer (
.clk (tx_clk_out_0), // 目标时钟域:发送时钟
.signal_in (user_tx_reset_int_0), // 源信号(异步复位)
.signal_out(user_tx_reset_0) // 同步后的复位信号
);
// 复位逻辑(依赖复位完成信号)
assign user_rx_reset_int_0 = ~rx_resetdone_out_0; // 复位未完成时保持复位
assign user_tx_reset_int_0 = ~rx_resetdone_out_0;
// 核心支持模块实例化(包含GT、PCS、MAC)
xxv_ethernet_0_exdes_support_wrapper i_xxv_ethernet_0_exdes_support_wrapper (
.gpo_0(ub_ready),
.xxv_ethernet_0_core_diff_gt_ref_clock_clk_n(gt_refclk_n),
.xxv_ethernet_0_core_diff_gt_ref_clock_clk_p(gt_refclk_p),
.axis_rx_0_0_tdata(rx_axis_tdata_0),
.axis_rx_0_0_tkeep(rx_axis_tkeep_0),
.axis_rx_0_0_tlast(rx_axis_tlast_0),
.axis_rx_0_0_tuser(rx_axis_tuser_0),
.axis_rx_0_0_tvalid(rx_axis_tvalid_0),
.axis_tx_0_0_tdata(tx_axis_tdata_0),
.axis_tx_0_0_tkeep(tx_axis_tkeep_0),
.axis_tx_0_0_tlast(tx_axis_tlast_0),
.axis_tx_0_0_tready(tx_axis_tready_0),
.axis_tx_0_0_tuser(tx_axis_tuser_0),
.axis_tx_0_0_tvalid(tx_axis_tvalid_0),
.s_axi_0_0_araddr(s_axi_araddr_0),
.s_axi_0_0_arready(s_axi_arready_0),
.s_axi_0_0_arvalid(s_axi_arvalid_0),
.s_axi_0_0_awaddr(s_axi_awaddr_0),
.s_axi_0_0_awready(s_axi_awready_0),
.s_axi_0_0_awvalid(s_axi_awvalid_0),
.s_axi_0_0_bready(s_axi_bready_0),
.s_axi_0_0_bresp(s_axi_bresp_0),
.s_axi_0_0_bvalid(s_axi_bvalid_0),
.s_axi_0_0_rdata(s_axi_rdata_0),
.s_axi_0_0_rready(s_axi_rready_0),
.s_axi_0_0_rresp(s_axi_rresp_0),
.s_axi_0_0_rvalid(s_axi_rvalid_0),
.s_axi_0_0_wdata(s_axi_wdata_0),
.s_axi_0_0_wready(s_axi_wready_0),
.s_axi_0_0_wstrb(s_axi_wstrb_0),
.s_axi_0_0_wvalid(s_axi_wvalid_0),
.s_axi_aclk_0_0(s_axi_aclk_0),
.s_axi_aresetn_0_0(s_axi_aresetn_0),
.pm_tick_0_0(pm_tick_0),
.user_reg0_0_0(user_reg0_0),
.ctl_tx_0_0_ctl_tx_send_idle(ctl_tx_send_idle_0),
.ctl_tx_0_0_ctl_tx_send_lfi(ctl_tx_send_lfi_0),
.ctl_tx_0_0_ctl_tx_send_rfi(ctl_tx_send_rfi_0),
.gt_rxn_in_0({3'b0, gt_rxn_in}),
.gt_rxp_in_0({3'b0, gt_rxp_in}),
.gt_txn_out_0(gt_txn_out_int_0),
.gt_txp_out_0(gt_txp_out_int_0),
.rx_resetdone_out_0_0(rx_resetdone_out_0),
.tx_resetdone_out_0_0(tx_resetdone_out_0),
.rx_core_clk_0(rx_clk_out_0),
.rx_reset_0(user_rx_reset_0),
.rx_serdes_clk_0(rx_clk_out_0),
.rx_usrclk_out_0(rx_clk_out_0),
.rx_preambleout_0_0 (rx_preambleout_0),
.tx_preamblein_0 (tx_preamblein_0),
.tx_unfout_0 (tx_unfout_0),
.stat_rx_0_0_stat_rx_block_lock (stat_rx_block_lock_0),
.stat_rx_0_0_stat_rx_framing_err (stat_rx_framing_err_0),
.stat_rx_0_0_stat_rx_framing_err_valid (stat_rx_framing_err_valid_0),
.stat_rx_0_0_stat_rx_hi_ber (stat_rx_hi_ber_0),
.stat_rx_0_0_stat_rx_valid_ctrl_code (stat_rx_valid_ctrl_code_0),
.stat_rx_0_0_stat_rx_bad_code (stat_rx_bad_code_0),
.stat_rx_0_0_stat_rx_local_fault (stat_rx_local_fault_0),
.stat_rx_status_0_0 (stat_rx_status_0),
.stat_rx_0_0_stat_rx_bad_fcs (stat_rx_bad_fcs_0),
.stat_rx_0_0_stat_rx_bad_preamble (stat_rx_bad_preamble_0),
.stat_rx_0_0_stat_rx_bad_sfd (stat_rx_bad_sfd_0),
.stat_rx_0_0_stat_rx_fragment (stat_rx_fragment_0),
.stat_rx_0_0_stat_rx_got_signal_os (stat_rx_got_signal_os_0),
.stat_rx_0_0_stat_rx_internal_local_fault (stat_rx_internal_local_fault_0),
.stat_rx_0_0_stat_rx_jabber (stat_rx_jabber_0),
.stat_rx_0_0_stat_rx_oversize (stat_rx_oversize_0),
.stat_rx_0_0_stat_rx_packet_1024_1518_bytes(stat_rx_packet_1024_1518_bytes_0),
.stat_rx_0_0_stat_rx_packet_128_255_bytes (stat_rx_packet_128_255_bytes_0),
.stat_rx_0_0_stat_rx_packet_1519_1522_bytes(stat_rx_packet_1519_1522_bytes_0),
.stat_rx_0_0_stat_rx_packet_1523_1548_bytes(stat_rx_packet_1523_1548_bytes_0),
.stat_rx_0_0_stat_rx_packet_1549_2047_bytes(stat_rx_packet_1549_2047_bytes_0),
.stat_rx_0_0_stat_rx_packet_2048_4095_bytes(stat_rx_packet_2048_4095_bytes_0),
.stat_rx_0_0_stat_rx_packet_256_511_bytes (stat_rx_packet_256_511_bytes_0),
.stat_rx_0_0_stat_rx_packet_4096_8191_bytes(stat_rx_packet_4096_8191_bytes_0),
.stat_rx_0_0_stat_rx_packet_512_1023_bytes (stat_rx_packet_512_1023_bytes_0),
.stat_rx_0_0_stat_rx_packet_64_bytes (stat_rx_packet_64_bytes_0),
.stat_rx_0_0_stat_rx_packet_65_127_bytes (stat_rx_packet_65_127_bytes_0),
.stat_rx_0_0_stat_rx_packet_8192_9215_bytes(stat_rx_packet_8192_9215_bytes_0),
.stat_rx_0_0_stat_rx_packet_bad_fcs (stat_rx_packet_bad_fcs_0),
.stat_rx_0_0_stat_rx_packet_large (stat_rx_packet_large_0),
.stat_rx_0_0_stat_rx_packet_small (stat_rx_packet_small_0),
.stat_rx_0_0_stat_rx_received_local_fault (stat_rx_received_local_fault_0),
.stat_rx_0_0_stat_rx_remote_fault (stat_rx_remote_fault_0),
.stat_rx_0_0_stat_rx_stomped_fcs (stat_rx_stomped_fcs_0),
.stat_rx_0_0_stat_rx_test_pattern_mismatch (stat_rx_test_pattern_mismatch_0),
.stat_rx_0_0_stat_rx_toolong (stat_rx_toolong_0),
.stat_rx_0_0_stat_rx_total_bytes (stat_rx_total_bytes_0),
.stat_rx_0_0_stat_rx_total_good_bytes (stat_rx_total_good_bytes_0),
.stat_rx_0_0_stat_rx_total_good_packets (stat_rx_total_good_packets_0),
.stat_rx_0_0_stat_rx_total_packets (stat_rx_total_packets_0),
.stat_rx_0_0_stat_rx_truncated (stat_rx_truncated_0),
.stat_rx_0_0_stat_rx_undersize (stat_rx_undersize_0),
.stat_rx_0_0_stat_rx_vlan (stat_rx_vlan_0),
.stat_rx_0_0_stat_rx_unicast (stat_rx_unicast_0),
.stat_rx_0_0_stat_rx_multicast (stat_rx_multicast_0),
.stat_rx_0_0_stat_rx_broadcast (stat_rx_broadcast_0),
.stat_rx_0_0_stat_rx_inrangeerr (stat_rx_inrangeerr_0),
.stat_tx_0_0_stat_tx_bad_fcs (stat_tx_bad_fcs_0),
.stat_tx_0_0_stat_tx_frame_error (stat_tx_frame_error_0),
.stat_tx_0_0_stat_tx_packet_1024_1518_bytes(stat_tx_packet_1024_1518_bytes_0),
.stat_tx_0_0_stat_tx_packet_128_255_bytes (stat_tx_packet_128_255_bytes_0),
.stat_tx_0_0_stat_tx_packet_1519_1522_bytes(stat_tx_packet_1519_1522_bytes_0),
.stat_tx_0_0_stat_tx_packet_1523_1548_bytes(stat_tx_packet_1523_1548_bytes_0),
.stat_tx_0_0_stat_tx_packet_1549_2047_bytes(stat_tx_packet_1549_2047_bytes_0),
.stat_tx_0_0_stat_tx_packet_2048_4095_bytes(stat_tx_packet_2048_4095_bytes_0),
.stat_tx_0_0_stat_tx_packet_256_511_bytes (stat_tx_packet_256_511_bytes_0),
.stat_tx_0_0_stat_tx_packet_4096_8191_bytes(stat_tx_packet_4096_8191_bytes_0),
.stat_tx_0_0_stat_tx_packet_512_1023_bytes (stat_tx_packet_512_1023_bytes_0),
.stat_tx_0_0_stat_tx_packet_64_bytes (stat_tx_packet_64_bytes_0),
.stat_tx_0_0_stat_tx_packet_65_127_bytes (stat_tx_packet_65_127_bytes_0),
.stat_tx_0_0_stat_tx_packet_8192_9215_bytes(stat_tx_packet_8192_9215_bytes_0),
.stat_tx_0_0_stat_tx_packet_large (stat_tx_packet_large_0),
.stat_tx_0_0_stat_tx_packet_small (stat_tx_packet_small_0),
.stat_tx_0_0_stat_tx_total_bytes (stat_tx_total_bytes_0),
.stat_tx_0_0_stat_tx_total_good_bytes (stat_tx_total_good_bytes_0),
.stat_tx_0_0_stat_tx_total_good_packets (stat_tx_total_good_packets_0),
.stat_tx_0_0_stat_tx_total_packets (stat_tx_total_packets_0),
.stat_tx_0_0_stat_tx_vlan (stat_tx_vlan_0),
.stat_tx_0_0_stat_tx_unicast (stat_tx_unicast_0),
.stat_tx_0_0_stat_tx_multicast (stat_tx_multicast_0),
.stat_tx_0_0_stat_tx_broadcast (stat_tx_broadcast_0),
.stat_tx_0_0_stat_tx_local_fault(stat_tx_local_fault_0),
.tx_core_clk_0 (tx_clk_out_0),
.tx_usrclk_out_0 (tx_clk_out_0),
.tx_reset_0 (user_tx_reset_0),
.rx_serdes_reset_0_0 (user_rx_reset_0),
.apb3clk_quad (dclk),
.gtwiz_reset_clk_freerun_in_0_0 (dclk)
);
// 数据包生成监控模块(测试功能)
xxv_ethernet_0_pkt_gen_mon #(
.PKT_NUM(PKT_NUM)
) i_xxv_ethernet_0_pkt_gen_mon_0 (
.gen_clk(tx_clk_out_0),
.mon_clk(rx_core_clk_0),
.dclk(dclk),
.sys_reset(sys_reset),
.ub_ready(ub_ready),
.restart_tx_rx(restart_tx_rx_0 | user_tx_reset_0),
.send_continuous_pkts(send_continous_pkts_0),
//// User Interface signals
.completion_status(completion_status_0),
.stat_reg_compare(stat_reg_compare_0),
//// AXI4 Lite Interface Signals
.s_axi_aclk(s_axi_aclk_0),
.s_axi_aresetn(s_axi_aresetn_0),
.s_axi_awaddr(s_axi_awaddr_0),
.s_axi_awvalid(s_axi_awvalid_0),
.s_axi_awready(s_axi_awready_0),
.s_axi_wdata(s_axi_wdata_0),
.s_axi_wstrb(s_axi_wstrb_0),
.s_axi_wvalid(s_axi_wvalid_0),
.s_axi_wready(s_axi_wready_0),
.s_axi_bresp(s_axi_bresp_0),
.s_axi_bvalid(s_axi_bvalid_0),
.s_axi_bready(s_axi_bready_0),
.s_axi_araddr(s_axi_araddr_0),
.s_axi_arvalid(s_axi_arvalid_0),
.s_axi_arready(s_axi_arready_0),
.s_axi_rdata(s_axi_rdata_0),
.s_axi_rresp(s_axi_rresp_0),
.s_axi_rvalid(s_axi_rvalid_0),
.s_axi_rready(s_axi_rready_0),
.pm_tick(pm_tick_0),
//// RX Signals
.rx_reset(rx_reset_0),
.user_rx_reset(user_rx_reset_0),
.rx_axis_tvalid(rx_axis_tvalid_0),
.rx_axis_tdata (rx_axis_tdata_0),
.rx_axis_tlast (rx_axis_tlast_0),
.rx_axis_tkeep (rx_axis_tkeep_0),
.rx_axis_tuser (rx_axis_tuser_0),
.rx_preambleout(rx_preambleout_0),
//// RX Control Signals
//// RX Stats Signals
.stat_rx_block_lock(stat_rx_block_lock_0),
.stat_rx_framing_err_valid(stat_rx_framing_err_valid_0),
.stat_rx_framing_err(stat_rx_framing_err_0),
.stat_rx_hi_ber(stat_rx_hi_ber_0),
.stat_rx_valid_ctrl_code(stat_rx_valid_ctrl_code_0),
.stat_rx_bad_code(stat_rx_bad_code_0),
.stat_rx_total_packets(stat_rx_total_packets_0),
.stat_rx_total_good_packets(stat_rx_total_good_packets_0),
.stat_rx_total_bytes(stat_rx_total_bytes_0),
.stat_rx_total_good_bytes(stat_rx_total_good_bytes_0),
.stat_rx_packet_small(stat_rx_packet_small_0),
.stat_rx_jabber(stat_rx_jabber_0),
.stat_rx_packet_large(stat_rx_packet_large_0),
.stat_rx_oversize(stat_rx_oversize_0),
.stat_rx_undersize(stat_rx_undersize_0),
.stat_rx_toolong(stat_rx_toolong_0),
.stat_rx_fragment(stat_rx_fragment_0),
.stat_rx_packet_64_bytes(stat_rx_packet_64_bytes_0),
.stat_rx_packet_65_127_bytes(stat_rx_packet_65_127_bytes_0),
.stat_rx_packet_128_255_bytes(stat_rx_packet_128_255_bytes_0),
.stat_rx_packet_256_511_bytes(stat_rx_packet_256_511_bytes_0),
.stat_rx_packet_512_1023_bytes(stat_rx_packet_512_1023_bytes_0),
.stat_rx_packet_1024_1518_bytes(stat_rx_packet_1024_1518_bytes_0),
.stat_rx_packet_1519_1522_bytes(stat_rx_packet_1519_1522_bytes_0),
.stat_rx_packet_1523_1548_bytes(stat_rx_packet_1523_1548_bytes_0),
.stat_rx_bad_fcs(stat_rx_bad_fcs_0),
.stat_rx_packet_bad_fcs(stat_rx_packet_bad_fcs_0),
.stat_rx_stomped_fcs(stat_rx_stomped_fcs_0),
.stat_rx_packet_1549_2047_bytes(stat_rx_packet_1549_2047_bytes_0),
.stat_rx_packet_2048_4095_bytes(stat_rx_packet_2048_4095_bytes_0),
.stat_rx_packet_4096_8191_bytes(stat_rx_packet_4096_8191_bytes_0),
.stat_rx_packet_8192_9215_bytes(stat_rx_packet_8192_9215_bytes_0),
.stat_rx_unicast(stat_rx_unicast_0),
.stat_rx_multicast(stat_rx_multicast_0),
.stat_rx_broadcast(stat_rx_broadcast_0),
.stat_rx_vlan(stat_rx_vlan_0),
.stat_rx_inrangeerr(stat_rx_inrangeerr_0),
.stat_rx_bad_preamble(stat_rx_bad_preamble_0),
.stat_rx_bad_sfd(stat_rx_bad_sfd_0),
.stat_rx_got_signal_os(stat_rx_got_signal_os_0),
.stat_rx_test_pattern_mismatch(stat_rx_test_pattern_mismatch_0),
.stat_rx_truncated(stat_rx_truncated_0),
.stat_rx_local_fault(stat_rx_local_fault_0),
.stat_rx_remote_fault(stat_rx_remote_fault_0),
.stat_rx_internal_local_fault(stat_rx_internal_local_fault_0),
.stat_rx_received_local_fault(stat_rx_received_local_fault_0),
.tx_reset(tx_reset_0),
.user_tx_reset(user_tx_reset_0),
//// TX AXIS Signals
.tx_axis_tready(tx_axis_tready_0),
.tx_axis_tvalid(tx_axis_tvalid_0),
.tx_axis_tdata(tx_axis_tdata_0),
.tx_axis_tlast(tx_axis_tlast_0),
.tx_axis_tkeep(tx_axis_tkeep_0),
.tx_axis_tuser(tx_axis_tuser_0),
.tx_unfout(tx_unfout_0),
.tx_preamblein(tx_preamblein_0),
//// TX Control Signals
.ctl_tx_send_lfi(ctl_tx_send_lfi_0),
.ctl_tx_send_rfi(ctl_tx_send_rfi_0),
.ctl_tx_send_idle(ctl_tx_send_idle_0),
//// TX Stats Signals
.stat_tx_total_packets(stat_tx_total_packets_0),
.stat_tx_total_bytes(stat_tx_total_bytes_0),
.stat_tx_total_good_packets(stat_tx_total_good_packets_0),
.stat_tx_total_good_bytes(stat_tx_total_good_bytes_0),
.stat_tx_packet_64_bytes(stat_tx_packet_64_bytes_0),
.stat_tx_packet_65_127_bytes(stat_tx_packet_65_127_bytes_0),
.stat_tx_packet_128_255_bytes(stat_tx_packet_128_255_bytes_0),
.stat_tx_packet_256_511_bytes(stat_tx_packet_256_511_bytes_0),
.stat_tx_packet_512_1023_bytes(stat_tx_packet_512_1023_bytes_0),
.stat_tx_packet_1024_1518_bytes(stat_tx_packet_1024_1518_bytes_0),
.stat_tx_packet_1519_1522_bytes(stat_tx_packet_1519_1522_bytes_0),
.stat_tx_packet_1523_1548_bytes(stat_tx_packet_1523_1548_bytes_0),
.stat_tx_packet_small(stat_tx_packet_small_0),
.stat_tx_packet_large(stat_tx_packet_large_0),
.stat_tx_packet_1549_2047_bytes(stat_tx_packet_1549_2047_bytes_0),
.stat_tx_packet_2048_4095_bytes(stat_tx_packet_2048_4095_bytes_0),
.stat_tx_packet_4096_8191_bytes(stat_tx_packet_4096_8191_bytes_0),
.stat_tx_packet_8192_9215_bytes(stat_tx_packet_8192_9215_bytes_0),
.stat_tx_unicast(stat_tx_unicast_0),
.stat_tx_multicast(stat_tx_multicast_0),
.stat_tx_broadcast(stat_tx_broadcast_0),
.stat_tx_vlan(stat_tx_vlan_0),
.stat_tx_bad_fcs(stat_tx_bad_fcs_0),
.stat_tx_frame_error(stat_tx_frame_error_0),
.stat_tx_local_fault(stat_tx_local_fault_0),
.rx_gt_locked_led(rx_gt_locked_led_0),
.rx_block_lock_led(block_lock_led_0)
);
// 状态信号输出
assign completion_status = completion_status_0;
assign stat_reg_compare = stat_reg_compare_0;
endmodulexxv_ethernet_0_pkt_gen_mon代码功能分析:
核心架构
以太网数据包生成器/监视器(xxv_ethernet_0_pkt_gen_mon)
包含AXI-Lite控制接口和AXI-Stream数据接口
采用多级状态机(S0-S7)控制初始化和数据传输流程
case(state) S0: state <= ok_to_start ? S1 : S0; // 等待启动条件 S1: begin // 初始化定时器 common_timer <= cvt_us(32'd10_000); state <= S2; end S2: state <= (|common_timer) ? S2 : S3; // 等待10ms稳定 S3: begin // 触发系统复位 sys_reset <= 1'b1; state <= S4; end S4: state <= (|common_timer) ? S4 : S5; // 保持复位3周期 S5: begin // 检查链路状态 if(~&stat_rx_block_lock) completion_status <= NO_LANE_SYNC; state <= S6; end //后续状态处理数据包生成与校验 //我们如果要修改,可以从这里开始
时钟域同步 :cdc_sync模块处理跨时钟域信号
xxv_ethernet_0_user_cdc_sync i_xxv_ethernet_0_core_cdc_sync_block_lock_syncer ( .clk(gen_clk), .signal_in(stat_rx_block_lock), .signal_out(stat_rx_block_lock_sync) ) 功能 :通过三级同步器处理跨时钟域信号(如stat_rx_block_lock) 实现 :使用异步寄存器链(ASYNC_REG)消除亚稳态 关键参数 :同步延迟3个时钟周期
PRBS生成 :用于产生伪随机测试数据流
// 在pkt_len_gen模块中 CRC <= {CRC, ^(CRC_POLYNOMIAL & {CRC,1'b0})} 算法 :基于多项式0x104C11DB7的32位CRC生成 数据流 : 通过LFSR生成伪随机序列 每个时钟周期生成64位数据 支持固定/随机长度(64-9000字节)CRC校验 :32位CRC计算模块(多项式0x104C11DB7)
包长度生成 :支持固定/随机长度(64-9000字节)
错误检测 :数据比对模块(cmpr)验证传输完整性
主要功能模块
数据流流程

关键参数
目的MAC:FF:FF:FF:FF:FF:FF(广播地址) 源MAC:14:FE:B5:DD:9A:82 以太网类型:0x0600(Xerox NS IDP)
其中的状态机模块我添加了注释:
module xxv_ethernet_0_example_fsm_axis #( parameter VL_LANES_PER_GENERATOR = 1 // 每个生成器使用的通道数 ) ( input wire dclk, // 数字逻辑时钟(驱动状态机) input wire fsm_reset, // 状态机全局复位(高有效) input wire send_continuous_pkts,// 连续发送数据包使能 input wire [VL_LANES_PER_GENERATOR-1:0] stat_rx_block_lock, // 接收块锁定状态 input wire [VL_LANES_PER_GENERATOR-1:0] stat_rx_synced, // 通道同步状态 input wire stat_rx_aligned, // 多通道对齐状态 input wire stat_rx_status, // 接收状态有效指示 input wire tx_timeout, // 发送超时错误 input wire tx_done, // 发送完成标志 input wire ok_to_start, // 启动测试许可信号 input wire [47:0] rx_packet_count, // 接收数据包计数 input wire [63:0] rx_total_bytes, // 接收总字节数 input wire rx_errors, // 接收协议错误 input wire rx_data_errors, // 接收数据位错误 input wire [47:0] tx_sent_count,// 发送数据包计数 input wire [63:0] tx_total_bytes,// 发送总字节数 output reg sys_reset, // 系统复位输出 output reg pktgen_enable, // 数据包生成器使能 output reg [4:0] completion_status // 测试完成状态码 ); // 仿真加速模式配置 `ifdef SIM_SPEED_UP parameter [31:0] STARTUP_TIME = 32'd5000; // 仿真模式启动时间(5000时钟周期) `else parameter [31:0] STARTUP_TIME = 32'd50_000; // 硬件模式启动时间(50,000时钟周期) `endif // 状态机参数定义 parameter GENERATOR_COUNT = 1; // 数据生成器数量 parameter [4:0] NO_START = 5'h1F, // 未启动状态 TEST_START = 5'd0, // 测试启动 SUCCESSFUL_COMPLETION = 5'd1, // 成功完成 NO_BLOCK_LOCK = 5'd2, // 未获得块锁定 PARTIAL_BLOCK_LOCK = 5'd3,// 部分块锁定 INCONSISTENT_BLOCK_LOCK = 5'd4, // 块锁定不一致 NO_LANE_SYNC = 5'd5, // 通道未同步 PARTIAL_LANE_SYNC = 5'd6, // 部分通道同步 INCONSISTENT_LANE_SYNC = 5'd7, // 通道同步不一致 NO_ALIGN_OR_STATUS = 5'd8, // 未对齐或状态丢失 LOSS_OF_STATUS = 5'd9, // 状态丢失 TX_TIMED_OUT = 5'd10, // 发送超时 NO_DATA_SENT = 5'd11, // 未发送数据 SENT_COUNT_MISMATCH = 5'd12, // 发送计数不匹配 BYTE_COUNT_MISMATCH = 5'd13, // 字节数不匹配 LBUS_PROTOCOL = 5'd14, // 协议错误 BIT_ERRORS_IN_DATA = 5'd15; // 数据位错误 // 状态编码定义(格雷码编码) localparam [4:0] S0 = 5'b00000, // 初始化等待 S1 = 5'b00001, // 系统启动延时 S2 = 5'b00011, // 延时等待 S3 = 5'b00010, // 触发系统复位 S4 = 5'b00110, // 复位保持 S5 = 5'b00111, // 复位释放 S6 = 5'b00101, // 块锁定检测 S7 = 5'b00100, // 全通道块锁定检查 S8 = 5'b01100, // 通道同步检测 S9 = 5'b01101, // 全通道同步检查 S10 = 5'b01111, // 对齐状态检查 S11 = 5'b01110, // 稳定性等待 S12 = 5'b01010, // 状态监控阶段 S13 = 5'b01011, // 数据传输阶段 S14 = 5'b01001, // 测试完成检查 S15 = 5'b01000, // 最终状态 S16 = 5'b11000, // 复位恢复延时 S17 = 5'b11001; // 主等待周期 // 内部信号 reg [4:0] state ; // 当前状态寄存器 reg [31:0] common_timer; // 通用定时器 reg rx_packet_count_mismatch; // 数据包计数不匹配标志 reg rx_byte_count_mismatch; // 字节数不匹配标志 reg rx_non_zero_error_count; // 接收错误标志 reg tx_zero_sent; // 未发送数据标志 // 跨时钟域同步信号 wire send_continuous_pkts_sync; xxv_ethernet_0_user_cdc_sync i_xxv_ethernet_0_core_send_continuous_pkts_syncer ( .clk(dclk), // 目标时钟域 .signal_in(send_continuous_pkts), // 原始信号 .signal_out(send_continuous_pkts_sync) // 同步后信号 ); // 状态机逻辑 always @( posedge dclk ) begin if ( fsm_reset ) begin // 复位初始化 common_timer <= 0; state <= S0; sys_reset <= 1'b0; pktgen_enable <= 1'b0; completion_status <= NO_START; rx_packet_count_mismatch <= 0; rx_byte_count_mismatch <= 0; rx_non_zero_error_count <= 0; tx_zero_sent <= 0; end else begin // 主状态机逻辑 common_timer <= |common_timer ? common_timer - 1 : common_timer; rx_non_zero_error_count <= rx_data_errors; rx_packet_count_mismatch <= 0; rx_byte_count_mismatch <= 0; tx_zero_sent <= 0; // 检查所有生成器通道的数据一致性 for ( integer i = 0; i < GENERATOR_COUNT; i=i+1 ) begin if ( tx_total_bytes[(64 * i)+:64] != rx_total_bytes[(64 * i)+:64] ) rx_byte_count_mismatch <= 1'b1; if ( tx_sent_count[(48 * i)+:48] != rx_packet_count[(48 * i)+:48] ) rx_packet_count_mismatch <= 1'b1; if ( ~|tx_sent_count[(48 * i)+:48] ) tx_zero_sent <= 1'b1; end // 状态转移逻辑 case ( state ) // S0: 等待启动许可 S0: state <= ok_to_start ? S1 : S0; // S1: 启动延时配置 S1: begin `ifdef SIM_SPEED_UP common_timer <= cvt_us(32'd100); // 仿真模式100us延时 `else common_timer <= cvt_us(32'd10_000); // 硬件模式10ms延时 `endif completion_status <= TEST_START; state <= S2; end // S2: 延时等待 S2: state <= (|common_timer) ? S2 : S3; // S3: 触发系统复位 S3: begin common_timer <= 3; sys_reset <= 1'b1; state <= S4; end // S4: 保持复位状态 S4: state <= (|common_timer) ? S4 : S5; // S5: 释放复位 S5: begin common_timer <= cvt_us(5); // 5us复位恢复时间 sys_reset <= 1'b0; state <= S16; end // S16: 复位恢复延时 S16: state <= (|common_timer) ? S16 : S17; // S17: 主等待周期配置 S17: begin common_timer <= cvt_us(STARTUP_TIME); // 主等待周期 state <= S6; end // S6: 检查块锁定状态 S6: if(|common_timer) state <= |stat_rx_block_lock ? S7 : S6; else begin state <= S15; completion_status <= NO_BLOCK_LOCK; end // S7: 检查全通道块锁定 S7: if(|common_timer) state <= &stat_rx_block_lock ? S8 : S7; else begin state <= S15; completion_status <= PARTIAL_BLOCK_LOCK; end // S8: 检查通道同步状态 S8: if(|common_timer) begin if( ~&stat_rx_block_lock ) begin state <= S15; completion_status <= INCONSISTENT_BLOCK_LOCK; end else state <= |stat_rx_synced ? S9 : S8; end else begin state <= S15; completion_status <= NO_LANE_SYNC; end // S9: 检查全通道同步 S9: if(|common_timer) begin if( ~&stat_rx_block_lock ) begin state <= S15; completion_status <= INCONSISTENT_BLOCK_LOCK; end else state <= &stat_rx_synced ? S10 : S9; end else begin state <= S15; completion_status <= PARTIAL_LANE_SYNC; end // S10: 检查对齐和状态 S10: if(|common_timer) begin if( ~&stat_rx_block_lock ) begin state <= S15; completion_status <= INCONSISTENT_BLOCK_LOCK; end else if( ~&stat_rx_synced ) begin state <= S15; completion_status <= INCONSISTENT_LANE_SYNC; end else state <= (stat_rx_aligned && stat_rx_status) ? S11 : S10; end else begin state <= S15; completion_status <= NO_ALIGN_OR_STATUS; end // S11: 稳定性等待配置 S11: begin state <= S12; `ifdef SIM_SPEED_UP common_timer <= cvt_us(32'd50); // 仿真模式50us `else common_timer <= cvt_us(32'd1_000); // 硬件模式1ms `endif end // S12: 状态监控阶段 S12: if(|common_timer) begin if( ~&stat_rx_block_lock || ~&stat_rx_synced || ~stat_rx_aligned || ~stat_rx_status ) begin state <= S15; completion_status <= LOSS_OF_STATUS; end end else begin state <= S13; pktgen_enable <= 1'b1; // 启动数据包生成 `ifdef SIM_SPEED_UP common_timer <= cvt_us(32'd200); `else common_timer <= cvt_us(32'd10_000); `endif end // S13: 数据传输阶段 S13: if(|common_timer) begin if( ~&stat_rx_block_lock || ~&stat_rx_synced || ~stat_rx_aligned || ~stat_rx_status ) begin state <= S15; completion_status <= LOSS_OF_STATUS; end if(send_continuous_pkts_sync) begin `ifdef SIM_SPEED_UP common_timer <= cvt_us(32'd50); `else common_timer <= cvt_us(32'd1_000); `endif end end else state <= S14; // S14: 测试完成检查 S14: begin state <= S15; completion_status <= SUCCESSFUL_COMPLETION; if(tx_timeout || ~tx_done) completion_status <= TX_TIMED_OUT; else if(rx_packet_count_mismatch) completion_status <= SENT_COUNT_MISMATCH; else if(rx_byte_count_mismatch) completion_status <= BYTE_COUNT_MISMATCH; else if(rx_errors) completion_status <= LBUS_PROTOCOL; else if(rx_non_zero_error_count) completion_status <= BIT_ERRORS_IN_DATA; else if(tx_zero_sent) completion_status <= NO_DATA_SENT; end // S15: 最终状态 S15: state <= S15; endcase end end // 微秒转时钟周期函数 function [31:0] cvt_us( input [31:0] d ); // 假设时钟频率为156.25MHz(周期6.4ns) // 计算公式:d(us) * 156.25MHz = d * 156.25 ≈ (d * 300)/4 cvt_us = ( ( d * 300 ) + 3 ) / 4 ; endfunction endmodule
第一个方法是直接修改状态机,把生成代码和接收代码的部分删除,改成自己的代码。
我倾向于:第二个方法是将本模块修改成【复位+初始化】功能的模块,AXI4 Stream接口的数据暴露给其他程序进行处理。
原模块
xxv_ethernet_0_pkt_gen_mon包含:AXI4 Lite接口(配置寄存器)
RX/TX LBUS数据通路(
rx_axis_*和tx_axis_*信号)状态机控制初始化流程(
stat_rx_block_lock同步、超时检测等)数据包生成器(
xxv_ethernet_0_axis_traffic_gen_mon)CDC同步逻辑(跨时钟域信号处理)
关键逻辑依赖
初始化流程依赖
stat_rx_block_lock信号同步AXI4 Lite接口通过
xxv_ethernet_0_axi4_lite_user_if实现寄存器访问数据通路逻辑通过
xxv_ethernet_0_axis_traffic_gen_mon驱动TX/RX信号
最后AXI配置模块的内容如下:
`timescale 1fs/1fs
(* DowngradeIPIdentifiedWarnings="yes" *)
module xxv_ethernet_0_axi4_lite_user_if
(
// 输入信号
input wire rx_gt_locked, // GT收发器锁定状态
input wire rx_gt_locked_led, // GT锁定LED指示
input wire stat_rx_aligned, // RX对齐状态
input [4:0] completion_status, // 完成状态标志
// 输出控制信号
output reg restart, // 重启信号
output reg stat_reg_compare, // 统计寄存器比较结果
// AXI4-Lite时钟与复位
input s_axi_aclk, // AXI时钟
input s_axi_sreset, // AXI复位
input s_axi_pm_tick, // PM时钟节拍
// AXI写地址通道
output [31:0] s_axi_awaddr,
output s_axi_awvalid,
input s_axi_awready,
// AXI写数据通道
output [31:0] s_axi_wdata,
output [3:0] s_axi_wstrb,
output s_axi_wvalid,
input s_axi_wready,
// AXI写响应通道
input [1:0] s_axi_bresp,
input s_axi_bvalid,
output s_axi_bready,
// AXI读地址通道
output [31:0] s_axi_araddr,
output s_axi_arvalid,
input s_axi_arready,
// AXI读数据通道
input [31:0] s_axi_rdata,
input [1:0] s_axi_rresp,
input s_axi_rvalid,
output s_axi_rready
);
// 状态定义
parameter STATE_AXI_IDLE = 0; // 空闲状态
parameter STATE_GT_LOCKED = 1; // GT锁定状态
parameter STATE_AXI_VERSION_READ = 2; // 版本寄存器读取
parameter STATE_WAIT_RX_ALIGNED = 3; // 等待RX对齐
parameter STATE_AXI_WR = 4; // AXI写操作
parameter STATE_WAIT_SANITY_DONE = 5; // 等待自检完成
parameter STATE_AXI_RD_WR = 6; // AXI读写操作
parameter STATE_READ_STATS = 7; // 统计寄存器读取
parameter STATE_READ_DONE = 8; // 读取完成
parameter STATE_TEST_DONE = 9; // 测试完成
parameter STATE_INVALID_AXI_RD_WR = 10; // 非法AXI操作
parameter STATE_GT_RESET_ALL = 11; // 全局GT复位
// 寄存器地址映射
parameter ADDR_GT_RESET_REG = 32'h00000000; // GT复位寄存器
parameter ADDR_RESET_REG = 32'h00000004; // 全局复位寄存器
parameter ADDR_MODE_REG = 32'h00000008; // 模式配置寄存器
parameter ADDR_CONFIG_TX_REG1 = 32'h0000000C; // TX配置寄存器1
parameter ADDR_CONFIG_RX_REG1 = 32'h00000014; // RX配置寄存器1
parameter ADDR_CORE_VERSION_REG = 32'h00000024; // 核心版本寄存器
parameter ADDR_TICK_REG = 32'h00000020; // PM节拍寄存器
// TX统计寄存器地址
parameter ADDR_STAT_TX_TOTAL_PACKETS_LSB = 32'h00000700;
parameter ADDR_STAT_TX_TOTAL_PACKETS_MSB = 32'h00000704;
parameter ADDR_STAT_TX_TOTAL_GOOD_PACKETS_LSB = 32'h00000708;
parameter ADDR_STAT_TX_TOTAL_GOOD_PACKETS_MSB = 32'h0000070C;
parameter ADDR_STAT_TX_TOTAL_BYTES_LSB = 32'h00000710;
parameter ADDR_STAT_TX_TOTAL_BYTES_MSB = 32'h00000714;
parameter ADDR_STAT_TX_TOTAL_GOOD_BYTES_LSB = 32'h00000718;
parameter ADDR_STAT_TX_TOTAL_GOOD_BYTES_MSB = 32'h0000071C;
// RX统计寄存器地址
parameter ADDR_STAT_RX_TOTAL_PACKETS_LSB = 32'h00000808;
parameter ADDR_STAT_RX_TOTAL_PACKETS_MSB = 32'h0000080C;
parameter ADDR_STAT_RX_TOTAL_GOOD_PACKETS_LSB = 32'h00000810;
parameter ADDR_STAT_RX_TOTAL_GOOD_PACKETS_MSB = 32'h00000814;
parameter ADDR_STAT_RX_TOTAL_BYTES_LSB = 32'h00000818;
parameter ADDR_STAT_RX_TOTAL_BYTES_MSB = 32'h0000081C;
parameter ADDR_STAT_RX_TOTAL_GOOD_BYTES_LSB = 32'h00000820;
parameter ADDR_STAT_RX_TOTAL_GOOD_BYTES_MSB = 32'h00000824;
// 状态寄存器
reg [3:0] axi_user_prestate; // 当前状态
reg [31:0] axi_wr_data; // AXI写数据
reg [31:0] axi_read_data; // AXI读数据
wire [31:0] axi_rd_data; // 读数据总线
reg [31:0] axi_wr_addr, axi_rd_addr; // 读写地址
reg [3:0] axi_wr_strobe; // 写选通信号
reg axi_wr_data_valid; // 写数据有效
reg axi_wr_addr_valid; // 写地址有效
reg axi_rd_addr_valid; // 读地址有效
reg axi_rd_req; // 读请求
reg axi_wr_req; // 写请求
wire axi_wr_ack; // 写响应
wire axi_rd_ack; // 读响应
wire axi_wr_err; // 写错误
wire axi_rd_err; // 读错误
reg [7:0] rd_wr_cntr; // 读写计数器
// 统计计数器
reg [47:0] tx_total_pkt; // TX总包数
reg [47:0] tx_total_bytes; // TX总字节数
reg [47:0] tx_total_good_pkts; // TX有效包数
reg [47:0] tx_total_good_bytes; // TX有效字节数
reg [47:0] rx_total_pkt; // RX总包数
reg [47:0] rx_total_bytes; // RX总字节数
reg [47:0] rx_total_good_pkts; // RX有效包数
reg [47:0] rx_total_good_bytes; // RX有效字节数
// 控制信号
reg init_rx_aligned; // RX对齐初始化
reg init_stat_read; // 统计读初始化
reg init_sanity_done; // 自检完成标志
wire stat_rx_aligned_sync; // 同步后的RX对齐信号
wire gt_locked_sync; // 同步后的GT锁定信号
reg reset_all; // 全局复位信号
wire posedge_rx_gt_locked_led; // GT锁定LED上升沿检测
reg rx_gt_locked_led_1d; // GT锁定LED延迟寄存器
// CDC同步模块实例化(用于跨时钟域信号同步)
xxv_ethernet_0_cdc_sync_axi i_xxv_ethernet_0_cdc_sync_rx_gt_locked_led
(
.clk (s_axi_aclk),
.signal_in (rx_gt_locked_led),
.signal_out (rx_gt_locked_led_sync)
);
// GT锁定LED信号同步寄存器
always @(posedge s_axi_aclk) begin
if (s_axi_sreset)
rx_gt_locked_led_1d <= 1'b0;
else
rx_gt_locked_led_1d <= rx_gt_locked_led_sync;
end
// 检测GT锁定LED的上升沿
assign posedge_rx_gt_locked_led = rx_gt_locked_led_sync & ~rx_gt_locked_led_1d;
// 主状态机逻辑
always @(posedge s_axi_aclk) begin
if (s_axi_sreset) begin
// 复位所有寄存器和状态
axi_user_prestate <= STATE_AXI_IDLE;
// ...(其他复位逻辑,此处省略)
end else begin
case (axi_user_prestate)
// 空闲状态:等待GT锁定
STATE_AXI_IDLE: begin
if (gt_locked_sync)
axi_user_prestate <= STATE_GT_RESET_ALL;
else
axi_user_prestate <= STATE_AXI_IDLE;
end
// GT锁定状态:准备读取版本寄存器
STATE_GT_LOCKED: begin
if (!gt_locked_sync)
axi_user_prestate <= STATE_AXI_IDLE;
else
axi_user_prestate <= STATE_AXI_VERSION_READ;
end
// 读取核心版本寄存器
STATE_AXI_VERSION_READ: begin
case (rd_wr_cntr)
0: begin
$display("开始读取核心版本寄存器...");
axi_rd_addr <= ADDR_CORE_VERSION_REG;
axi_rd_addr_valid <= 1'b1;
axi_rd_req <= 1'b1;
end
1: begin
$display("核心版本: %d.%0d", axi_read_data[7:0], axi_read_data[15:8]);
axi_user_prestate <= STATE_AXI_WR;
end
endcase
end
// AXI写操作状态(配置寄存器)
STATE_AXI_WR: begin
case (rd_wr_cntr)
0: begin
// 配置模式寄存器(内部环回模式)
axi_wr_addr <= ADDR_MODE_REG;
axi_wr_data <= 32'hC000_0000;
end
1: begin
// 配置RX控制寄存器
axi_wr_addr <= ADDR_CONFIG_RX_REG1;
axi_wr_data <= 32'h0000_0033;
end
2: begin
// 配置TX控制寄存器
axi_wr_addr <= ADDR_CONFIG_TX_REG1;
axi_wr_data <= 32'h0000_3003;
end
3: begin
// GT复位操作
axi_wr_addr <= ADDR_GT_RESET_REG;
if (!gt_all_reset_once_only)
axi_wr_data <= 32'h0000_0001; // 复位
else
axi_wr_data <= 32'h0000_0000; // 释放复位
end
// ...(其他写操作步骤)
endcase
end
// 读取统计寄存器状态
STATE_READ_STATS: begin
case (rd_wr_cntr)
0: begin
if (pm_tick_r)
axi_rd_addr <= ADDR_STAT_TX_TOTAL_PACKETS_LSB;
else
// 配置PM节拍寄存器
axi_wr_addr <= ADDR_TICK_REG;
end
// 依次读取所有统计寄存器(TX和RX)
1: axi_rd_addr <= ADDR_STAT_TX_TOTAL_PACKETS_LSB;
2: tx_total_pkt[31:0] <= axi_read_data;
// ...(其他统计寄存器读取步骤)
16: rx_total_good_bytes[31:0] <= axi_read_data;
endcase
end
// 读取完成状态:比较统计值
STATE_READ_DONE: begin
$display("统计结果比较...");
if ((tx_total_pkt == rx_total_pkt) &&
(tx_total_good_pkts == rx_total_good_pkts) &&
(tx_total_bytes == rx_total_bytes) &&
(tx_total_good_bytes == rx_total_good_bytes))
stat_reg_compare <= 1'b1;
else
stat_reg_compare <= 1'b0;
axi_user_prestate <= STATE_TEST_DONE;
end
// 全局GT复位状态
STATE_GT_RESET_ALL: begin
if (!gt_all_reset_once_only)
axi_wr_data <= 32'h0000_0001; // 触发复位
else
axi_wr_data <= 32'h0000_0000; // 释放复位
// 等待GT锁定后进入下一状态
if (rx_gt_locked_led_sync)
axi_user_prestate <= STATE_GT_LOCKED;
end
// 错误处理状态
STATE_INVALID_AXI_RD_WR: begin
$display("AXI读写错误,需要系统复位...");
end
// 默认状态处理
default: axi_user_prestate <= STATE_AXI_IDLE;
endcase
end
end
// AXI读写接口实例化
xxv_ethernet_0_axi4_lite_rd_wr_if i_xxv_ethernet_0_axi4_lite_rd_wr_if
(
// 连接AXI总线信号(此处省略具体连接)
);
// CDC同步模块实例化(用于GT锁定和RX对齐信号)
xxv_ethernet_0_cdc_sync_axi i_xxv_ethernet_0_cdc_sync_gt_locked
(
.clk(s_axi_aclk),
.signal_in(rx_gt_locked),
.signal_out(gt_locked_sync)
);
xxv_ethernet_0_cdc_sync_axi i_xxv_ethernet_0_cdc_sync_stat_rx_aligned
(
.clk(s_axi_aclk),
.signal_in(stat_rx_aligned),
.signal_out(stat_rx_aligned_sync)
);
// PM节拍信号直接连接
assign pm_tick_r = s_axi_pm_tick;
endmodule
// AXI4-Lite读写接口模块
module xxv_ethernet_0_axi4_lite_rd_wr_if
(
// AXI时钟与复位
input wire axi_aclk,
input wire axi_sreset,
// 用户侧读写请求
input wire usr_write_req,
input wire usr_read_req,
// AXI写响应通道
input wire [1:0] axi_bresp,
input wire axi_bvalid,
output wire axi_bready,
// AXI读数据通道
input wire [31:0] axi_rdata,
input wire [1:0] axi_rresp,
input wire axi_rvalid,
output wire axi_rready,
// AXI读地址通道
output wire [31:0] axi_araddr,
output wire axi_arvalid,
input wire axi_arready,
// AXI写地址通道
output wire [31:0] axi_awaddr,
output wire axi_awvalid,
input wire axi_awready,
// AXI写数据通道
output wire [31:0] axi_wdata,
output wire [3:0] axi_wstrb,
output wire axi_wvalid,
input wire axi_wready,
// 用户侧读数据返回
output wire [31:0] usr_rdata,
// 用户侧读写响应
output wire usr_wrack,
output wire usr_rdack,
output wire usr_wrerr,
output wire usr_rderr
);
// 状态定义
parameter IDLE_STATE = 0;
parameter WRITE_STATE = 1;
parameter READ_STATE = 2;
parameter ACK_STATE = 3;
// 状态寄存器
reg [2:0] pstate;
// 内部寄存器(用于缓存AXI信号)
reg [31:0] axi_awaddr_r;
reg axi_awvalid_r;
reg [31:0] axi_wdata_r;
reg [3:0] axi_wstrb_r;
reg axi_wvalid_r;
reg [31:0] usr_araddr_r;
reg axi_arvalid_r;
// 读写响应信号
reg usr_wrack_r;
reg usr_rdack_r;
reg usr_wrerr_r;
reg usr_rderr_r;
// 输出信号连接
assign axi_awaddr = axi_awaddr_r;
assign axi_awvalid = axi_awvalid_r;
assign axi_wdata = axi_wdata_r;
assign axi_wstrb = axi_wstrb_r;
assign axi_wvalid = axi_wvalid_r;
assign usr_rdata = axi_rdata;
assign axi_araddr = usr_araddr_r;
assign axi_arvalid = axi_arvalid_r;
assign usr_wrack = usr_wrack_r;
assign usr_rdack = usr_rdack_r;
assign usr_wrerr = usr_wrerr_r;
assign usr_rderr = usr_rderr_r;
// AXI写响应就绪信号生成
always @(posedge axi_aclk) begin
if (axi_sreset)
axi_bready_r <= 1'b0;
else
axi_bready_r <= (~axi_bready_r) & axi_bvalid;
end
// AXI读数据就绪信号生成
always @(posedge axi_aclk) begin
if (axi_sreset)
axi_rready_r <= 1'b0;
else
axi_rready_r <= (~axi_rready_r) & axi_rvalid;
end
// 状态机逻辑
always @(posedge axi_aclk) begin
if (axi_sreset) begin
pstate <= IDLE_STATE;
// 复位所有信号
end else begin
case (pstate)
IDLE_STATE: begin
if (usr_read_req)
pstate <= READ_STATE;
else if (usr_write_req)
pstate <= WRITE_STATE;
end
WRITE_STATE: begin
if (axi_bvalid & axi_bready_r) begin
pstate <= ACK_STATE;
usr_wrack_r <= 1'b1;
usr_wrerr_r <= (axi_bresp == 2'b10); // 检测写错误
end
end
READ_STATE: begin
if (axi_rvalid & axi_rready_r) begin
pstate <= ACK_STATE;
usr_rdack_r <= 1'b1;
usr_rderr_r <= (axi_rresp == 2'b10); // 检测读错误
end
end
ACK_STATE: begin
pstate <= IDLE_STATE;
// 清除响应信号
end
endcase
end
end
endmodule
// 跨时钟域同步模块
module xxv_ethernet_0_cdc_sync_axi (
input clk,
input signal_in,
output wire signal_out
);
reg s_out_d2_cdc_to;
reg s_out_d3;
// 使用两级触发器同步信号
always @(posedge clk) begin
s_out_d2_cdc_to <= signal_in; // 第一级同步
s_out_d3 <= s_out_d2_cdc_to; // 第二级同步
end
assign signal_out = s_out_d3; // 输出同步后的信号
endmodule修改步骤
1、删除xxv_ethernet_0_axis_traffic_gen_mon、xxv_ethernet_0_traf_data_chk、xxv_ethernet_0_traf_chk1、xxv_ethernet_0_buf、xxv_ethernet_0_pkt_len_gen、xxv_ethernet_0_pktprbs_gen、xxv_ethernet_0_example_fsm_axis模块和调用。
2、简化状态机逻辑 目标 :初始化完成后直接进入空闲状态,不再触发数据传输。
// 原状态机(部分) case (state) S0: state <= S1; S1: state <= S2; ... S12: if (|common_timer) begin if (~&stat_rx_block_lock || ~&stat_rx_synced) begin state <= S15; // 错误处理 end end else begin state <= S13; // 原进入数据传输状态 end ... // 修改后(跳过数据传输状态) case (state) S0: state <= S1; S1: state <= S2; ... S12: if (|common_timer) begin if (~&stat_rx_block_lock || ~&stat_rx_synced) begin state <= S15; // 保留错误处理 end end else begin state <= S15; // 直接进入完成状态 completion_status <= SUCCESSFUL_COMPLETION; end ...
3、移除LBUS接口(由其他模块产生数据和接收数据)
//// TX LBUS Signals input wire tx_axis_tready, output wire tx_axis_tvalid, output wire [63:0] tx_axis_tdata, output wire tx_axis_tlast, output wire [7:0] tx_axis_tkeep, output wire tx_axis_tuser, input wire tx_unfout, output wire [55:0] tx_preamblein, //// RX LBUS Signals input wire rx_axis_tvalid, input wire [63:0] rx_axis_tdata, input wire rx_axis_tlast, input wire [7:0] rx_axis_tkeep, input wire rx_axis_tuser, input wire [55:0] rx_preambleout,
总的来说,我们需要关注的就是两件事,第一件事如何进行初始化,第二件事,如何使用AXI Stream实现我们需要的通信功能。
第一件事是要弄清楚该怎么调用xxv_ethernet_0_axi4_lite_user_if,如何产生各自复位逻辑。第二件事网上教程一大堆,就不用我赘述了。
rx_gt_locked信号是从外部输入的,

连接到了固定的~rx_reset上,

即rx_gt_locked输入的相当于是固定的1'b1即可。
rx_gt_locked_led信号来源于xxv_ethernet_0_axis_traffic_gen_mon模块,

其中tx_resetn信号来源于user_tx_reset | restart_tx_rx

user_tx_reset来源于外部输入

restart_tx_rx也来源于外部输入

stat_rx_aligned信号来源于

这个来自IP核,暂时不管
completion_status信号来自xxv_ethernet_0_example_fsm_axis状态机,
if (stat_rx_block_lock_sync) begin completion_status <= 5'h1F; // 成功完成 end else begin completion_status <= 5'h01; // 锁定失败

stat_reg_compare信号没啥用暂时不管,researt信号也不需要引出。
接下来只需要将AXI4 Lite接到IP的配置端口即可。


