跳转到主要内容
瑞苏盈科专栏
我与瑞苏盈科板卡的开发故事

ZCU102 上用 ICAP + DFX Controller 实现运行时局部重配置

作者:Yin Chaowen,AMD开发者;文章来源:AMD开发者社区

平台:ZCU102 / Zynq UltraScale+ MPSoC

工具:Vivado / Vitis 2025.2

主题:A53 + DDR + DFX Controller + ICAPE3 的 runtime DFX 设计原理

1. 为什么要把 DFX Controller 和 ICAP 放在一起

Dynamic Function eXchange(DFX)要解决的问题是:系统运行时,不重新下载整片 FPGA,只替换 PL 中某一块可重配置区域(Reconfigurable Partition, RP)里的模块(Reconfigurable Module, RM)。

在调试或 bring-up 阶段,我们经常用 JTAG 直接下载 partial bitstream。这个方法直观,也适合验证 RP/RM 本身是否正确。但它不代表最终系统里的运行时路径。真实系统更常见的需求是:

1. A53 或其他处理器决定什么时候切换功能。

2. partial bitstream 预先存在 DDR、Flash、SD 卡或网络载入的内存区域中。

3. 一个硬件控制器负责把 bitstream 从内存搬到配置端口。

4. PL 内部的配置入口(ICAP/ICAPE3)完成真正的局部重配置。

DFX Controller IP 正好承担第 3 步:它可以作为 AXI master 从内存读取 partial bitstream,再驱动 ICAP 接口完成配置,同时提供状态机、trigger、RM/bitstream table 等控制接口。

所以本文讨论的不是“JTAG partial 能不能成功”,而是这个运行时链路:

这个链路跑通以后,A53 软件只需要准备数据、配置表项、触发 DFX Controller,不需要自己逐拍操作 ICAPE3。

2. 整体架构:控制路径和数据路径要分开看

这类设计最容易混淆的地方,是把“谁下命令”和“谁搬数据”混在一起。建议一开始就拆成两条路径理解。

在 ZCU102 的一个可复用设计中,地址可以按下面的方式规划:

RM 本身最好留一个非常直接的硬件判据。例如

这样无论是 JTAG script、UART log,还是 A53 程序,都可以用“常量是否变化”判断 partial reconfiguration 是否真的生效。

3. DFX Controller IP 在这个设计里做什么

DFX Controller 可以理解为一个“运行时局部重配置调度器”。它不是 magic,也不会自动知道 bitstream 在哪里。软件需要先把表项写进去:

1. RM table:RM ID 与 bitstream ID 的关系。

2. Bitstream table:每个 partial BIN 的 DDR 起始地址和大小。

3. Trigger table:某个 trigger 对应要加载哪个 RM。

4. Control/status:触发加载、轮询状态、读取错误码。

触发后,DFX Controller 的工作流程大致是:

从软件角度看,最关键的状态是:

最后一条很重要:DFX Controller 到 FULL 只是 IP 状态机的结果,真正的功能判据仍然应该来自 RP/RM 侧的硬件输出。

4. ICAPE3 与 bridge:为什么需要一个“观察窗口”

在简单设计里,可以把 DFX Controller 的 ICAP interface 直接接到 ICAPE3 wrapper。但一旦遇到 RM_LOAD 卡住,只看 DFXC status 往往不够。你会不知道问题发生在:

1. DDR 里没有正确的 BIN。

2. DFXC 没有从 DDR 读出数据。

3. DFXC 已经出流,但 ICAP 仲裁没给它。

4. ICAPE3 不可用。

5. ICAPE3 收到了数据,但没有 PRDONE。

因此一个很实用的做法,是在 DFX Controller 和 ICAPE3 之间加一个轻量 bridge。它不改变重配置本质,只做三件事:

1. 信号适配:把 DFXC 的 ICAP 写时序接到 ICAPE3 primitive。

2. 简单仲裁:如果系统中只有 DFXC 一个 ICAP master,可以使用 always-grant。

3. 状态观测:把 AVAIL、PRDONE、PRERROR、write word count、first/last word、PL cycle counter 等信息通过 AXI GPIO 暴露给 A53/JTAG。

一个典型 bridge 结构如下:

bridge 里最有用的调试信号包括:

调试中还可以临时加一个 FORCE_DFXC_AVAIL 开关:强制让 DFXC 看到 available=1。这个开关只能作为诊断手段,不能作为正式修复。因为它可能让 DFXC 继续出流甚至进入 FULL,但如果底层 ICAPE3 实际不可用,RM 仍然不会变化。

5. ZynqMP 上最容易忽略的点:PCAP 和 ICAP 的配置端口归属

ZCU102 是 Zynq UltraScale+ MPSoC 平台。这里有一个非常关键的系统级事实:PCAP 与 PL 侧 ICAP/MCAP 共享配置通道,配置端口的归属需要正确设置。

在一个典型失败场景里:

这时很容易怀疑 BIN 格式、字节序、DFX Controller table、AXI HP0、SmartConnect 或 RP compatibility。但如果 direct JTAG partial 能成功,DDR 里的 BIN marker 也正确,而 ICAPE3 AVAIL=0,就应该优先检查 ZynqMP 配置端口归属。

关键寄存器是:

当 PCAP_CTRL.PCAP_PR=1 时,配置通道由 PCAP 持有,PL 内部 ICAPE3/MCAP 不能真正接收配置流。对于要走 ICAP 的 DFX Controller runtime path,需要在 A53 软件启动后清这个 bit:

建议把这个动作放在 DFX Controller 初始化之前:

如果 UART 或 JTAG log 能看到下面这种信息,说明配置端口归属已经切到 ICAP:

