
VCU128这块板子在我手头放了大半年才真正轮到它上桌。VU3P的资源非常充裕板载PCIe Gen4和高速光口天生就是做100G以太网数据通路的好料子。这次任务是把100G Ethernet Subsystem IP核跑起来用QSFP28光模块和交换机或者另一块板打通链路再通过XDMA把收到的数据搬回主机。这个过程里我踩的坑比预想的多但也都很有代表性——GTY参考时钟怎么配、QSFP28的LPMode和ResetL该拉高还是拉低、回环测试怎么一步步做这些经验值得单独写一篇。文章按我实际调试的顺序来重点讲IP核参数背后的逻辑和上板时怎么定位问题适合正在用VCU128、或者准备在UltraScale上做100G的同学参考。1. 上板之前的方案设计先把数据通路和IP清单列清楚1.1 为什么选VCU128跑100GVCU128用的是Virtex UltraScale VU3P逻辑单元和DSP数量不是旗舰级别但这块板真正值钱的地方在于高速收发器和PCIe资源配比非常均衡。100G以太网链路是4路25.78125Gbps对GTY收发器通道数量要求很直接VU3P的GTY足够用而且内部BlockRAM和UltraRAM容量能支撑较大规模的帧缓存数据通路设计起来不用太抠门。相比以前在Kintex上调1G/10G100G带来的是一种完全不同的处理思路。线速率上去之后CPU不能再逐包干预必须让DMA和描述符机制扛大头。VCU128板载PCIe Gen4 x16接口理论带宽能够覆盖100G线速这是我选它而不是随便拿块带光口的开发板的主要原因。另外板卡对QSFP28的供电和散热设计比较完善长时间跑压力测试不容易因为电源纹波导致误码这点在100G速率下非常关键。1.2 整体数据通路从光模块到主机需要经过哪些环节这条链路实际可以分成三层物理层负责收发链路层负责MAC/PCS传输层是PCIe DMA。光模块把光信号转成4对GTY差分电气信号经过100G Ethernet Subsystem IP核完成PCS编解码和MAC处理输出AXI4-Stream总线接着接异步FIFO做跨时钟域缓冲再进XDMA映射成PCIe DMA描述符最后写进主机内存。逻辑链路大概是QSFP28光模块 → GTY收发器 → 100G MAC/PCS → AXI4-Stream → 异步FIFO → XDMA → PCIe Gen4 → 主机内存。这里最容易低估的是缓存、索引和重组的工作量。100G线速下一个64字节的最小以太网帧只有约6.7ns的处理窗口这种包如果让CPU逐包处理CPU早就挂了。所以我在设计中采用了“缓存—索引—重组”的思路每个方向维护一个描述符池收到的整帧以4KB页为单位写进DDR更新描述符里的长度和状态主机侧再通过描述符索引把完整的包取走。说得直白一点硬件只负责把数据块放进指定内存并通知软件拆包组包的事交给驱动层。这个架构决定了后续IP核选型和时钟规划的方向。1.3 IP核清单与分工下面是我在这个项目里实际用到的Vivado IP核清单它们并不是独立存在的很多坑就是IP之间的时序配合没做好引发的。IP核用途关键点100G Ethernet SubsystemMACPCS/PMA一体化以太网链路线速率、FEC、回环、统计寄存器Clocking Wizard生成用户时钟与复位同步GT参考时钟与用户时钟必须分离XDMAPCIe Gen4 DMA数据搬运AXI4-Stream和AXI4-Lite两套接口AXI4-Stream Data FIFO跨时钟域缓冲与速率平滑写满保护、异步时钟、包长匹配ILA片上逻辑分析采样深度、触发条件、信号数量VIO在线读写控制寄存器快速拉引脚、复位模块、检查状态这套组合是Xilinx高速数据通路的常见用法但并不意味着自动就能工作。最关键的是理解它们之间的依赖关系尤其是时钟和复位后面我会单独展开。2. 100G以太网IP核配置参数背后是行为和代价2.1 MAC/PCS/PMA一体还是分拆配置界面里怎么选Xilinx的100G Ethernet Subsystem IP核有三种常见形态单独的100G MAC、MACPCS/PMA一体、单独的PCS/PMA。如果目标是对接标准以太网设备比如交换机的100G口我建议直接用MACPCS/PMA一体化配置省去自己拼外部PCS的麻烦。如果只是想在FPGA之间做私有高速互联不在乎协议兼容性用PCS/PMA或者干脆用Aurora会更简单。这个选择要提前想清楚因为后续调试方式完全不同。配置界面里第二个容易迷惑的是FEC选项。如果对端交换机开启了RS-FEC本地也必须配置成对应模式两边不一致的话光口Link状态看着正常但上层帧校验会疯狂报错。FEC模式有CL108和CL127两种具体用哪个取决于对端设备支持的协商结果。我的建议是先用没有FEC的模式做通链路稳定之后再逐步加上FEC验证误码率提升效果这样能减少同时排查多个变量的压力。接口位宽和时钟也是配置的必选项。512-bit用户接口在100G速率下的时钟大概是200 MHz量级这个值IP核会自动计算生成工程后会通过约束文件告诉你应该跑多少。不要手动改接口位宽去“优化”时序一旦改了IP内部的PCS和MAC带宽匹配关系就可能出问题后面查起来非常难受。2.2 时钟方案是第一步Clock Wizard不能随手配100G以太网对时钟的要求比10G苛刻得多。GTY收发器的参考时钟必须来自专用的MGTREFCLK引脚不能从普通逻辑时钟转过来。我第一次做的时候就犯了想当然的错误直接用Clocking Wizard生成一个频率给GTY做参考结果QPLL一直失锁。后来查原理图确认VCU128板上有专门给QSFP28光口用的可编程时钟芯片默认输出频率和IP核要求的GT参考时钟频率匹配把源切到专用引脚之后PLL很快就锁上了。用户侧时钟则是另一回事。100G Ethernet Subsystem IP核的AXI4-Stream接口时钟通常由内部逻辑供给这个时钟可以用Clocking Wizard生成但必须和GT参考时钟保持独立。很多人以为反正都是同一个晶振出来的共用一下没问题实际上一旦数据通路的读侧和写侧出现频率抖动异步FIFO就会周期性出现水位异常表现是偶尔丢帧或者带宽掉一半。时钟方案上偷懒后面一定会用更痛苦的方式还回来。2.3 接口模式选错也是经典坑调过SGMII IP核的人都知道当IP核和外部PHY芯片配合使用时FPGA侧必须把SGMII配置成MAC模式否则两侧都以为自己是PHY协商永远不会成功。100G Ethernet Subsystem虽然把MAC和PCS/PMA都集成了不像SGMII那样有明显的MAC/PHY角色二选一但它在对外对接标准以太网设备时本质上还是扮演MAC侧角色这个定位不能搞混。有同学问我为什么不直接用Aurora 8B/10B或者64B/66B做互联省去一堆以太网协议的开销。Aurora确实适合板间私有互联配置简单、时延低但它和标准以太网不互通。如果另一端接的是交换机或者服务器网卡就必须用标准的100G以太网IP核。简单说私有场景用Aurora公共场景用Ethernet Subsystem别想着用一个IP吃遍所有场景。3. QSFP28光模块的管理和回环调试3.1 先把模块管理引脚和I2C读写摸清楚QSFP28模块不是插上就能用的。SFF-8636规范里的几个控制引脚上电状态非常关键。我在第一次上电时发现模块完全没有反应用万用表量了LPMode引脚发现默认被拉高了模块一直处于低功耗模式发送和接收路径全部不工作。解决办法很简单把这个引脚拉低让光模块进入正常工作模式。另外ResetL引脚是低有效复位正常工作时必须保持高电平。模块管理信息通过I2C接口读取器件地址是0x50。最开始我建议先用VIO或者简单的I2C控制器读几个关键寄存器确认FPGA能够和模块正常通信。以bus 2为例读Identifier寄存器的命令大致是这样# 选中低页地址0x00 i2cset -y 2 0x50 0x00 0x00 # 读取Identifier寄存器QSFP28模块应该返回0x0D i2cget -y 2 0x50 0x00如果系统里不方便用i2c-tools就通过VIO把I2C总线的SCL和SDA拉起来手动模拟一个读操作逻辑完全一样。Identifier返回0x0D说明识别到了QSFP28模块接下来可以继续看中断状态寄存器、光模块温度和电压等诊断信息。很多时候Link不上并不是FPGA逻辑问题而是模块自己报错了提前读状态寄存器能节省大量时间。3.2 调试次序建议内部回环、光纤回环、再到对端把所有模块都接好之后不要急着连对端设备。我强烈建议按照“内部回环 → 外部光纤回环 → 对端联调”的顺序推进。内部回环是指在100G Ethernet Subsystem IP核的PCS/PMA层使能loopback数据从FPGA内部发出去马上收回来完全不经过光模块这一步能验证MAC和PCS的逻辑是否正常。如果内部回环都收不到数据问题一定在FPGA内部逻辑而不是光模块或者线缆。内部回环通过之后再上光模块做外部回环。100G QSFP28常见的光模块有MPO接口和LC接口需要根据模块类型准备对应的loopback线。MPO模块用MPO环回线LC模块就用一根短跳线把收发路径串起来。外部回环通了的另一个隐藏好处是能验证光模块的收发状态如果这个环节出现误码多半是信号完整性或者模块问题。最后才接对端的交换机或另一块FPGA板。联调时我会先发固定长度的测试帧用对端统计寄存器确认收到的帧数和发送端一致。如果这一步发现错包再回到统计计数器和ILA逐段排查。3.3 上电时序和复位释放顺序不能乱高速IP核的上电复位顺序看起来是小事踩坑之后才知道有多要命。100G这条链路我的经验是严格按照下面这个顺序先确保GT参考时钟稳定输出释放GTY收发器的复位等待TX和RX的resetdone信号拉高再释放100G Ethernet Subsystem IP核的core复位等待IP核状态寄存器里的PLL和链路状态有效初始化QSFP28光模块拉高ResetL、拉低LPMode最后释放用户侧数据通路的复位AXI4-Stream和DMA才开始跑。这个顺序不用背只需要记住一条原则先时钟再收发器再核心逻辑最后应用数据。任何时候发现Link起不来优先检查当前卡在哪一步而不是反复改RTL逻辑。用ILA挂一下resetdone和link status信号基本一眼就能定位。3.4 热插拔和静电问题开发阶段很多人习惯带电换光模块这种做法在10G时代偶尔还能蒙混过关到100G就很容易出问题。QSFP28笼子的金手指在热插拔瞬间会产生比较大的电流冲击轻则模块寄存器读出来是乱值重则把模块烧掉。我自己就有一次没断电拔模块结果模块I2C彻底挂死重新上电也读不到Identifier最后只能换模块。所以我的建议是凡是涉及插拔光模块和光纤都先把板卡断电至少也要把模块的电源和控制引脚通过逻辑保持在安全状态。逻辑侧可以做一个模块在位检测用ModPrsL信号触发中断模块不在位时自动关断发送路径这样能大大降低误操作带来的损失。4. 上板实测ILA和统计计数器配合排查问题4.1 ILA探针怎么挂更实用Vivado的Integrated Logic AnalyzerILA是上板调试最重要的工具。100G这条链路的信号位宽很大典型的是512-bit数据总线加几十个控制信号不能一股脑全部挂上去否则布线压力和BRAM资源消耗都非常大。我的做法是先把关键状态信号挂上比如GTY的resetdone、core_status、AXI4-Stream的tvalid/tready/tlast以及几个关键的统计计数器采样深度设成16384触发条件用rx_tvalid的上升沿。等基本链路打通之后再根据实际问题增加信号。例如怀疑接收数据出现CRC错误就把rx_stats的几个计数器加到探针里再看丢帧发生在哪个环节。ILA调试的关键不是信号挂得多而是能定位到具体模块大面积盲目抓波形只会让每次编译时间成倍增加效率反而低。4.2 统计寄存器比抓波形更能说明问题100G Ethernet Subsystem IP核内置了发送和接收统计模块分别对应tx_stats和rx_stats。寄存器手册在IP核生成时会附带一份文档里面每个字段都写得比较清楚包括帧计数、字节计数、CRC错误计数、过短帧计数等。上板之后先读这组寄存器能快速判断链路健康状态。真正排查问题时统计计数器比ILA更直观。比如接收方向统计中帧计数在增加但CRC错误也在增加说明物理层或者PCS层有误码需要回头看GTY的接收均衡参数或者光模块状态如果帧计数完全不动大概率是模块没有进入正常工作模式或者RX路径的复位没有释放。计数器定位到方向ILA定位到信号两套工具配合使用非常高效。4.3 一次典型问题复盘模块Link上了但收不到帧这个案例我一个下午才排查完印象非常深。现象是QSFP28模块已经识别成功GTY的Tx/Rx resetdone都拉高了IP核状态也显示Link up可是RX方向统计帧数一直为零。我先用ILA挂上rx_axis_tvalid和rx_axis_tdata抓了一段时间发现tvalid有时会拉高一两个周期但紧接着tlast和tuser出现异常整个包被丢弃了。这个现象说明物理层已经通了问题在MAC层成帧或PCS状态机。后来回头看IP核的复位信号发现RX侧的用户复位一直被外部逻辑拉高虽然GTY resetdone已经完成但MAC侧的rx_core_reset还没释放导致数据到了MAC层之后被内部状态机丢弃。把复位时序调整成GTY resetdone完成之后再释放rx_core_reset马上就能看到RX统计开始计数。这个坑的根源就是我在3.3里说的复位顺序问题其实原理我很清楚但现场接线和逻辑优先级一多就容易疏忽。做100G这类复杂链路复位状态一定要放在最显眼的位置最好做一个状态寄存器把每一步的完成状态都记录下来出问题时先看它。5. 常见问题与避坑速查表5.1 光口Link不上先查这些做100G高速链路Link不上的原因很多我整理了一张速查表涵盖了最常遇到的几种情况。现象可能原因排查动作Link灯不亮、状态寄存器为0QSFP28的LPMode过高检查LPMode引脚正常要拉低模块复位后一直无响应ResetL没拉高或模块热插拔损坏量ResetL电平重新上电拔出重插GTY PLL锁不住GT参考时钟频率不对或来源插错确认MGTREFCLK来自板载可编程时钟芯片模块读到Identifier但TX/RX resetdone不拉高GTY通道没有正确连接到QSFP28的对应引脚核对原理图收发器通道映射Link up但RX统计为0rx_core_reset未释放或成帧异常抓ILA看tvalid/tlast/tuser检查复位顺序频繁CRC错误FEC模式不一致或光模块光功率异常检查FEC开关读模块诊断寄存器大部分Link问题最后都能归结到引脚电平、参考时钟、复位时序这三类。出现问题时不要急着改宏定义或者到处加逻辑先把状态寄存器读一遍通常能直接定位到具体环节。5.2 AXI4-Lite寄存器写入没有反应XDMA的AXI4-Lite接口用于配置用户逻辑和100G IP核寄存器有时候会出现写入完全没有反应的情况。首先确认AXI4-Lite总线的reset是否已经释放XDMA上电后需要等待PCIe link up然后用户逻辑侧复位才会释放。如果复位没释放总线事务会被直接丢弃。其次IP核的寄存器偏移地址必须参考Vivado生成的寄存器手册不同版本、不同选项的IP核寄存器地址可能不同。我第一次就是凭上一个项目的记忆直接写0x0204结果那个地址根本不输入法白白浪费了半天。正确做法是打开IP核生成的regmap文档找到要操作的寄存器核对偏移再检查4字节对齐。非对齐访问会被AXI总线丢弃这是很常见的低级错误。如果很难定位直接在AXI4-Lite从机接口上挂ILA观察awvalid、wvalid和bready的握手情况能立刻看出是总线上没有事务进来还是从机没响应。这个方法屡试不爽。5.3 异步FIFO和跨时钟域导致的数据错乱GT参考时钟、用户时钟、PCIe时钟三个时钟域在100G数据通路里必然交汇跨时钟域是必须跨过的一道坎。我使用AXI4-Stream Data FIFO来做缓冲它支持读写侧独立的时钟配置时要注意FIFO的数据位宽要和上下游接口一致否则会出现字节错位或者带宽不匹配。FIFO深度也不是越大越好。深度过大Latency会明显增加而且几乎占满整个BRAM甚至UltraRAM深度太小在背靠背帧突发时又容易丢帧。按照典型的100G应用每包最大2KB估算写侧时钟和读侧时钟频率相差不超过10%的情况下深度选4096比较均衡既能吸收突发也不会带来太多额外时延。实际项目中可以根据发包模式调整先用大深度跑通再逐步减小优化资源。5.4 缓存、索引和重组方向的经验教训高速数据通路中缓存、索引、重组这三件事做不好带宽再高也是白搭。我在调试XDMA搬到主机的数据时发现收到的包偶尔会出现长度对不上追查下来是描述符里的长度字段更新晚于数据写完的时钟导致主机读取时拿到了旧长度。这个问题的本质是异步场景下状态同步没有做好。我的解决方法是DMA写完一整个数据块之后插入一个内存屏障或者状态同步信号等确认数据落盘完成再更新描述符。听起来很像软件里的缓存一致性其实硬件上也完全一样。另外描述符本身要按自然边界对齐不要用位域跨字节否则驱动侧解析会越来越复杂出问题极难排查。5.5 关于IP核版本和生成工程的坑最后提醒一句不同Vivado版本生成的100G Ethernet Subsystem IP核可能存在差异尤其是寄存器映射和约束文件最好不要在不同版本之间来回迁移工程。我中途把工程从Vivado 2021.2升级到2022.1结果IP核的example design自动更新部分引脚约束和GT参考时钟定义发生了变化调试问题一下多了好几倍。如果项目周期紧就用固定版本不要随便升级。所有IP核都保持在同一个版本下生成和综合避免因为工具链差异引入额外变量。这类问题往往看不出逻辑错误却会让整个上板的节奏被打乱。6. 几句体会我在这次调板过程中最大的体会是100G这类高速接口90%的坑其实都出在时序和初始化上而不是数据通路的逻辑设计上。如果再来一次我一定会把板级时钟、复位顺序和QSFP28模块管理接口这三件事先做完再开IP核的配置。另外多做回环测试从内部回环、外部光纤回环再到对端联调一层层递进遇到问题不要急着改RTL先用ILA和统计计数器把疑点定位到具体模块往往能省下半天时间。最后再分享一个小技巧把GTY resetdone、Link状态和复位步骤记录到Debug寄存器里上板后先读一遍很多问题在动手之前就已经有答案了。