当前位置:首页 > FPGA > Versal ACAP > 正文内容

10G/25G Ethernet Subsystem(4.1) IP理解和使用

chanra1n2周前 (03-22)Versal ACAP132

首先新建子系统IP到Block Design:

image.png

image.png

image.png

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

image.png

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

image.png

我们现在开始分析一下工程的原理,
image.png

我们主要需要关注的是如何应用,也就是说,我们需要理解顶层的链接方法,还有产生测试数据并比对的实现原理:

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;

endmodule

xxv_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)验证传输完整性

        数据流流程

        image.png

关键参数 

目的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接口的数据暴露给其他程序进行处理。

  1. 原模块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同步逻辑(跨时钟域信号处理)

  2. 关键逻辑依赖

    • 初始化流程依赖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信号是从外部输入的,

image.png

连接到了固定的~rx_reset上,

image.png

rx_gt_locked输入的相当于是固定的1'b1即可。


rx_gt_locked_led信号来源于xxv_ethernet_0_axis_traffic_gen_mon模块,

image.png

其中tx_resetn信号来源于user_tx_reset | restart_tx_rx

image.png

user_tx_reset来源于外部输入

image.png

restart_tx_rx也来源于外部输入

image.png


stat_rx_aligned信号来源于

image.png

这个来自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; // 锁定失败

image.png


stat_reg_compare信号没啥用暂时不管,researt信号也不需要引出。

接下来只需要将AXI4 Lite接到IP的配置端口即可。

扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:https://world.myfpga.cn/index.php/post/442.html

分享给朋友:

“10G/25G Ethernet Subsystem(4.1) IP理解和使用” 的相关文章

what is network on chip(NOC)?

what is network on chip(NOC)?

上面的一堆主要是说:现在PS、PL、DDR甚至外设和AIE都能通过统一的NOC进行通信。具体有以下这些单元来实现:1. NMU(NoC Master Units)功能 :NMU是数据进入NoC(片上网络)的入口 ,类似高速公路的“入口收费站”。它负责将主设备(如CPU、DMA控制器等)发出的数据请求...

Versal ACAP Primer Handbook

Versal ACAP Primer Handbook

一、核心架构区别1. Versal(ACAP)异构计算架构 :Versal是AMD/Xilinx推出的自适应计算加速平台(ACAP) ,集成多种计算单元:标量处理引擎 (Scalar Engine):包含ARM Cortex-A72应用处理器(APU)和Cortex-R5实时处理器(RPU),支持L...

自定义Versal BSP编译Petalinux

自定义Versal BSP编译Petalinux

首先设计XSA文件略紧接着我们开始编译Petalinux我的系统版本:LSB Version:    core-11.1.0ubuntu4-noarch:security-11.1.0ubuntu4-noarch Distributor ...

(二)自定义Versal BSP编译Petalinux

(二)自定义Versal BSP编译Petalinux

接下来我们配置uboot、内核,弹出uboot页面按两次Esc按键即可退出chanra1n@chanra1n-Standard-PC-i440FX-PIIX-1996:~/vd100$ petalinux-config -c u-boot [INFO] Bi...

自定义Versal BSP创建XSA文件

自定义Versal BSP创建XSA文件

新建工程:紧接着添加CIPS双击,然后根据你的硬件添加外设,例如我添加SPI的存储器、EMMC和SD卡这里图片截图有问题,GEM0需要勾选MDIO。接下来按OK即可,我们现在开始配置NOC按OK后退出,我们配置这个时钟紧接着创建例化模板:Verilog程序(top.v)`timescale ...

基于Versal Adaptive SoC Transceivers Wizard实现Aurora 64/66B通信

基于Versal Adaptive SoC Transceivers Wizard实现Aurora 64/66B通信

Vivado版本:Vivado 2023.2系统版本:Distributor ID: Ubuntu Description: Ubuntu 24.04.1 LTS Release: 24.04 Codename: noble参考文档:pg331-vers...