🏠

connectivity_x4 模块技术深度解析

概述:这个模块解决什么问题?

connectivity_x4 是 Vitis 硬件加速平台中用于配置 Alveo 数据中心加速卡四通道以太网连接 的链接配置文件。想象你正在搭建一个高性能网络数据包处理系统——你需要让 FPGA 通过四个独立的 10G/25G 以太网通道同时收发数据,就像在机场建立四条并行的行李传送带,每条都能独立处理旅客的行李。

这个模块的核心价值在于:它定义了如何将 RTL 内核(包含 GTY 收发器的以太网子系统)与数据缓冲内核通过 AXI Stream 接口连接起来,形成完整的硬件数据通路。没有这种配置,Vitis 链接器无法知道各个内核实例应该如何互联,也无法将 GT 收发器的专用信号(参考时钟、自由运行时钟、物理端口)正确绑定到平台资源上。

为什么需要专门的配置文件?因为现代 FPGA 加速卡集成了复杂的硬核资源(GTY 收发器、QSFP 接口、专用时钟网络),这些资源不能通过标准的 HLS 流接口自动推断,必须通过显式的 connect 语句告诉 Vitis 工具链如何布线。


架构设计:数据如何流动

整体拓扑图

graph TB subgraph "Platform Resources" REFCLK[io_clk_qsfp_refclka_00
QSFP 参考时钟] FREERUN[ii_level0_wire/ulp_m_aclk_freerun_ref_00
自由运行时钟] QSFP[io_gt_qsfp_00
QSFP 物理接口] end subgraph "eth0: ethernet_krnl_axis_x4" ETH_IP[xxv_ethernet_x4_0
四通道以太网子系统 IP] TX_FIFO0[tx0_fifo
发送 FIFO] RX_FIFO0[rx0_fifo
接收 FIFO] TX_FIFO1[tx1_fifo] RX_FIFO1[rx1_fifo] TX_FIFO2[tx2_fifo] RX_FIFO2[rx2_fifo] TX_FIFO3[tx3_fifo] RX_FIFO3[rx3_fifo] CTRL[ethernet_control_s_axi
AXI-Lite 控制接口] end subgraph "df0-df3: data_fifo_krnl x4" DF0[df0
数据回环 FIFO] DF1[df1] DF2[df2] DF3[df3] end REFCLK -->|gt_refclk| ETH_IP FREERUN -->|clk_gt_freerun| ETH_IP ETH_IP <-->|gt_port| QSFP ETH_IP -->|rx0_axis| DF0 ETH_IP -->|rx1_axis| DF1 ETH_IP -->|rx2_axis| DF2 ETH_IP -->|rx3_axis| DF3 DF0 -->|tx0_axis| ETH_IP DF1 -->|tx1_axis| ETH_IP DF2 -->|tx2_axis| ETH_IP DF3 -->|tx3_axis| ETH_IP style ETH_IP fill:#e1f5fe style DF0 fill:#fff3e0 style DF1 fill:#fff3e0 style DF2 fill:#fff3e0 style DF3 fill:#fff3e0

组件角色解析

1. eth0 - 四通道以太网内核 (ethernet_krnl_axis_x4)

这是整个系统的核心网络引擎,内部封装了 AMD 的 xxv_ethernet IP 核,提供四个独立的 10G/25G 以太网通道。它的设计遵循生产者-消费者分离模式:每个通道都有独立的接收和发送 AXI Stream 接口,通过异步 FIFO 实现跨时钟域的数据缓冲。

关键设计洞察:

  • 双时钟域架构:以太网子系统工作在 tx_clk_outrx_core_clk 时钟域(由 GT 收发器恢复),而外部接口工作在 ap_clk 系统时钟域。FIFO 充当"翻译官",平滑两个不同时钟域之间的数据传输。
  • 控制面与数据面分离:AXI-Lite 接口 (s_axi_control_*) 用于配置寄存器、读取状态;AXI Stream 接口用于高速数据吞吐。这种分离确保控制操作不会阻塞数据流水线。

2. df0-df3 - 数据缓冲内核 (data_fifo_krnl)

