
从目标边界、开源移植走向时钟、CMAC 与双 DDR 板级地基专栏MRF8 100G RoCEv2 FPGA 工程实践关键词FPGA、100G Ethernet、RoCEv2、开源网络栈、CMAC、双 DDR4、板级移植很多 FPGA 网络项目的第一步是“把示例工程跑起来”但这次的目标从一开始就更明确让一块自研 XCZU47DR 板卡成为协议兼容的 RoCEv2 RC 端点通过 100G DAC 与服务器上的标准 RDMA 网卡通信。服务器不需要专用 FPGA驱动来搬运 payloadFPGA 也不通过 PCIe 伪装成传统网卡。基础工程选用了开源fpga-network-stack。它提供 ARP、IPv4、UDP、TCP 和RoCEv2 等 HLS 模块但“协议模块存在”与“板级系统可用”之间还有很长距离。原工程面向 VC709、VCU118、ADM7V3 等平台而我们的硬件是xczu47dr-fsvg1517-2-i工具版本固定为 Vivado/Vitis HLS 2021.2物理接口也变成了硬 CMAC、四路 GTY、双 PL DDR4 和 Zynq UltraScale PS。最先确定的边界工程早期最重要的工作不是写 RTL而是把职责边界写清楚QSFP28 只使用一个 100G 端口CAUI-4启用 RS-FECRoCEv2 第一阶段只做 Reliable Connection两组 DDR4 都保留每组提供 512-bit、250 MHz AXI UIPS 可以使用但只做启动、初始化、UART 和 AXI-Lite 控制PS 不进入网络 payload 路径FPGA 必须能作为 requester 主动向服务器执行 RDMA WRITE对端是标准 Linux RDMA 软件栈和 mlx5 RNIC而不是另一个定制 FPGA。这个边界决定了系统的基本形态CMAC 后面是 512-bit AXI4-Stream 网络域RoCE transport 直接连接双 DDR DMAPS 只通过寄存器配置 QP、MR、远端地址、ACK 和 timeout。这样即使 A53 停止运行PL 数据面仍应继续传输。100G DAC / RoCEv2 RCAXI-Lite 初始化与遥测不承载 payload服务器标准 RNICCMAC RS-FEC512-bit 网络域250 MHzRoCEv2 RC ICRCDDR4-A下行接收DDR4-B上行与重传A53 / OCM为什么坚持两组 DDR4一组 512-bit、250 MHz DDR UI 的理论带宽已经是 16 GB/s看起来足以覆盖100GbE。但全双工时服务器到 FPGA 的数据需要落入本地内存FPGA 到服务器的主动发送又需要读取源数据和重传数据。如果共用一组 DDR读写仲裁、刷新和突发尾部会直接影响网络实时性。最终我们把 DDR4-A 定位为下行接收 bank把 DDR4-B 定位为上行发送和重传bank。两套 MIG 独立运行只在 250 MHz 网络域通过异步 AXI4-Stream FIFO与 RoCE 数据面交互。这不是单纯增加容量而是在结构上隔离两个方向的带宽。开源设计真正提供了什么开源工程提供了协议知识和大量可复用模块但板级产品化仍需要重新完成自研板约束、时钟、复位、CMAC 和 MIG 集成适合 100G 的 ICRC 实现MR/RKey 保护和双 bank 地址路由AXI-Lite 控制面、PS 裸机初始化与启动流程主动 requester、ACK scoreboard、重传和长期遥测与标准 RNIC 的功能、性能、故障和长时间互操作测试。这次实践最大的体会是移植网络栈不是更换 FPGA而是重新建立一套从线协议、时钟域、内存语义到测试判据都闭环的系统工程。用里程碑代替“大爆炸式集成”时钟/复位/管脚CMAC 链路与 FEC双 DDR BISTARP/ICMP/UDPRoCE WRITE/READ 互操作主动 requester 与重传双向性能和故障恢复1h/8h/24h 长测RFDC 与业务帧接入每个方框都同时检查功能、时序、遥测和可复现性。后续出错时先比较“最后一个已知正常层”而不是把所有问题都归结为协议栈。板级移植先把地基打稳多时钟域、双内存控制器与 100G 物理链路共同构成板级地基100G 网络逻辑很容易吸引全部注意力但自研板移植中最先决定成败的通常是时钟、管脚和复位。协议栈再完整如果 CMAC user clock、MIG UI clock 和PS 控制时钟之间的关系没有定义清楚后面看到的“协议错误”很可能只是跨时钟域或初始化顺序问题。五组关键时钟MRF8 最终设计使用了几类彼此不同的时钟时钟频率用途fpga_mclk_p/n100 MHzPL 初始化参考生成网络时钟CMAC refclk156.25 MHzGTY/CMAC 参考CMAC RX/TX user clock约 322.266 MHzCMAC AXI4-Stream 侧net_clk250 MHzEthernet、RoCE、ICRC、AXI-LiteDDR4-A/B refclk各 125 MHz两套 MIG 输入参考DDR4-A/B UI clock各 250 MHz两个独立 DDR AXI 域CMAC 与网络域之间使用 packet-aware 异步 FIFO网络域与两个 MIG UI 域之间也分别使用异步 AXI4-Stream FIFO。约束中把三个 250 MHz 域声明为异步关系但没有用宽泛 false path 掩盖真实 CDC复位则在每个目标域同步释放。packet CDCasync AXIS/command CDCasync AXIS/command CDC100 MHz PL 参考MMCM/Clock Wizardnet_clk 250 MHz156.25 MHz CMAC refclkCMAC user clock约 322.266 MHzDDR4-A 125 MHzDDR4-A UI 250 MHzDDR4-B 125 MHzDDR4-B UI 250 MHz同一个 MIG IP不等于同一个控制器两组 DDR4 都使用 MT40A512M16GE-083E每组 64 bit。为了减少生成物差异工程复用同一份 MIG IP 定义在顶层实例化两次再分别连接 DDR4-A 和 DDR4-B管脚。两次实例各自拥有 PHY、校准状态、UI clock 和 AXI master 端口因此仍是两套真正独立的内存控制器。板上内存支持更高速度但首版选择 DDR4-2000、4:1 模式使 UI 恰好成为512 bit 250 MHz。这个选择让 DDR、网络和 RoCE 数据宽度一致减少了宽度转换也给 Vivado 2021.2 的时序收敛留出余量。PS 只做控制不碰 payloadPS 参考时钟为 33.333 MHzUART1 使用 MIO28/MIO29串口参数为 115200 8N1。为了后续制作启动镜像还保留了 Dual Parallel x4 QSPI 和 SDIO1。PS DDR 被禁用最小测试程序直接运行在 OCM 中。最初的验证不是读取 RoCE 寄存器而是先在 OCM 中运行一段最小程序并通过UART 打印MRF8 OCM Hello World A53 executes from OCM; UART1MIO28/29 115200 8N1这条信息很关键它把“CPU 没运行”“UART 配错”和“AXI-Lite 访问失败”三类问题分开了。随后在同一个 HPM0/SmartConnect 上放置对照外设再访问 RoCECORE_ID才能判断故障位于 PS 配置、AXI 总线还是 RoCE 从设备。时序收敛不是最后一步完整设计最终达到全局 setup WNS 为正、hold WHS 为正、DRC Error 为 0。一个代表性正式镜像的 WNS/WHS 为0.011 ns/0.010 ns。这个裕量不大但它覆盖了 CMAC、双 MIG、HLS RoCE、ICRC、AXI-Lite 和调试逻辑的完整布局布线结果而不是只看某个 OOC 模块。上电顺序也属于架构板级状态机把参考时钟稳定、MMCM lock、两套 MIG 校准、CMAC RX/TX 对齐和RoCE reset 释放作为依赖而不是依靠固定延时碰运气。PS 初始化程序读取同一组状态位测试脚本在启动 A53 前再次轮询 ready mask避免软件抢在 PL完成初始化前访问寄存器。后来一小时长测暴露的 OCM 初始化竞态正是通过这套分层状态定位并修复的。板级地基完成后问题才真正进入协议层。下一步是解决一个在 100G 下非常难搞的模块RoCEv2 ICRC。