作者: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 输出可验证。