这四个实例本质上是简单的回环缓冲器,每个包含两个级联的 AXIS FIFO。它们的作用是:

  • eth0 接收数据(RX 方向)
  • 将数据原样返回给 eth0(TX 方向)
  • 在示例设计中形成 Loopback 测试通路

这种设计的精妙之处在于模块化复用data_fifo_krnl 是一个通用组件,可以被任意数量的通道实例化。如果你需要真实的业务逻辑(如协议解析、加密解密),只需替换这些 FIFO 内核即可,无需修改 eth0 或连接配置。


配置文件深度解读

内核实例化声明

nk=ethernet_krnl_axis_x4:1:eth0
nk=data_fifo_krnl:4:df0.df1.df2.df3

nk (number of kernels) 指令告诉 Vitis 链接器:

  • 实例化 1 个 ethernet_krnl_axis_x4,命名为 eth0
  • 实例化 4 个 data_fifo_krnl,分别命名为 df0df1df2df3

命名约定很重要——后续所有的 stream_connectconnect 语句都依赖这些实例名来定位端口。

流连接拓扑

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

这八条语句构建了完全对称的四通道回环拓扑。每条 stream_connect 建立了一个单向的 AXI Stream 连接,格式为 source:destination

数据流向:

  1. 接收方向:外部网络 → QSFP → eth0 的 GT 收发器 → xxv_ethernet IP → rxN_fiforxN_axis 端口 → dfN.rx_axis
  2. 发送方向dfN.tx_axiseth0.txN_axistxN_fifoxxv_ethernet IP → GT 收发器 → QSFP → 外部网络

注意 FIFO 的方向性:rx_fifo 将以太网时钟域的数据转换到系统时钟域;tx_fifo 做相反的转换。

平台专用信号绑定

# For xilinx_u200_gen3x16_xdma_1_202110_1 platform
connect=eth0/clk_gt_freerun:ii_level0_wire/ulp_m_aclk_freerun_ref_00
connect=io_clk_qsfp_refclka_00:eth0/gt_refclk
connect=eth0/gt_port:io_gt_qsfp_00

这三行是平台相关的关键配置,直接决定了 GT 收发器能否正常工作:

信号 方向 作用
clk_gt_freerun Input → eth0 GT 收发器的自由运行时钟,用于复位和初始化期间的稳定时钟源
gt_refclk Platform → eth0 来自 QSFP 接口的差分参考时钟(通常为 156.25MHz 或 161.1328125MHz),决定线速率
gt_port Bidirectional GT 收发器的物理差分信号对(txp/txn, rxp/rxn),直连 QSFP 连接器

设计权衡:这些信号名称(io_clk_qsfp_refclka_00io_gt_qsfp_00)是 Alveo U200 平台特定的。如果移植到其他 Alveo 卡(如 U250、U280),必须使用 platforminfo 工具查询对应的信号名并修改配置。


RTL 内核实现剖析

ethernet_krnl_axis_x4.sv 核心结构

该模块是一个参数化的 SystemVerilog 包装器,围绕 xxv_ethernet IP 构建。关键参数包括:

parameter integer C_S_AXI_CONTROL_ADDR_WIDTH = 12;  // AXI-Lite 地址宽度
parameter integer C_S_AXI_CONTROL_DATA_WIDTH = 32;  // AXI-Lite 数据宽度
parameter integer C_M_AXI_ADDR_WIDTH       = 64;    // 保留(未使用内存映射主接口)
parameter integer C_M_AXI_DATA_WIDTH       = 64;    // 保留
localparam C_NUM_LANES = 4;                         // 固定四通道

为什么保留未使用的 AXI4 主接口参数? 这是 Vitis RTL 内核的标准模板要求——即使当前设计不需要 DRAM 访问,保留这些参数可以确保与 Vitis 工具链的预期签名兼容,方便未来扩展。

时钟域交叉 (CDC) 策略

// 复位同步链
always_ff @(posedge ap_clk) begin
  sys_reset <= sys_reset_comb;
  for (int ii = 0; ii < C_NUM_LANES; ii++) begin
      areset <= ~ap_rst_n || sys_reset;
      fifo_resetn[ii] <= !(areset || scalar[ii][8]);
  end 
