ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ZYNQ7045万兆光口测速实战:GTH配置、Vivado工程与iperf3调优

ZYNQ7045万兆光口测速实战:GTH配置、Vivado工程与iperf3调优 简介面向FPGA开发与嵌入式工程师该压缩包提供基于ZYNQ7045主控XC7Z045FFG900-2的光纤接口万兆网测速完整Vivado工程可通过替换约束等方式便捷移植到XC7Z045系列芯片。资源共1326个文件压缩包约202.11MB逻辑设计以223个.v与48个.vhdl源码为主46个.xdc负责引脚/时钟约束37个.tcl与100个.do脚本支撑自动化仿真、综合与调试27个.xci保存IP核配置35个.dcp为综合后网表配合rpt报告、bit/ltx硬件调试文件和少量PDF说明可覆盖从RTL设计到板级验证的完整链路。目前已有147人学习下载。工程代码可顺利编译运行适合具备ZYNQ基础、希望快速落地光纤万兆测速或做功能扩展的读者目录按源码、约束、脚本、IP核、报告等模块清晰组织省去从零搭建环境的麻烦也能帮助理解GTX/光纤接口在ZYNQ上的实现流程。1. 为什么万兆光口测速要选 ZYNQ7045 而不是纯软件方案ZYNQ7045 是 Xilinx Zynq-7000 系列里少见的「PS 双核 A9 PL 大量逻辑资源 GTH 高速串行收发器」三合一的芯片PL 端的 GTH 可以稳定跑到 10.3125Gbps正好对应 10GBASE-R 的光口线速率。相比用独立 MAC 芯片加 PCIe 网卡的做法ZYNQ7045 的优势在于 PL 里既能放 10G Ethernet MAC也能用 AXI DMA 直接把帧送进 PS 的 DDR测速时整条链路都在自己手里出问题能用 Vivado 的 ILA 抓到信号级别而不是对着黑盒网卡猜。这个标题里真正要解决的三件事是光模块SFP怎么和 FPGA 的 GTH 管脚对接Vivado 里 10G Ethernet Subsystem IP 怎么配置以及数据通路搭好之后用什么工具、什么参数才能把万兆带宽「跑满并且测得准」。适合的人群是已经在用 Vivado 做过一些中小规模逻辑、但对高速串行链路和 Ethernet 协议栈还不太熟的工程师以及需要给实验室或产线搭建 10G 光纤测试环境的人。需要提前说明一点万兆光口测速的难点从来不在「把 IP 拖出来连上线」而在参考时钟的抖动预算、收发 lane 的约束、DMA 描述符的带宽以及测速工具本身的瓶颈。这篇文章按「GTH 与 IP 配置 → Vivado 工程搭建 → Linux 下实测 → 排错与调优」的顺序展开我尽量把参数和命令写到可以直接抄的程度。2. GTH 收发器与 10G Ethernet Subsystem 的选型和配置思路2.1 光口万兆在 ZYNQ7045 上的数据通路从 SFP 光模块到 PS 端 DDR完整的数据通路是光模块 → GTH 收发器 → 10G Ethernet Subsystem IP内含 PCS/PMA 和 MAC→ AXI-Stream 接口 → DMA如 Xilinx DMA/Bridge for PCI Express 或 AXI DMA→ PS DDR或者直接由 PL 内的 AXI-Lite 寄存器控制收发状态。测速时通常有两种做法做法一PL 里只做 MAC 和 DMAPS 跑 Linux用 ethtool 和 iperf3 测吞吐。这是最接近「网卡测速」语义的方案适合验证整机网络性能。做法二PL 里自己写精简 UDP 协议栈绕过 MAC直接组帧、封装、发流PS 只做配置和控制。这个方案吞吐上限高但实现的 Ethernet 帧校验、流控和状态统计都很粗糙测出来的数据只能证明「GTH 能跑」不能证明「这是一块合格的万兆网卡」。做测速项目我更推荐做法一因为 iperf3 这类工具的报文构造和统计逻辑是成熟的你只需要关注 FPGA 侧有没有丢帧和错帧。数据通路的核心是 10G Ethernet Subsystem IP它把 XGMII/RGMII 的 MAC 层和 10GBASE-R 的 PCS/PMA 层打包在了一个 IP 里GTH 的 PMA 配置也由它间接管理。2.2 10G Ethernet Subsystem IP 的关键参数怎么填在 Vivado 的 IP Catalog 里搜索 10G Ethernet Subsystem双击进入配置界面。这里我按最常见的「10GBASE-R 光口线速率 10.3125Gbps」场景说明参数怎么选2.2.1 协议与接口模式Protocol 选择 10GBASE-R这是 SFP 光模块的标准模式线速率 10.3125Gbps。如果你用的是 SFP 铜缆DAC 线协议同样选 10GBASE-R只是不需要光模块的电源和 LOS 信号处理。Management Interface 建议勾选它会在 IP 核外暴露一组 MDIO 接口后续可以通过它读取光模块的寄存器状态比如温度、光功率、LOS 告警。2.2.2 参考时钟与 GTH 的绑定10GBASE-R 需要 156.25MHz 的参考时钟线速率 10.3125Gbps ÷ 66 156.25MHz这个时钟必须从专用的 MGTREFCLK 引脚接入不能从普通全局时钟引脚进去。ZYNQ7045 上通常是把板上的 156.25MHz 差分晶振接到 GTH 的参考时钟引脚对然后在 IP 配置里选择对应的 refclk 索引。很多第一次做的人会在这里出错以为给 IP 一个 10G 或者 800M 的时钟就够了实际上 IP 内部会自己从 refclk 做时钟分频和恢复你只需要保证 refclk 的频率准确、抖动足够低。156.25MHz 的晶体必须是低抖动型号如 SiTime 的 LVDS 差分振荡器如果用普通晶振链路很容易出现 CDR 失锁。2.2.3 统计数据与调试选项Statistics 选项建议全部勾选它会给你一组计数器包括 tx_bytes、rx_bytes、tx_frames、rx_frames、rx_errors、rx_dropped 等。测速时这些计数器是判断丢包和错帧的直接依据。Pause 选项按需开启点对点直连测速时可以不开走交换机时建议开。Support level 选 Include shared logic 还是 Include shared logic in example design 取决于你的工程。如果只有这一个高速 IP选前者如果多个高速 IP 共用一个 GT 参考时钟选后者并手动把共享逻辑提到顶层。2.2.4 地址与 MDIO 从机地址IP 配置的最后一步会要求填写 MDIO 地址默认是 0如果板子上有多个 SFP 或者多个 MAC记得逐个区分否则 Linux 下 miitool 读到的 PHY 地址会混乱。2.3 GTH Bank 的布局和约束对测速上限的影响ZYNQ7045 的 GTH 分布在多个 Quad 里每个 Quad 管理 4 个 lane。选择哪个 Quad 要看原理图上 SFP 的差分对接到了哪个 bank。常见的错误是原理图上 SFP 接在 Quad 114 的 lane 0~3但 IP 配置时选了 Quad 116Vivado 会报布局错误或者勉强布线后时序收敛困难。约束方面除了标准的 XDC 管脚约束还要注意以下两点差分对约束SFP 的 RX 和 TX 是两组差分信号约束时用set_property PACKAGE_PIN指定 P 引脚N 引脚会自动关联但最好显式写出set_property PACKAGE_PIN成对约束防止布线器把 N/P 弄反。参考时钟约束MGTREFCLK 的引脚约束和普通 IO 不同需要加set_property PACKAGE_PIN之外还要在 XDC 里写明set_property LOC GTXE2_CHANNEL或set_property LOC GT_QUAD之类的定位约束否则布线工具可能把 refclk 布到很远的 Quad导致抖动恶化。这里给一个常见的 XDC 片段做参考set_property PACKAGE_PIN AK4 [get_ports sfp_rx_p] set_property PACKAGE_PIN AK3 [get_ports sfp_rx_n] set_property PACKAGE_PIN AK6 [get_ports sfp_tx_p] set_property PACKAGE_PIN AK5 [get_ports sfp_tx_n] set_property PACKAGE_PIN AP6 [get_ports refclk_p] set_property PACKAGE_PIN AP5 [get_ports refclk_n] create_clock -period 6.400 [get_ports refclk_p]关于create_clock的周期156.25MHz 对应周期是 6.4ns这个时钟是差分输入Vivado 会通过 IBUFDS_GTE4 原语进入 GTH不需要额外创建生成时钟。如果你在约束里写了 800MHz那可能是把 GT 的 bit clock 或者 TXOUTCLK 当成 refclk 了这是概念混淆后面在排错章里会展开。3. Vivado 工程与 Block Design 的最小可跑通方案3.1 从 IP 搭建到比特流生成的完整步骤假设你已经有一个 ZYNQ7045 的板卡SFP 的引脚接到了 GTH156.25MHz 参考时钟已经连到 MGTREFCLK。下面是在 Vivado 2023.1更新的版本流程一致里搭建最小测速工程的步骤新建工程器件选 xc7z045ffg900-2 或你板卡对应的具体型号。创建 Block Design添加ZYNQ7 Processing SystemIP按板卡原理图配好 DDR、UART、SD 等 PS 端外设。在 BD 里添加10G Ethernet SubsystemIP按 2.2 节的参数配置线速率选 10.3125Gbps协议选 10GBASE-R。添加AXI DMAIPS2MM 和 MM2S 通道都开启地址位宽选 32 或 64看 PS DDR 的地址映射Buffer Length Register 位宽保持默认 14即最大 16K 字节刚好覆盖 MTU 9000 的 jumbo frame。用Run Block Automation和Run Connection Automation让 Vivado 自动连接 ZYNQ PS 的 M_AXI_GP 或 S_AXI_HP 口到 AXI DMA 的 S_AXI_LITE 和 M_AXI 接口。注意DMA 的数据搬运建议连接到 S_AXI_HP高吞吐接口不要连到 M_AXI_GPGP 口的带宽不够万兆。把 10G Ethernet Subsystem 的 AXI-Stream 接口连到 AXI DMA 的 S_AXI_MM2S 和 M_AXI_S2MM 数据接口。在 BD 中把 tx_axis_tready、rx_axis_tvalid 等握手信号连好或者让 IP 自己处理一般 Run Connection Automation 能搞定。创建 HDL wrapper把 BD 例化到顶层补充 SFP 的差分引脚和 refclk 引脚约束然后综合、布线、生成比特流。3.2 AXI DMA 与 10G MAC 的带宽匹配合法性这里有一个非常关键的参数匹配问题AXI DMA 的 S2MM 通道接收 Ethernet 帧时数据宽度默认是 32 位对应 AXI4-Stream 的 tdata 宽度 32而 10G Ethernet Subsystem 在 10GBASE-R 模式下XGMII 接口的数据宽度是 64 位。Vivado 会在 IP 之间自动插入转换逻辑但你要确认转换逻辑没有落在关键路径上否则时序可能收敛不了。我一般会在 AXI DMA 的配置里把Memory Map Data Width设为 64把Stream Data Width也设为 64这样两边都是 64 位减少不必要的转换。同时注意10G MAC 的 AXI-Stream 接口的 tkeep 信号是 8 位64 位有效字节DMA 的 tkeep 也是 8 位两者对齐。// 顶层连接示意伪代码级 axi_dma_0 mm2s_axis_tdata - mac_0 s_axis_tdata axi_dma_0 mm2s_axis_tkeep - mac_0 s_axis_tkeep axi_dma_0 mm2s_axis_tvalid - mac_0 s_axis_tvalid axi_dma_0 mm2s_axis_tready - mac_0 s_axis_tready axi_dma_0 mm2s_axis_tlast - mac_0 s_axis_tlast mac_0 m_axis_rx_tdata - axi_dma_0 s2mm_axis_tdata mac_0 m_axis_rx_tkeep - axi_dma_0 s2mm_axis_tkeep mac_0 m_axis_rx_tvalid- axi_dma_0 s2mm_axis_tvalid mac_0 m_axis_rx_tready- axi_dma_0 s2mm_axis_tready mac_0 m_axis_rx_tlast - axi_dma_0 s2mm_axis_tlast3.3 约束文件中除了引脚还要锁什么除引脚约束之外万兆工程至少还要额外声明这几类约束否则时序收敛会很痛苦时钟约束refclk 的create_clock是必须的如果 10G IP 输出了 txoutclk 和 rxoutclk 给下游逻辑比如你自研的 FIFO需要create_generated_clock把它们和 GT 的时钟关系写清楚。伪路径约束SFP 的 LOSLoss of Signal信号是慢速告警信号不需要时序收敛加set_false_path是最常见的做法。CDC 约束PS 的 AXI 时钟与 PL 的 GT 时钟天然不同步在 BD 里自动加的 CDC 逻辑一般会被识别但如果你手动写了跨时钟域 FIFO一定要确认异步 FIFO 的 IP 配置里两个时钟都声明了。下面是一个补充约束的示例# SFP LOS 是异步慢信号不需要时序约束 set_false_path -to [get_ports {sfp_los*}] # MDIO 接口时钟为 2.5MHz由 IP 内部产生不做额外约束 set_false_path -from [get_pins -hier -filter {NAME ~ *mdio*}]写完约束后跑综合和布线重点看WNS最差负时序裕量。万兆设计里GTH 的并行数据路径通常能跑到 300MHz 左右WNS 只要为正且不小于 -0.05ns可以先尝试生成比特流后续再微调。3.4 如何判断比特流烧进去之后硬件是否正常烧录完成后不要急着跑 iperf3先做三个检查用 Vivado 的 Hardware Manager 读10G Ethernet Subsystem的状态寄存器确认gt_powergoodGTH 电源稳定、rx_reset_done接收端复位完成、tx_reset_done发送端复位完成都是 1。用 ILA 抓rx_axis_tvalid和rx_axis_tready如果没有插光纤或者对端没发包tvalid 应该是低如果有报文进来而 tvalid 一直为高但 tlast 长期不拉高说明帧长超限或 FCS 错误。用逻辑分析仪或万用表量 SFP 的Tx_Fault引脚正常工作时应该为低如果一直为高说明光模块的供电或 I2C 配置有问题。4. Linux 驱动与万兆测速实操iperf3 与 ethtool 组合4.1 在 ZYNQ7045 上跑起网卡驱动的两种路线ZYNQ7045 的 PS 端跑 PetaLinux 或 Ubuntu网卡驱动有两种选择一是用 Xilinx 官方的xilinx_axidma驱动在老版本内核里叫xilinx_dma二是用现成的axienet驱动配合xilinx_emaclite。对于 10G Ethernet Subsystem官方推荐的是axienet驱动但要注意 10G 版本的 IP 需要指定支持 10GBASE-R 的内核补丁。PetaLinux 2020.2 及以上版本默认包括了这些补丁直接用即可。设备树里需要描述 DMA 和 MAC 的关系一个最小可用的设备树片段如下axi_ethernet_0: axi-etherneta0000000 { compatible xlnx,axi-ethernet-1.00.a; reg 0xa0000000 0x40000; interrupts 0 26 4; local-mac-address [00 0a 35 00 00 00]; xlnx,rxcsum 0x0; xlnx,txcsum 0x0; phy-mode xgmii; phy-handle phy0; axi-dma-channela0005000 { compatible xlnx,axi-dma-1.00.a; reg 0xa0005000 0x200; dma-channel { compatible xlnx,axi-dma-s2mm-channel; interrupts 0 27 4; }; }; axi-dma-channela0005100 { compatible xlnx,axi-dma-1.00.a; reg 0xa0005100 0x200; dma-channel { compatible xlnx,axi-dma-mm2s-channel; interrupts 0 28 4; }; }; };phy-mode xgmii是关键表示 10G MAC 与 PHY实际上 PCS/PMA 集成在 IP 内之间走 XGMII。驱动加载成功后ip link里应该能看到 eth0 或类似命名的接口。4.2 ethtool 查看链路仲裁与协商结果接口起来后先用 ethtool 确认链路状态确实是 10G 全双工ethtool eth0输出里关注两个字段Speed应为 10000Mb/sDuplex应为 Full。如果显示Speed: Unknown!说明 PCS 层没有成功和对端协商原因可能是光模块未识别、LOS 拉高、或者 refclk 抖动太大导致 CDR 失锁。再看一看ethtool -m eth0的输出它通过 MDIO/I2C 读取 SFP 的 EEPROM应该能看到光模块型号和链路诊断信息。4.3 iperf3 双向测速的命令与参数讲究万兆测速最怕瓶颈不在 FPGA 而在工具和协议栈。先用最简单的 TCP 单向测# 服务端ZYNQ7045 上 iperf3 -s -p 5201 # 客户端对端 PC 或另一台 FPGA 板卡 iperf3 -c 192.168.10.2 -t 30 -i 5这里-t 30是测 30 秒-i 5每 5 秒打印一次实时速率。万兆下 30 秒的测试数据量约 37.5GB能较好地覆盖 DMA 描述符回收和缓存一致性开销。如果实测带宽在 6~8Gbps 之间先别怀疑 FPGA先试以下调参# 客户端加大 TCP 窗口并多流并发 iperf3 -c 192.168.10.2 -t 30 -i 5 -w 1M -P 8-w 1M把 socket 缓冲区调到 1MB-P 8起 8 个并发流。万兆链路的 BDP带宽延迟积在局域网内虽然不高但多流能绕开单核软中断处理瓶颈。如果多流后能跑到 9.4Gbps 左右说明 FPGA 硬件通路没问题之前是 CPU/协议栈瓶颈。4.4 UDP 测速与丢包率的判定方法TCP 有重传机制测出来的速率不代表 FPGA 的真实收包能力。用 UDP 打流看 Drops 才是硬指标# 客户端 iperf3 -c 192.168.10.2 -u -b 10G -t 20 -i 5 # 服务端测完看输出中的 lost/total服务端输出会显示Received和Lost两个数值。丢包率小于 0.01% 说明稀缺陷失主要是软件收包慢如果丢包率超过 1%要看是 FPGA 内部丢的还是 Linux 协议栈丢的。区分方法很简单在 PL 里把 MAC IP 的rx_dropped计数器读出来如果它接近 0说明所有报文都进了 DMA丢包发生在内核协议栈优先调整中断合并和 DMA ring buffer 大小。# 查看网卡统计信息重点看 rx_dropped 和 rx_missed_errors ethtool -S eth0在ethtool -S的输出里rx_dropped是由驱动丢弃的帧rx_missed_errors是硬件 FIFO 溢出导致的丢帧。这两个字段如果为 0那丢包只能发生在协议栈之上需要调net.core.rmem_max这类内核参数。5. 测速结果异常时的分层排错路径与关键陷阱5.1 先把问题分层物理层、数据链路层、传输层遇到测速跑不满最忌讳的是直接改代码里的一堆参数乱试。按下面的顺序排查能快速定位问题层级物理层光模块指示灯是否亮、SFP 的 LOS 是否拉低、ethtool eth0能否识别到 10G 全双工。物理层没过链路层和传输层的数据都是空谈。数据链路层MAC IP 的 rx_error_counter 是否为 0。这个计数器统计 CRC 错误、符号错误、帧对齐错误只要它增长说明物理层有误码大概率是 refclk 抖动或者 PCB 走线质量不行。传输层Linux 的软中断占用率是否打到 100%。用top看si的数值如果多核都被软中断打满就要做 RPSReceive Packet Steering或用驱动级多队列支持。5.2 Vivado 生成比特流失败时最先要看的问题标题热词里有一个很常见的检索词——「vivado 生成比特流失败」这里单独说。万兆工程的比特流生成失败九成和 GTH 的时钟资源冲突有关。尤其是当工程里同时存在 PCIe、SATA 等其他高速 IP 时多个 IP 都申请了同一个 Quad 的 refclkVivado 会在布局阶段报出类似ERROR: [Vivado 12-561] No GT_QUAD available的错误。解决办法先说最省事的在10G Ethernet Subsystem里把 Shared logic 改成 Include shared logic in example design然后在顶层手动例化共享逻辑单独给 GT 的 refclk buffer 分配 Quad。手动指定 Quad 的 Tcl 命令如下set_property LOC GTYE4_CHANNEL_X0Y0 [get_cells inst/gt_wrapper/gt0_gt] set_property LOC GTYE4_CHANNEL_X0Y1 [get_cells inst/gt_wrapper/gt1_gt]注意 ZYNQ7045 的 GTH 是 GTXE2_CHANNEL7 系列命名如果设计里同时出现 GTYE4那是 UltraScale 的工程模板抄错了排查时先确认器件型号和 IP 版本匹配。5.3 参考时钟的「800M」迷思与正确设置搜索结果里有「vivado 时钟800m怎么设置」这个热词很多做万兆的人会困惑为什么我自定义的 IP 非要 800MHz 的时钟而官方例子只有 156.25MHz这里做一个澄清156.25MHz 是 10GBASE-R 的参考时钟线速率 10.3125Gbps ÷ 64B/66B 编码率 156.25MHz它供 GTH 的 PMA 使用。800MHz 是你在 Block Design 里给 AXI 总线或者自定义逻辑配的时钟两者没有任何换算关系。如果 Vivado 提示某个 IP 需要 800MHz 时钟通常是该 IP 的 AXI4-Stream 接口被配置成了 256 位宽度而你又给它连了一个只支持 32 位数据的 DMAVivado 会自动插入 AXIS 转换器并提高时钟频率来补偿带宽。这不是问题只是效率损失。更合理的做法是把数据位宽对齐到 64 位时钟回到 156.25MHz吞吐量完全够万兆64bit × 156.25MHz ≈ 10Gbps。5.4 高速差分线的 SI 问题怎么用 Vivado 排查PCB 走线不好的时候GTH 不会直接报错而是表现出偶发的 CRC 错误。Vivado 的 Hardware Manager 里可以看到 GTH 的眼图扫描结果。打开 Hardware Manager 连接到设备右键 GTH 的 transceiver 选择Open Eye Scan观察眼图的张开程度如果眼睛高度低于 100mV 或者宽度低于 0.5UI基本可以断定 PCB 走线损耗超了。SI 问题的软件侧补救手段有限可以尝试在 IP 配置里调整 TX 预加重Pre-emphasis和 RX 均衡RX Equalization的档位# 示例Tcl 命令设置 GTH 的 TX 摆幅和预加重 set_property GT_settings [list \ TX_DRIVE_RATE 2 \ TX_PRE_CURSOR 4 \ TX_POST_CURSOR 8] [get_cells inst/gt_wrapper/gt0_gt]每次调整后重新综合并烧录再用 ethtool 看 rx_error_counter 是否归零。如果调整到最大档位后误码仍然存在那就不是板卡设计阶段能补的只能反馈硬件改版。5.5 测速结果的验收标准与一个值得养成的验证习惯万兆测速做完之后别急着把数据截图发出去。建议固化一个验证流程先把 FPGA 的 TX 发到对端对端用tcpdump -i eth0 -c 100000抓包并统计帧长分布。正常 iperf3 流下的帧长应该是均匀的或集中在 MTU 边界如果抓到大量小帧小于 64 字节说明协议栈在重组或者 GRO 没生效这时的吞吐数字可以忽略。另一个习惯是保留每次调参前的测速日志包括ethtool -S的输出这样你改了一版 RTL 或约束之后才能判断性能变化到底来自哪里而不是凭感觉说「优化有效」。这两个习惯比调出最巅峰的数字更能帮助你在后续项目中快速形成自己的排错经验。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进