10G/25G Ethernet Subsystem(4.1) 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; 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)验证传输完整性
主要功能模块
数据流流程
关键参数
目的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的配置端口即可。