end

// 块锁定状态同步
xpm_cdc_array_single #(
    .DEST_SYNC_FF(4),
    .INIT_SYNC_FF(0),
    .SIM_ASSERT_CHK(0),
    .SRC_INPUT_REG(0),
    .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)
);

这里使用了 XPM (Xilinx Parameterized Macros) CDC 原语,而非手写同步器。好处是:

  • 经过验证的亚稳态保护(4 级触发器链)
  • 工具可识别的标准结构,便于时序分析和约束生成
  • 仿真和综合行为一致

stat_rx_block_lock 是以太网 PCS 层的信号,表示接收端已锁定到传入的数据流。它需要同步到 ap_clk 域,供软件通过 AXI-Lite 读取。

控制寄存器映射

ethernet_control_s_axi #(
  .C_S_AXI_ADDR_WIDTH ( C_S_AXI_CONTROL_ADDR_WIDTH ),
  .C_S_AXI_DATA_WIDTH ( C_S_AXI_CONTROL_DATA_WIDTH )
)
inst_control_s_axi (
  // ... AXI 信号 ...
  .scalar00 ( scalar[0]             ),
  .scalar01 ( scalar[1]             ),
  .scalar02 ( scalar[2]             ),
  .scalar03 ( scalar[3]             ),
  .rx_block_lock( ap_stat_rx_block_lock_sync)
);

每个通道有 32 位的 scalar 寄存器,位域定义如下:

位范围 功能
[2:0] gt_loopback - GT 收发器环回模式选择
[4] gtwiz_reset_rx_datapath - 接收通路复位
[5] gtwiz_reset_tx_datapath - 发送通路复位
[8] 通道级 FIFO 复位使能
[12] 全局系统复位

设计决策:使用单个 32 位寄存器而非多个独立寄存器,减少了 AXI-Lite 地址空间占用,简化了驱动程序开发。代价是位域语义不够自描述,需要配合文档使用。

异步 FIFO 实例化模式

axis_data_fifo_0 tx0_fifo (
  .s_axis_aresetn(fifo_resetn[0]),
  .s_axis_aclk(ap_clk),                          // 写侧:系统时钟
  .s_axis_tvalid(tx0_axis_tvalid),
  .s_axis_tready(tx0_axis_tready),
  // ... 数据信号 ...
  .m_axis_aclk(tx_clk_out[0]),                   // 读侧:以太网发送时钟
  .m_axis_tvalid(axi_str_txd_tvalid[0]),
  .m_axis_tready(axi_str_txd_tready[0]),
  // ... 数据信号 ...
);

八个 FIFO(4 TX + 4 RX)遵循镜像对称的时钟连接:

  • TX FIFO: ap_clk (写) → tx_clk_out[N] (读)
  • RX FIFO: rx_core_clk[N] (写) → ap_clk (读)

这种设计确保了无论以太网和系统时钟的频率关系如何(同源或异步),数据都能可靠传输。FIFO 的深度在生成的 IP 中配置,通常设置为能容纳几个最大长度的以太网帧(约 9KB)。


依赖关系分析

上游依赖(本模块依赖谁)

依赖项 关系类型 说明
connectivity_x1.cfg 设计变体 x1 配置是单通道版本,x4 是其四通道扩展。两者共享相同的内核源码,仅连接拓扑不同
ethernet_krnl_axis_x4 RTL 内核实现 配置文件引用的内核,必须在打包阶段生成 .xo 文件
data_fifo_krnl RTL 内核实现 四个缓冲内核实例的源码
xxv_ethernet IP 子系统 IP gen_ip_x4.tcl 生成的以太网子系统,包含 PCS/PMA 和 GT 配置
axis_data_fifo IP 基础 IP 用于跨时钟域缓冲的 FIFO,由 Vivado IP Integrator 管理
Alveo U200 平台 目标平台 提供 QSFP 时钟和 IO 资源定义

下游依赖(谁依赖本模块)