这也是本文最想强调的经验:DFX Controller + ICAPE3 的硬件连接正确,并不自动意味着 ICAPE3 可以用;在 ZynqMP 上还要确认 PCAP/ICAP 端口归属。

6. Partial BIN 格式与 DDR 校验

DFX Controller 从 DDR 读取的是面向 ICAP 的配置数据,不是任意文件。一般流程是从 Vivado partial bitstream 生成适合 ICAP/SMAP 的 BIN,例如:

具体命令会随工程组织方式变化,但要点是:DFXC 读取的内存内容必须和 ICAPE3 期望的 word order/format 匹配。

软件把 BIN 拷贝到 DDR 后,不要只看第一个 word。实际 ICAP BIN 前面可能有 dummy word。例如一次验证中,正确数据表现为:

0xFFFFFFFF 在这里是正常 dummy word,不能据此判断 DDR copy 失败。更稳妥的做法是检查多个固定 offset 上的 marker,并结合 bridge 的 first_word / word_count 判断 DFXC 是否真的读到了 DDR 数据。

另外,A53 拷贝 BIN 到 DDR 后需要 flush DCache,避免 DFX Controller 通过 HP0 读到旧数据:

7. 推荐验证顺序:不要一上来就看 DFXC

运行时 DFX 链路比较长,建议按层次验证,而不是直接跑完整 app 后猜原因。

典型 PASS log 可以长这样:

如果出现下面这种组合,就优先查 ICAP 可用性和 PCAP/ICAP 归属

如果出现 FULL 但 RM 常量不变,则说明 DFXC 状态机完成了某个内部流程,但配置流没有真正改变 RP,仍然要回到 ICAPE3/PCAP/ICAP 端口归属和底层配置信号继续查。

8. PL 侧配置耗时:为什么不要用软件轮询时间当 Tconfig

运行时 partial reconfiguration 的耗时可以有很多定义。软件从“写 trigger”到“轮询到 done”的时间,包含 A53 代码、cache、AXI-Lite、JTAG/UART 输出、轮询间隔等因素,不适合直接代表 ICAP 配置流本身耗时。

如果想测更纯粹的配置时间,可以在 bridge 里用 PL 计数器定义:

Tconfig_pl = 第一拍有效 ICAP write 到 ICAPE3 PRDONE 的 cycle 数

比如 PL 计数时钟是 100 MHz,一次测得:

一次 30 轮 RM1/RM0 循环(共 60 次 load)中,如果每次都是 125045 cycles,说明:

1. DFX Controller 的 fetch/stream 路径稳定。

2. ICAPE3 配置完成信号稳定。

3. PL 侧测量不受 UART 打印、JTAG script sleep、A53 轮询粒度影响。

这个指标适合用于比较不同 partial bitstream 大小、ICAP clock、DFXC 配置或系统架构下的配置效率。

9. Vivado / Vitis 构建思路

Vivado 侧的核心不是“把 IP 都放进去”,而是保证三类连接正确:

1. A53 控制 DFXC:PS master 能通过 AXI-Lite 访问 DFX Controller。

2. DFXC 访问 DDR:DFX Controller M_AXI_MEM 能通过 SmartConnect 接到 PS S_AXI_HP0_FPD。

3. DFXC 访问 ICAP:DFX Controller ICAP interface 经过 bridge 或 wrapper 接到 ICAPE3。

Vitis 侧的核心是一个 bare-metal app:

1. 初始化平台。

2. 清 PCAP_CTRL.PCAP_PR。

3. 将 rm0_icap.bin、rm1_icap.bin 拷贝到 DDR。

4. flush cache。

5. 写 DFX Controller tables。

6. 触发 RM0/RM1 load。

7. 读取 DFXC status 和 RM constant。

如果使用 Vitis 2025.2 的 SDT flow,还要注意 DFX Controller / PRC 相关驱动生成可能与 no-POR-RM 配置存在兼容性问题。工程实践中更稳妥的做法是:

1. 不修改全局 Xilinx 安装。

2. 使用本地 SDT overlay 修正生成脚本或绕过有问题的自动配置表。

3. 在 app 中直接按 DFX Controller 寄存器定义写 table 和 trigger。

这样做的好处是验证路径可复现,并且不会污染其他 Vivado/Vitis 工程。

10. 复用这类设计时的 checklist

如果你也要在 ZynqMP 平台上做 DFX Controller + ICAP runtime DFX,可以按这个 checklist 过一遍:

• RP/RM 先用 direct JTAG partial 验证通过。

• RM 里放一个可读回的硬件常量,作为最终功能判据。

• DFX Controller M_AXI_MEM 确认能访问 PS DDR,例如经 SmartConnect 到 S_AXI_HP0_FPD。

• partial bitstream 转成 ICAP/SMAP 适用的 BIN,并检查 DDR 中多个 offset 的 marker。

• A53 拷贝 BIN 后 flush DCache。

• A53 在触发 DFXC 前清 PCAP_CTRL.PCAP_PR,确认 0xFFCA3008[0]=0。

• 不要只相信 DFXC FULL,还要读 RM 输出确认真实切换。

• 调试版本建议加入 ICAP bridge debug GPIO:AVAIL、word_count、first/last word、PRDONE、PRERROR。

• 如果要测配置耗时,优先用 PL 侧 first ICAP write -> PRDONE 计数,而不是软件轮询时间。

11. 小结

ZCU102 上的 ICAP + DFX Controller runtime DFX,本质上是一条跨 PS/PL 的协作链路:A53 准备数据和控制表,DFX Controller 从 DDR 取 partial BIN,ICAPE3 完成真正的 PL 局部重配置。

这类设计最关键的不是某一个 IP 怎么连,而是把几个边界条件同时满足:DDR 数据正确、DFXC table 正确、ICAP bridge 可观察、ICAPE3 可用、RM 输出可验证。