简介:面向FPGA开发者的ZYNQ7035光纤接口万兆网测速完整工程,基于Vivado工具链实现,主控芯片为XC7Z035FFG900-2,支持向XC7Z035系列其他型号移植,可用于高速光纤通信链路调试与性能验证。压缩包共797个文件,约160.78MB,核心内容涵盖Verilog/VHDL源码、XDC引脚约束、DCP网表、Vivado工程与IP配置(XPR/XCI)、BIT比特流、LTX调试探针,以及DO/VDS仿真脚本、TCL命令和RPT报告等,便于直接编译和复现。当前已有476人学习下载。项目代码可顺利编译运行,提供从RTL设计到上板测试的一整套万兆网测速方案,能帮助开发者快速搭建基于ZYNQ的光纤收发平台,理解高速串行收发器配置与回环测速流程,显著降低高速接口开发门槛。
1. 为什么ZYNQ7035做万兆网测速,瓶颈不在MAC而在DMA与缓存对齐
把ZYNQ7035的光纤接口跑上万兆,说难不难:XC7Z035的PL侧有足够的GTX高速收发器和逻辑资源,Vivado里也有现成的10G Ethernet IP核可以直接例化。但真去测速就会发现,光链路UP、链路层状态正常,速率却始终卡在7Gbps甚至更低。做过几块板子之后我的结论是:MAC和PCS层的设计Vivado已经替你包好了,真正决定吞吐的是PS与PL之间的数据搬运——AXI DMA描述符的管理、缓存行对齐、中断合并的频率,这三个点任何一个处理不合适,吞吐就打不满。这篇文章按我实际搭建的顺序来讲:从SFP+光模块接入,到Vivado里搭最小Block Design,再到Linux下用iperf3测速,最后落在几个能把速率从9.0Gbps顶到9.4Gbps的验证和排查技巧。适合手里有ZYNQ7035开发板、正在做网络转发或高速数据采集的FPGA工程师。
2. 从光纤到PS:ZYNQ7035万兆链路的逻辑架构与关键选型
2.1 光纤接口≠MAC:SFP+、PCS/PMA与10G Base-R的关系
很多人在Vivado里搜“光纤”找到IP核,这是个常见误区。光纤接口本身是物理层的SFP+ cage和光模块,对应到Xilinx体系下是GTX高速收发器外接的串行通道;而万兆网要跑的是10G Base-R协议,逻辑上分为PCS(物理编码子层)和MAC(媒体访问控制层)两段。ZYNQ7035的PL侧集成的是GTX收发器,线速率最高12.5Gbps,承载10.3125Gbps的10G Base-R信号绰绰有余,不需要外部PHY芯片,SFP+光模块直连就可以。
从协议分层看,动态链接过程是这么串起来的:GTX完成串并转换和时钟恢复,PCS负责64b/66b编码、加扰以及链路同步状态机的维护,MAC层处理以太网帧的封装、FCS校验和流量控制。在Vivado里用Xilinx官方提供的AXI 10G Ethernet IP核,实际是把MAC和PCS打包给了你,对外暴露两类接口:一侧是串行的GTX引脚接SFP+,另一侧是AXI4-Stream数据接口接到DMA或FIFO。这意味着你不用关心64b/66b编码细节,但必须清楚PCS层有一个“链路同步”状态,link-up要在这里确认。
ZYNQ7035开发板上SFP+通常接在Bank 115或Bank 116等有GTX的Bank上,参考时钟大多用156.25MHz。需要注意参考时钟的来源,是板上晶振还是由PS端可配置时钟输出。这个时钟抖动直接影响PCS层误码率,布局布线时它与GTX的引脚分配要优先满足同一Bank约束,后面在XDC里会体现。
2.2 两条技术路线:PS+Linux方案与PL纯逻辑方案
万兆测速的落地路线,工作量差异很大,得先选清楚。我一般根据测试目的来分:要测“链路能通多快”,选PL纯逻辑方案;要测“系统能转发多快”,选PS+Linux方案。
PS+Linux方案的核心是把AXI 10G Ethernet IP挂在PS的HP(High Performance)口或ACP口上,再用AXI DMA做数据搬运。PS上跑Linux和网络协议栈,应用层用iperf3测试。这条路线贴近真实服务器网卡的使用模型,TCP/IP收包、协议栈处理、socket开销都算进去了,测出来的结果和商用网卡对比有参考性。代价是:IP核配置项多,DMA描述符管理要在驱动层做对,排查链路要跨PL和PS两层。
PL纯逻辑方案不经过PS,在PL内部自己写一个发包模块(比如固定构造UDP帧),通过AXI4-Stream直接喂给10G MAC,收端用计数器或者ILA抓波形统计。这种方式适合验证链路质量或做数据采集板卡,因为避开了OS和驱动的不确定性,能测出纯MAC层的最高线速。但注意它测的不是“万兆网”的端到端性能,光纤对端还得有一台能打满万兆的仪表或服务器。
两条路线的关键参数对比如下:
| 对比项 | PS+Linux路线 | PL纯逻辑路线 |
|---|---|---|
| IP核选择 | AXI 10G Ethernet + AXI DMA | 任意厂商10G MAC + 自研数据产生模块 |
| 数据接口 | AXI4-Stream / AXI4-Lite配置 | 自定制Stream接口 |
| 测速工具 | iperf3、ethtool、ifconfig | ILA抓包、帧计数器 |
| 主要瓶颈 | DMA描述符、中断、CPU调度 | MAC收发FIFO深度、时序收敛 |
| 适用场景 | 网络转发、协议栈测试、服务器板卡 | 线速采集、协议卸载、波形抓取 |
2.3 数据通路设计:AXI DMA的SG模式为何是默认选择
在PS+Linux路线里,数据通路设计成“PS配置+PL搬运”的双通道结构。PS的M_AXI_GP口用来读写IP核的控制寄存器,比如通过AXI4-Lite配置MAC地址、速率、流控等;数据本身走AXI DMA,DMA挂在HP口上,带宽足够,不占用CPU去逐字搬运。
AXI DMA有三种模式:Direct Register模式适合单次传输且数据量小;SG模式适合大块连续传输并支持描述符链表;CDMA专门做内存到内存拷贝,这里的网络场景通常只用SG模式。SG模式的好处是CPU只需在初始化时把描述符链表放到内存里,DMA传输完成后通过中断通知CPU,收包和发包可以在描述符上并行推进,从而把吞吐打开。描述符每一项里包含地址、长度、控制字和下一项指针,驱动要保证这些结构在物理上是连续的或者用IOMMU映射过。
一个常见的坑:AXI DMA的S2MM通道(收方向)要求缓冲区地址至少按缓存行对齐,但Linux协议栈分配的skb缓冲区起始地址是可变偏移的,直接交给DMA写数据可能导致部分缓存行被覆盖而引发一致性问题。正确做法是在设备树里给DMA分配专用的、对齐过的DMA内存池,或者驱动里用dma_alloc_coherent申请一致内存。设备树里大致是这样描述的:
axidma: dma@40400000 { compatible = "xlnx,axi-dma-1.00.a"; reg = <0x40400000 0x10000>; dma-channels = <1>; dma-channel { interrupts = <0 29 4>; xlnx,include-sg; }; }; axiethernet: axiethernet@40c00000 { compatible = "xlnx,axi-ethernet-1.00.a"; reg = <0x40c00000 0x40000>; local-mac-address = [00 0a 35 00 01 22]; xlnx,has-statistics; };这里的xlnx,include-sg一定要保留,它使驱动进入SG模式;如果删掉,DMA只能做单次传输,吞吐会退化到几百Mbps。reg的基地址来自Vivado地址编辑器里PS给IP核分配的地址,每个工程不一样,不要直接抄,要看Address Editor的映射。
3. 在Vivado里把万兆链路搭起来:最小Block Design与关键参数
3.1 Block Design的最小组成:PS、AXI 10G Ethernet、DMA、Clocking Wizard
在Vivado 2023.2里新建Block Design,最小能跑通万兆链路的连接方式我固定用这几组:ZYNQ7 PS、AXI 10G Ethernet、AXI DMA、Clocking Wizard、以及Processor System Reset。PS的HP口通过AXI Interconnect接DMA的S2MM和MM2S,PS的GP口接10G Ethernet的AXI4-Lite配置口和DMA的AXI4-Lite寄存器口。以太网IP的中断和DMA的中断分别接到PS的PL-PS中断端口上,Vivado会自动分配中断ID,但建议手动固定两个不同的中断号,方便Linux侧确认。
Clocking Wizard在这里起两个作用:一是给AXI DMA和10G MAC生成核心时钟,二是给GTX的参考时钟做缓冲。参考时钟的选择有个细节:如果板上SFP+模块的参考时钟是独立晶振,直接约束为GTX专用时钟引脚;如果是由PS MGTREFCLK输出的,则需要在Vivado中配置为使用PS侧时钟资源,这时PS内还要开启对应的时钟输出。务必先看原理图再配置,这一步错了波形能生成但光模块不会亮。
连接完成后,Validate Design会提示必需的连接,比如AXI 10G Ethernet的axi_txd_arstn复位要靠Processor System Reset的输出。这里有个容易漏的:10G MAC的复位必须处于“低有效”状态,和DMA的复位极性一致,否则上板后一侧能起来另一侧永远在复位状态,现象就是link up了但收发计数为零。
3.2 10G Ethernet IP核参数:参考时钟、MAC地址与Flow Control
双击AXI 10G Ethernet IP核,参数页里需要逐项确认。“Physical Interface”选“GT”表示使用GTX收发器,参考时钟频率根据原理图填156.25MHz;“Speed”固定10G;“MAC”选项勾选“Include AXIlite”用来做寄存器配置;“Flow Control”建议先关闭,特别是做测速时不希望pause帧影响吞吐结果。RX和TX的复位阈值保持默认的100us即可。
有一个参数是“Statistics Counters”,建议开启。它会把MAC层的收发帧数、CRC错误、FCS错误统计到一组寄存器里,Linux下可以用ethtool把这些计数器拉出来,对后面判断丢包到底发生在MAC层还是DMA层非常关键。如果嫌寄存器数量太多,也可以只在调试版本的工程里开,量产时再关掉以节省面积。
AXI DMA的参数设置更需要注意:收发两个通道都要选择SG模式,地址位宽跟随AXI互联设置为64位;缓冲区长度寄存器位宽保持默认的26位,最大支持64MB传输,但实际驱动里会用32KB左右的描述符缓冲区,没必要改大。DMA的微DMA功能在ZYNQ7045上验证过有兼容性问题,ZYNQ7035上我干脆关闭,省得Linux驱动适配时多一个变量。
生成比特流之前跑一次综合,资源评估至少要心里有数。我在XC7Z035上实测,AXI 10G Ethernet + AXI DMA + AXI Interconnect的组合大约消耗2.4万个LUT和3.1万个FF,BRAM约15块,占PL资源20%上下。如果看到LUT占用超过40%,多半是AXI Interconnect的数据宽度设置成了256bit导致跨时钟域逻辑膨胀,改成与DMA一致的64bit即可。
3.3 管脚约束与时钟约束:XDC里必写的三行
Vivado综合布线后生成比特流失败,常见原因不是逻辑错误而是约束缺失。最小系统至少要写三组约束:SFP+收发引脚、GT参考时钟引脚、以及SFP+的MOD_ABS和TX_DISABLE控制脚。GT收发引脚通常由Vivado根据IP核配置自动分配,不需要手写,但参考时钟的管脚声明必须写在XDC里。
参考时钟约束示例:
set_property PACKAGE_PIN AH12 [get_ports gt_ref_clk_p] set_property PACKAGE_PIN AH11 [get_ports gt_ref_clk_n] set_property IOSTANDARD LVDS [get_ports {gt_ref_clk_p gt_ref_clk_n}] create_clock -name gt_ref_clk -period 6.4 [get_ports gt_ref_clk_p]第一行指定差分时钟P端引脚,第二行指定N端,第三行设置电平标准为LVDS,第四行创建周期为6.4ns的时钟约束,对应156.25MHz。注意GT参考时钟的约束不要用get_pins去绑定GT内部节点,只约束到顶层端口就够了,Xilinx会自动传递给GT的专用时钟网络。如果板上的参考时钟实际是125MHz,-period要改成8ns,而不是去改IP核里填的156.25MHz,否则时序分析会报大范围的hold violation。
SFP+控制脚的约束里有个容易忽略的:TX_DISABLE这个引脚必须初始化为低电平,否则光模块发送端被强制关闭。有的开发板这个脚被上拉到高,硬件上也没有跳线,那么必须在XDC里加set_property STARTUP_WAIT或者在FSBL里初始化GPIO,不然链路永远无法建立。
4. Linux下用iperf3测速:从能ping通到跑到9.4Gbps
4.1 设备树匹配与驱动加载:先确认irq和dma都映射对
上板后先不急着跑iperf,先用Linux的启动日志确认三个设备都枚举成功。开机后执行dmesg | grep -i xilinx,应该能看到axiethernet、axidma、interrupt-controller三条记录。如果只看到Axi Ethernet但没有DMA,多半是设备树里DMA节点的中断号被PS中断控制器占用;如果两个设备都有但ifconfig看不到网卡接口,重点查AXI地址是否和Vivado的Address Editor一致。
接口起来之后,用ethtool eth0确认速度和双工模式:
ethtool eth0 ethtool -S eth0第一条命令会显示Speed: 10000Mb/s,Duplex: Full;第二条拉出MAC层统计。重点看rx_total_bytes是否随着外部打流在增长,如果链路已link-up但字节计数不动,问题不在MAC,而在DMA收方向:要么描述符没准备好,要么中断没分配对。此时用cat /proc/interrupts看DMA对应的中断号是否在增长,中断号增长而字节数不增长,说明收的是空描述符。
还有一个我踩过的坑:驱动默认会打开RX和TX的coalesce中断合并。中断合并虽然能降低CPU占用,但合并时间太长会把小包堆积起来,导致iperf单流速率上不去。测速之前用ethtool -C eth0 rx-usecs 8 tx-usecs 8把合并时间降到微秒级,吞吐会有明显提升。
4.2 iperf3测速:单流与多流分别能说明什么问题
测速命令按照常规iperf3用法就好。服务端在ZYNQ7035板卡上:
iperf3 -s -p 5201PC端作为发送方:
iperf3 -c 192.168.1.10 -p 5201 -t 30 -u -b 8G这里-UDP测的是纯数传能力,8Gbps的带宽设置是为了留出余量观察丢包。TCP测速时加-P 8开8个并发流,避免单流受TCP窗口和CPU单核限制。记录几个典型数据点:单流UDP如果只能到8.5Gbps,大概率是DMA或PCIe侧的瓶颈;多流TCP如果总和到9.2Gbps以上而单流到不了4Gbps,大概率是ZYNQ7035的PS侧两个A9核跑协议栈已经到极限了,和PL侧的MAC没有关系。
测速过程中同时用top观察CPU占用,会发现irq线程占满一个核。这是预期现象:10G线速的收包中断频率很高,PS只有一个双核A9,协议栈吞吐上限大约在6到9Gbps之间,主要取决于包大小。MTU从1500改到9000(jumbo frame),吞吐通常能涨20%到30%,因为单位包处理开销摊薄了。板卡和对端服务器都要同时改MTU,只改一端会分片,效果反而更差。
4.3 从9.0到9.4:调缓冲区、CPU亲和性、DMA一致性
如果UDP测试已经在9Gbps附近,想再往上挤一点,按顺序做三件事。第一,增大DMA接收环形缓冲区的描述符数量。默认驱动里rxringsize是128,改成512可以在突发流量下减少丢包,但代价是内存占用增加,ZYNQ7035的DDR资源足够,放心改。第二,把处理中断的CPU和iperf进程绑到不同核上。设置echo 2 > /proc/irq/<irq>/smp_affinity后,DPDK或协议栈处理线程占用另一个核,避免两个核争抢同一个缓存行。
第三件事比较隐蔽:AXI DMA的S2MM通道在单次传输结束时会写一个状态字节到描述符里,如果这个描述符所在的内存被CPU缓存了,DMA写入和CPU读取之间需要一次dmac_flush,次数多了会直接降速。解决方法是驱动里用dma_alloc_coherent分配描述符内存,保证它的一致性属性,而不是用kmalloc加手动flush。改完这三点,同样是UDP 30秒测试,速率能从9.0Gbps波动爬到9.3到9.4Gbps,线速上限约9.42Gbps(10G扣除编码前导与IFG的物理极限),再高就该怀疑光模块或光纤质量了。
5. 测速结果验证与异常分析:一跑就断、速率上不去的排查技巧
5.1 用ethtool计数器定位丢包层
测速结果不理想,第一步不是改代码,而是看计数器。执行ethtool -S eth0,只关注四类字段:rx_total_bytes和tx_total_bytes看宏观通量,rx_crc_errors判断物理层误码,rx_fifo_errors判断DMA收FIFO是否溢出,rx_errors是MAC层收包错误汇总。如果CRC错误很多,说明光模块或光纤链路易出问题,GTX方向的信号完整性不达标,优先换一根短一点的光纤试试;如果CRC很少但rx_fifo_errors持续增长,问题就在DMA来不及搬数据,检查DMA中断和描述符在设备树里是否绑定正确。
5.2 用环回拆解问题:把PL层和PS层分开验证
ZYNQ7035里有一个更快的拆解手段:把AXI 10G Ethernet的TX和RX数据通路内部环回打开。IP核的寄存器里有一项loopback模式,设为“MAC local loopback”之后,数据从DMA发出就直接回到接收端,不经过SFP+光口和物理光纤。此时用iperf打到本机ZYNQ7035的IP,如果速率也能到9Gbps,说明DMA和MAC都是好的,排除发问题到最后的光模块和光纤;如果环回都跑不满,就老老实实回到第4章的调优顺序去检查DMA,不要折腾对端光纤链路。
5.3 一个容易忽略的细节:SFP+的link-up时间与FEC阈值
最后提一个现象:跑速过程中偶发链路断开又立即自动恢复,表现为iperf出现几秒的gap或重传,但ethtool eth0看到的link一直是up。这通常是PCS层发生误码触发了链路重同步,而MAC层中断没有上报。对策是检查SFP+模块是否支持10G Base-R自协商,ZYNQ7035的AXI 10G Ethernet IP默认关闭自动协商,如果对端光模块强制开启自协商,两边就会反复切换。建议两端都设置强制10Gfull,并在IP核内关闭autoneg,再看连续12小时长时间压测的rx_crc_errors,确认FEC没有隐性问题。
本文还有配套的精品资源,点击获取