Alveo Ethernet Kernel Connectivity 模块深度解析
一句话概括
本模块展示了如何在 AMD Alveo 数据中心加速卡上,通过 Vitis 流程将包含 GTY 收发器的 RTL Kernel 集成到硬件设计中,实现与外部网络的 10G 以太网数据通路连接。它就像是一座"数字桥梁"——将 FPGA 内部的计算逻辑与物理世界的网络线缆连接起来。
问题空间:为什么需要这个模块?
背景挑战
AMD Alveo 加速卡(如 U200、U250、U280、U50)配备了 QSFP28 网络接口,支持 10GbE/25GbE/40GbE/100GbE 等多种以太网配置。然而,在 Vitis 统一开发流程中使用这些高速收发器面临几个核心挑战:
- 物理层复杂性:GTY 收发器涉及差分时钟、参考时钟、高速串行信号等复杂的模拟电路接口
- 平台依赖性:不同 Alveo 卡片的 GT 位置、时钟频率、引脚分配各不相同
- 工具链集成:需要将底层 RTL 设计与 Vitis 的高级综合流程无缝衔接
- 协议栈抽象:开发者希望专注于业务逻辑,而非以太网 MAC/PCS 的底层细节
设计动机
传统上,使用 Alveo 的网络功能需要直接在 Vivado 中进行底层设计,这违背了 Vitis "软件定义硬件"的理念。本模块的核心价值在于:
证明可以在 Vitis 流程中,以近乎普通 RTL Kernel 的方式使用 GTY 收发器,仅需处理少量的 GT 专用信号连接。
这是一个方法论教程——它本身不提供复杂的业务功能,而是展示集成模式的正确打开方式。
心智模型:如何理解这个系统?
类比:邮局分拣系统
想象一个现代化的邮局分拣中心:
-
ethernet_krnl = 邮局的大门和前台
- 负责与外部世界(公路上的邮车)对接
- 管理进出的信件流(以太网帧)
- 提供控制面板(AXI-Lite 寄存器)供管理员配置
-
data_fifo_krnl = 内部传送带
- 简单地将接收的信件转发出去(loopback 模式)
- 在本示例中只是演示连通性,实际应用中会替换为真正的处理逻辑
-
QSFP28 接口 = 连接外部公路的卡车码头
- GTY 收发器就是这里的装卸设备
- 差分时钟如同码头的同步调度系统
核心抽象层次
┌─────────────────────────────────────────────────────────────┐
│ 用户业务逻辑 (Your Logic) │
│ (替换 data_fifo_krnl) │
├─────────────────────────────────────────────────────────────┤
│ AXI4-Stream 接口 (标准流式接口) │
│ tx_axis / rx_axis (64-bit 数据) │
├─────────────────────────────────────────────────────────────┤
│ ethernet_krnl (网络内核封装层) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ AXI-Stream │◄──►│ xxv_ │◄──►│ GTY │ │
│ │ FIFOs │ │ ethernet │ │ Transceivers│ │
│ └─────────────┘ │ (MAC/PCS) │ └─────────────┘ │
│ └─────────────┘ │
│ ┌─────────────┐ │
│ │ AXI-Lite │ ← 控制寄存器访问 (复位、环回、状态) │
│ │ Control │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Alveo Platform (固定资源) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ GT RefClk │ │ QSFP28 │ │
│ │ (161.132MHz)│ │ Connector │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
架构详解
组件拓扑图
ap_ctrl_hs 执行模型"] end subgraph "Alveo FPGA Fabric" subgraph "ethernet_krnl_axis_x1/x4" CTRL["ethernet_control_s_axi
AXI-Lite 控制接口"] ETH_IP["xxv_ethernet IP
10G MAC/PCS"] TX_FIFO["TX AXI-Stream FIFO"] RX_FIFO["RX AXI-Stream FIFO"] end subgraph "data_fifo_krnl(s)" LOOPBACK["Loopback FIFOs
rx_axis → tx_axis"] end subgraph "Platform Resources" GT["GTY Transceivers
4 lanes"] REFCLK["GT Refclk
161.1328125 MHz"] FREERUN["Free Run Clock"] end end subgraph "External Network" QSFP["QSFP28 Port"] NET["Ethernet Network"] end HOST -->|"s_axi_control
配置寄存器"| CTRL CTRL -->|"scalar[31:0]
控制信号"| ETH_IP ETH_IP <-->|"axi_str_txd/rxd
64-bit stream"| TX_FIFO ETH_IP <-->|"axi_str_txd/rxd
64-bit stream"| RX_FIFO TX_FIFO -->|"tx0_axis"| LOOPBACK LOOPBACK -->|"rx0_axis"| RX_FIFO ETH_IP <-->|"gt_txp/n gt_rxp/n
高速差分信号"| GT GT <-->|"物理连接"| QSFP QSFP <-->|"光纤/铜缆"| NET REFCLK -->|"gt_refclk_p/n
差分时钟"| ETH_IP FREERUN -->|"clk_gt_freerun
自由运行时钟"| ETH_IP style HOST fill:#e1f5ff style ETH_IP fill:#fff4e1 style GT fill:#ffe1e1 style QSFP fill:#f0e1ff
关键组件职责
1. ethernet_krnl_axis_x1.sv / ethernet_krnl_axis_x4.sv
这是以太网内核的 RTL 顶层,有两种变体:
| 特性 | x1 版本 | x4 版本 |
|---|---|---|
| 通道数 | 1 lane | 4 lanes |
| 数据流接口 | rx0_axis, tx0_axis | rx0-3_axis, tx0-3_axis |
| 控制寄存器 | scalar00 | scalar00-03 |
| 适用场景 | 单通道测试 | 多通道聚合 |
核心设计要点:
- 参数化设计:通过
C_NUM_LANES局部参数区分两种变体的大部分共享逻辑 - 时钟域处理:
rx_core_clk由tx_clk_out驱动,确保收发时钟同源 - 跨时钟域同步:使用
xpm_cdc_single/xpm_cdc_array_single将stat_rx_block_lock从以太网时钟域同步到ap_clk域
// 关键 CDC (Clock Domain Crossing) 实例
xpm_cdc_array_single #(
.DEST_SYNC_FF(4), // 4级同步,降低亚稳态概率
.WIDTH(C_NUM_LANES)
) ap_rx_block_lock_sync_i (
.dest_out(ap_stat_rx_block_lock_sync),
.dest_clk(ap_clk),
.src_clk(1'b0), // 源时钟未使用,因为是电平信号
.src_in(stat_rx_block_lock)
);
2. ethernet_control_s_axi_x1.v / ethernet_control_s_axi_x4.v
AXI-Lite 从接口控制器,提供寄存器访问能力:
寄存器映射(x1 版本):
| 地址 | 名称 | 权限 | 描述 |
|---|---|---|---|
| 0x10 | scalar00 | R/W | 控制寄存器,位定义见下表 |
| 0x14 | status0 | RO | bit[0] = rx_block_lock |
scalar00 位域定义:
bit[2:0] : gt_loopback // GT 环回模式
bit[4] : gtwiz_reset_rx_datapath // RX 数据通路复位
bit[5] : gtwiz_reset_tx_datapath // TX 数据通路复位
bit[8] : fifo 单独复位控制
bit[12] : sys_reset // 全局系统复位
设计权衡:
- 使用简单的状态机实现 AXI-Lite 协议,而非完整的 AXI Interconnect
- 省略了 ID、SIZE、BURST 等信号以节省逻辑资源(注释中明确说明)
- x4 版本扩展为 4 组独立的 scalar/status 寄存器,每通道独立控制
3. data_fifo_krnl.sv
简化的数据通路内核,用于演示 loopback:
// 结构:RX_FIFO → 内部连线 → TX_FIFO
axis_data_fifo_0 rx_fifo_0 (...); // 接收外部数据
axis_data_fifo_0 tx_fifo_0 (...); // 发送数据到外部
关键特性:
- 使用
ap_ctrl_none执行模型——无需主机启动,上电即运行 - 两个 FIFO 背靠背连接形成 loopback
- 实际应用中应替换为真正的处理逻辑
4. IP 生成脚本 (gen_ip_x1.tcl, gen_ip_x4.tcl)
xxv_ethernet IP 配置要点:
# 通用配置
CONFIG.LINE_RATE 10 ;# 10Gbps
CONFIG.BASE_R_KR BASE-R ;# 使用 BASE-R 模式
CONFIG.INCLUDE_AXI4_INTERFACE 0 ;# 禁用 AXI4-MM DMA 接口,仅用 Stream
CONFIG.ENABLE_PIPELINE_REG 1 ;# 启用流水线寄存器提升时序
# 板卡特定配置(以 U200 为例)
CONFIG.GT_REF_CLK_FREQ 161.1328125 ;# 精确参考时钟频率
CONFIG.GT_GROUP_SELECT Quad_X1Y12 ;# GT Quad 选择
CONFIG.LANE1_GT_LOC X1Y48 ;# 具体 GT 位置
axis_data_fifo 配置:
CONFIG.IS_ACLK_ASYNC 1 ;# 异步时钟模式
CONFIG.TDATA_NUM_BYTES 8 ;# 64-bit 数据宽度
CONFIG.FIFO_MODE 2 ;# 特定 FIFO 模式
CONFIG.HAS_TKEEP 1 ;# 支持字节使能
CONFIG.HAS_TLAST 1 ;# 支持包边界指示
数据流分析
接收路径 (Network → FPGA)
QSFP28 → GTY (gt_rxp/n) → xxv_ethernet → RX_FIFO → rx_axis → data_fifo_krnl
↓
stat_rx_block_lock → 控制寄存器
- 物理层:光/电信号通过 QSFP28 进入 GTY 收发器
- PCS/MAC 层:
xxv_ethernetIP 完成解码、对齐、CRC 校验 - FIFO 缓冲:
axis_data_fifo吸收时钟域差异和突发流量 - 流式输出:标准的 AXI4-Stream 接口提供给下游逻辑
发送路径 (FPGA → Network)
data_fifo_krnl → tx_axis → TX_FIFO → xxv_ethernet → GTY (gt_txp/n) → QSFP28
- 流式输入:上游逻辑通过 AXI4-Stream 提供数据
- FIFO 缓冲:平滑数据流,处理反压 (backpressure)
- PCS/MAC 层:添加前导码、FCS,编码后发送
- 物理层:GTY 将并行数据转换为高速串行信号
控制路径 (Host → Kernel)
XRT → xclbin → s_axi_control → ethernet_control_s_axi → scalar → xxv_ethernet
→ rx_block_lock (回读)
系统集成:连接配置详解
connectivity_x1.cfg 解析
[connectivity]
# 内核实例化声明
nk=ethernet_krnl_axis_x1:1:eth0 # 类型:数量:实例名
nk=data_fifo_krnl:1:df0
# AXI-Stream 连接:以太网 RX → FIFO RX
stream_connect=eth0.rx0_axis:df0.rx_axis
# AXI-Stream 连接:FIFO TX → 以太网 TX
stream_connect=df0.tx_axis:eth0.tx0_axis
# === GT 专用信号连接(平台相关)===
# Free-running 时钟连接(用于 GT 初始化期间的稳定时钟源)
connect=eth0/clk_gt_freerun:ii_level0_wire/ulp_m_aclk_freerun_ref_00
# GT 参考时钟(来自板载晶振,经平台路由)
connect=io_clk_qsfp_refclka_00:eth0/gt_refclk
# GT 数据端口(连接到物理 QSFP 接口)
connect=eth0/gt_port:io_gt_qsfp_00
connectivity_x4.cfg 差异点
# 4个以太网通道 + 4个 FIFO 实例
nk=ethernet_krnl_axis_x4:1:eth0
nk=data_fifo_krnl:4:df0.df1.df2.df3
# 每通道独立的 stream 连接
stream_connect=eth0.rx0_axis:df0.rx_axis
stream_connect=eth0.rx1_axis:df1.rx_axis
stream_connect=eth0.rx2_axis:df2.rx_axis
stream_connect=eth0.rx3_axis:df3.rx_axis
stream_connect=df0.tx_axis:eth0.tx0_axis
stream_connect=df1.tx_axis:eth0.tx1_axis
stream_connect=df2.tx_axis:eth0.tx2_axis
stream_connect=df3.tx_axis:eth0.tx3_axis
关键设计决策与权衡
1. 为什么选择 RTL Kernel 而非 HLS?
决策:使用 SystemVerilog/Verilog 手写 RTL 而非 C++/OpenCL HLS
理由:
- GTY 接口是高度专用的硬件资源,需要精确的引脚控制和时序约束
xxv_ethernetIP 的集成需要精细的端口映射和参数配置- RTL 提供了对 AXI-Stream 握手信号的完全控制
代价:
- 开发门槛更高,需要硬件设计经验
- 调试复杂度增加(需要理解波形和时序)
2. 为什么使用 ap_ctrl_hs 而非 ap_ctrl_chain?
决策:以太网内核使用 ap_ctrl_hs(单次执行),FIFO 内核使用 ap_ctrl_none
理由:
- 以太网内核需要显式的启动/停止控制来进行链路初始化和复位
- 控制寄存器需要运行时动态修改(如设置环回模式)
- FIFO 是纯数据通路,无需状态机控制
3. 为什么采用双 FIFO 结构?
决策:data_fifo_krnl 中包含两个独立的 axis_data_fifo 实例
理由:
- 物理隔离收发路径,避免 head-of-line blocking
- 允许独立的时钟门控和复位控制
- 符合 AXI-Stream 的单向流语义
4. 平台可移植性策略
决策:通过 Tcl 脚本中的条件分支支持多板卡
if {[string compare -nocase $board "u200"] == 0} {
# U200 特定配置
} elseif {[string compare -nocase $board "u250"] == 0} {
# U250 特定配置
}
权衡:
- 优点:一份源码适配多款 Alveo 卡
- 代价:新增板卡需要修改脚本并验证时序
5. 省略 AXI4 内存映射接口
决策:CONFIG.INCLUDE_AXI4_INTERFACE {0}
理由:
- 本设计专注于纯流式处理(类似 SmartNIC 的数据面)
- 避免了复杂的 DMA 描述符管理
- 数据直接流经 FIFO,不经过 DDR
替代方案:若需要大包缓冲或复杂调度,可启用 AXI4-MM 接口连接 DDR
新贡献者必读:陷阱与注意事项
🔴 关键前提条件
- 许可证要求:需要
xxv_eth_mac_pcs和x_eth_mac两个 IP 许可证 - 物理连接:需要实际的光模块和光纤/网线进行测试
- 平台版本:确保 platform 版本与
connect=语句中的信号名匹配
⚠️ 常见错误
1. GT 时钟连接错误
# 错误:使用了错误的时钟名
connect=eth0/clk_gt_freerun:wrong_clock_name
# 正确:使用 platforminfo 命令查询正确的信号名
# platforminfo -p xilinx_u200_gen3x16_xdma_1_202110_1 -v
2. 参考时钟频率不匹配
不同板卡的 GT 参考时钟频率可能不同:
- U200/U250/U50: 161.1328125 MHz
- U280: 156.25 MHz
使用错误的频率会导致链路无法锁定。
3. GT 位置冲突
每个 GT Quad 有固定的物理位置,两个设计不能分配到重叠的 GT。检查 LANE1_GT_LOC 等参数。
4. 复位顺序敏感
// 注意复位信号的依赖关系
areset <= ~ap_rst_n || sys_reset; // 组合复位
fifo_resetn[ii] <= !(areset || scalar[ii][8]); // FIFO 单独复位
必须先释放 areset,再释放 fifo_resetn,否则可能导致 FIFO 处于不确定状态。
🛠️ 调试技巧
- 检查
rx_block_lock:读取控制寄存器 0x14,bit0 应该为 1 表示链路已锁定 - 使用 GT 环回模式:设置
scalar00[2:0]为 3'b010 (近端 PCS 环回) 进行自测 - Vivado ILA:在
_x/link/vivado/vpl/prj/prj.xpr中添加 Integrated Logic Analyzer - 查看实现结果:检查
xxv_ethernet的 placement 是否符合预期
📋 扩展指南
若要基于此设计开发真实应用:
- 替换
data_fifo_krnl:插入你的处理逻辑(如协议解析、加密、压缩等) - 增加 DDR 访问:如需大包缓冲,添加
m_axi接口和 DDR 控制器 - 多队列支持:参考 x4 设计,扩展更多独立的数据通路
- 中断支持:当前设计使用轮询,可添加
interrupt接口实现事件驱动
文件清单
| 文件 | 用途 |
|---|---|
rtl/ethernet_krnl_axis_x1.sv |
单通道以太网内核 RTL |
rtl/ethernet_krnl_axis_x4.sv |
四通道以太网内核 RTL |
rtl/ethernet_control_s_axi_x1.v |
单通道 AXI-Lite 控制器 |
rtl/ethernet_control_s_axi_x4.v |
四通道 AXI-Lite 控制器 |
rtl/data_fifo_krnl.sv |
Loopback FIFO 内核 RTL |
gen_ip_x1.tcl / gen_ip_x4.tcl |
IP 生成脚本 |
pack_eth_x1_kernel.tcl / pack_eth_x4_kernel.tcl |
内核打包脚本 |
pack_data_fifo_kernel.tcl |
FIFO 内核打包脚本 |
connectivity_x1.cfg / connectivity_x4.cfg |
Vitis 链接配置 |
Makefile |
构建流程控制 |
子模块文档
本模块包含以下子模块,每个都有详细的独立文档:
| 子模块 | 文档链接 | 描述 |
|---|---|---|
| connectivity_x1 | connectivity_x1 配置详解 | 单通道以太网连接配置 |
| connectivity_x4 | connectivity_x4 配置详解 | 四通道以太网连接配置 |
相关模块
- alveo_aurora_kernel_stream_config - Aurora 协议的类似实现
- mixing_c_and_rtl_kernels_integration - RTL 与 HLS 内核混合集成方法
- vitis_data_mover_kernels_and_system_connectivity - 数据搬运内核基础
总结
alveo_ethernet_kernel_connectivity 模块是一个方法论示范,它证明了:
在 Vitis 流程中集成 GTY 收发器并非黑魔法——只要正确处理
gt_port、gt_refclk和clk_gt_freerun三个关键接口,其余部分与普通 RTL Kernel 无异。
这个设计的优雅之处在于其分层抽象:
- 底层:
xxv_ethernetIP 隐藏了 PCS/MAC 的复杂性 - 中层:RTL wrapper 提供标准化的 AXI-Stream 接口
- 上层:Vitis 工具链处理平台连接和比特流生成
对于新加入团队的工程师,建议按以下顺序学习:
- 通读本文档理解架构
- 阅读
README.md了解构建流程 - 研究
connectivity_x1.cfg理解信号连接 - 在 Vivado 中打开实现后的设计查看实际布线
- 尝试修改
data_fifo_krnl加入简单逻辑(如计数器、包头解析)