被依赖项 关系类型 说明
Vitis v++ 链接器 构建工具 读取此配置完成内核互联和平台绑定
生成的 top_level.xclbin 输出产物 链接过程的最终输出,包含完整比特流

设计权衡与决策记录

1. 为什么选择 x4 而非更多通道?

Alveo U200 的 QSFP28 接口物理上支持 4 个通道(每通道最高 25Gbps,共 100G)。选择 x4 而非 x8 或 x16 是因为:

  • 物理限制:QSFP 连接器只有 4 对收发差分线
  • 资源平衡xxv_ethernet x4 实例已经消耗了大量 GTY 收发器和相关时钟资源
  • 教学目的:作为教程,x4 足够展示多通道设计模式,又不至于过度复杂

2. 为什么使用独立的 data_fifo_krnl 而非内嵌 FIFO?

解耦优势

  • 允许用户替换为自定义处理逻辑,无需重新编译 ethernet_krnl
  • 符合 Vitis 的"内核即积木"哲学,提高复用性
  • 独立的 ap_ctrl_none 执行模型意味着 FIFO 内核不需要主机控制,简化运行时

代价

  • 额外的 LUT/FF 开销用于内核边界封装
  • 略微增加的布线复杂度

3. 为什么 GT 信号需要显式 connect 而非自动推断?

GT 收发器是硬核资源,其引脚位置由芯片物理布局固定,且需要特殊的时钟缓冲(IBUFDS_GTE)。Vitis 无法像普通 AXI Stream 那样自动推断这些连接,因为:

  • 时钟和数据的严格配对要求
  • 平台可能提供多种 GT 参考时钟选择
  • 某些设计可能需要级联多个 GT 通道

显式 connect 语句赋予开发者完全的控制权,代价是需要了解平台特定的信号命名。

4. 为什么 RX 和 TX 使用不同的 FIFO 深度策略?

观察 ethernet_krnl_axis_x4.sv 可以发现:

  • TX FIFO: s_axis_tready 连接到外部(可被反压)
  • RX FIFO: s_axis_tready 悬空(始终就绪,不反压以太网子系统)

这是非对称流量控制的设计:

  • 发送方向可以反压上游,防止 FIFO 溢出
  • 接收方向必须持续消费数据,否则以太网子系统会丢包(这是预期行为,高层协议负责重传)

新贡献者注意事项

常见陷阱

  1. 平台信号名不匹配

    # 错误示例(U250 平台)
    connect=io_clk_qsfp_refclka_00:eth0/gt_refclk  # U200 的信号名
    # U250 可能是 io_clk_qsfp0_refclka_00
    

    修复:始终先用 platforminfo -p <platform> -v 确认信号名。

  2. FIFO 复位顺序 必须先复位 ethernet_krnl 内部的 fifo_resetn,再释放 ap_rst_n。如果顺序颠倒,可能导致 FIFO 处于不确定状态。

  3. 时钟约束遗漏 tx_clk_outrx_core_clk 是由 GT 恢复的时钟,需要在 XDC 中创建 generated clock 约束。Vitis 通常自动生成这些约束,但手动编辑设计时需要检查。

调试技巧

  • 验证连接:链接完成后,打开 _x/link/vivado/vpl/prj/prj.xpr,查看 Block Design 中的 ulp 单元,确认所有 stream_connectconnect 都已正确实例化为 AXI Interconnect 或直接连线。

  • Loopback 测试:示例设计的数据通路是纯回环。如果收不到数据,分段排查:

    1. 检查 stat_rx_block_lock 是否为 1(物理层锁定)
    2. 检查 df0rx_axis 是否有活动(接收 FIFO 写入)
    3. 检查 df0tx_axis 是否有活动(发送 FIFO 读出)

扩展指南

若要添加第 5-8 通道(如果硬件支持):

  1. 修改 ethernet_krnl_axis_x4.sv,将 C_NUM_LANES 改为 8
  2. 更新 xxv_ethernet IP 配置为 x8 模式
  3. connectivity_x4.cfg 中添加 df4-df7 实例和对应的 stream_connect
  4. 确认平台有足够的 GTY 通道和 QSFP 接口

参考链接

On this page