7、部分重构设计流程:Vivado PR设计流程、约束文件编写、综合与实现策略

好,咱们今天聊点实在的。部分重构(Partial Reconfiguration,简称PR)这个技术,说白了就是让FPGA在运行的时候,只换掉一部分逻辑,其他部分照常干活。听起来很酷对吧?但真正上手做,你会发现坑不少。我最早接触PR是在一个通信项目里,板子已经装到机箱里了,想升级算法又不能断电……嗯,那时候我就知道,PR这东西,流程不对,后面全是泪。

7.1 Vivado PR设计流程:三步走

Vivado的PR流程,我习惯把它拆成三个阶段。你按这个节奏走,基本不会乱。

7.1.1 第一步:规划与准备

这一步最容易被忽略。很多人上来就写代码,结果后面发现管脚冲突、资源不够,回头改设计,那叫一个痛苦。

  • 确定重构区域:哪些模块需要动态换?哪些是固定的?我个人建议,把频繁升级的算法模块、协议处理模块划为可重构区。
  • 划分物理区域:在芯片上圈出一块矩形区域,作为PR Region。注意,这个区域必须是连续的、对齐的时钟区域(Clock Region)。
  • 创建PR设计:顶层模块里,把可重构模块实例化成一个黑盒(Black Box)。Vivado会帮你生成一个“空壳子”。
小技巧:我习惯在规划阶段就用Tcl脚本把PR Region的坐标算好。比如用 create_pblock 命令,精确到SLICE级别。这样后面综合实现时,Vivado不会乱放逻辑。

7.1.2 第二步:综合与实现

这一步是PR流程的核心。Vivado会做两遍综合:一遍是静态逻辑(Static Logic),一遍是每个可重构模块的“变体”(Reconfigurable Module Variant)。

  • 综合静态设计:把顶层和固定模块综合成网表。
  • 综合每个变体:比如你有三个版本的算法模块,每个都要单独综合。
  • 布局布线:先布静态逻辑,再布每个变体。注意,变体只能放在你划好的PR Region里。
注意:我曾经犯过一个错——静态逻辑和可重构逻辑之间用了跨时钟域信号,结果重构时出现了亚稳态。后来我强制要求所有跨区信号必须经过同步器,并且用 ASYNC_REG 约束标记。嗯,从那以后就没出过问题。

7.1.3 第三步:生成比特流

Vivado会生成两种比特流:

  • 全比特流:包含静态逻辑和初始的可重构模块。第一次加载用这个。
  • 部分比特流:只包含可重构模块的差异部分。运行时加载这个,就能换模块。

生成完成后,你会得到一堆 .bit.partial.bit 文件。记得用 write_bitstream 命令加上 -cell 选项,指定哪个模块生成部分比特流。

7.2 约束文件编写:别让时序飞了

PR的约束,比普通设计多了一层。你想想看,同一个物理区域,要跑不同的逻辑,时序约束必须覆盖所有变体。

7.2.1 物理约束

pblock 约束来定义PR Region。我一般这么写:

create_pblock pblock_pr_region
add_cells_to_pblock [get_cells {u_pr_module}] pblock_pr_region
resize_pblock pblock_pr_region -add {SLICE_X36Y100:SLICE_X55Y149}

这里 u_pr_module 是顶层里那个黑盒实例的名字。坐标范围你得查芯片手册,别瞎填。

7.2.2 时序约束

PR的时序约束,核心是“静态逻辑的时序必须覆盖所有变体”。我习惯的做法是:

  • 对静态逻辑的时钟,用 create_clock 正常约束。
  • 对可重构模块的输入输出路径,用 set_input_delayset_output_delay 约束,并且把 -max-min 都设上。
  • set_clock_groups 把不同变体的时钟分开,避免Vivado乱分析。
避坑指南:我曾经遇到一个情况——某个变体跑200MHz没问题,另一个变体只能跑150MHz。结果静态逻辑按200MHz约束,导致150MHz的变体时序违例。后来我学乖了:所有变体必须满足最严格的时序要求。说白了,就是“就高不就低”。

7.3 综合与实现策略:让工具听话

Vivado的综合和实现策略,在PR设计里需要特别调教。默认策略往往不够好。

7.3.1 综合策略

我推荐用 Vivado Synthesis Defaults 作为基础,然后做两处修改:

  • 开启PR模式:在综合设置里,把 -pr_mode 设为 reconfigurable。这样Vivado会保留可重构模块的层次结构,不会把逻辑优化到静态区。
  • 关闭跨模块优化:用 -flatten_hierarchy none。你想想看,如果Vivado把可重构模块和静态逻辑合并优化了,那后面怎么单独换模块?

7.3.2 实现策略

实现阶段,我习惯用 Performance_ExplorePR 策略。这个策略会尝试多种布局布线方案,找到最优解。但注意,它跑得比较慢。如果项目时间紧,可以用 Congestion_SpreadLogic_high 来缓解布线拥塞。

另外,有个参数叫 pr_flow,在实现时一定要设为 true。否则Vivado不会生成部分比特流。

个人经验:我一般在综合后先跑一次 report_utilization,看看可重构区域的资源占用。如果LUT或BRAM超过80%,我会调整区域大小或优化代码。因为PR模块的布线资源是固定的,太挤了容易时序违例。

7.4 知识体系总览

下面这张图,是我自己总结的PR设计流程。你照着这个框架走,基本不会漏步骤。

Vivado PR设计流程总览 阶段1:规划与准备 确定PR区域 · 创建黑盒 阶段2:综合与实现 静态+变体综合 · 布局布线 阶段3:生成比特流 全比特流 · 部分比特流 子步骤 1. 划分时钟区域 2. 创建pblock约束 3. 实例化黑盒模块 子步骤 1. 综合静态逻辑 2. 综合每个变体 3. 布局布线+时序分析 子步骤 1. 生成全比特流 2. 生成部分比特流 3. 验证重构功能 关键输出文件 • 全比特流:top.bit • 部分比特流:pr_module.partial.bit • 约束文件:pr_constraints.xdc • 时序报告:timing_summary.rpt

7.5 常见问题与对策

最后,我列几个PR设计里容易踩的坑,都是真金白银换来的教训。

问题 原因 对策
部分比特流加载失败 PR Region的边界与静态逻辑有未约束的路径 set_property PR_MODE RECONFIGURABLE 强制约束
时序违例 不同变体的路径延迟差异大 所有变体共用同一套时序约束,以最严为准
资源利用率过高 PR Region太小,或逻辑太密集 扩大区域,或拆分模块
重构时系统崩溃 重构过程中,静态逻辑访问了正在重构的模块 在顶层加握手信号,重构期间禁止访问
重要提醒:PR设计不是写完代码就完事的。你必须在硬件上实际验证重构过程。我见过太多仿真通过、上板就挂的案例。尤其是ICAP接口的时序,一定要用示波器或逻辑分析仪抓一下。

好了,关于Vivado PR设计流程、约束和策略,今天就聊到这儿。你回去可以拿一个简单的LED闪烁模块练练手,先跑通流程,再慢慢加复杂度。记住,PR这东西,纸上谈兵没用,动手做一遍比看十遍文档都管用。


公众号:蓝海资料掘金营,微信deep3321