首页 / 资讯中心 / 文章详情

FPGA PBlock设计指南:从时序违例到布局优化的实战技巧

FPGA PBlock设计指南:从时序违例到布局优化的实战技巧 ★ FEATURED ARTICLE
1. 从一次时序违例说起PBlock到底在解决什么问题很多人第一次接触PBlock是因为综合实现跑完之后时序报告一片飘红或者布线拥塞到工具直接摆烂。你打开Device视图看到逻辑被撒得满芯片都是关键路径上的两个模块隔了半个die延迟自然下不来。这时候老手会告诉你去画个PBlock吧。但PBlock不是万能药。我见过太多人把模块往PBlock里一拖约束一加结果时序更差了——因为PBlock本质上是一种物理区域约束它限制的是逻辑被放置在芯片的哪个矩形区域内而不是直接优化时序。理解这一点非常关键PBlock做的是“圈地”不是“修路”。你把两个需要高速通信的模块圈在一起缩短它们之间的物理距离布线延迟才会降下来但如果你圈得太小工具在里面塞不下就会疯狂报错或者降低布局质量。从VIVADO的实现流程来看PBlock作用于布局Placement阶段。综合完成之后你的设计还是一张逻辑网表每个LUT、FF、BRAM、DSP都还没有具体的物理位置。布局阶段的任务就是把这些逻辑单元分配到芯片上具体的SLICE、BRAM块、DSP Slice上。PBlock的作用就是在这一步告诉工具“这些逻辑只能放在这个区域里别的地方不许去。”那为什么需要这种约束几个典型场景时序收敛跨SLICEM和SLICEL的长线延迟差异很大关键路径上的逻辑如果被放得太散布线延迟可能占到总延迟的60%以上。把相关逻辑约束到一个PBlock里物理距离缩短布线延迟自然下降。拥塞缓解某些区域布线资源紧张工具默认的布局策略可能把大量逻辑堆在一起导致局部拥塞。PBlock可以强制把逻辑分散到不同区域。接口约束高速接口如DDR、PCIe、以太网的收发逻辑必须靠近对应的IO Bank否则走线太长会导致时序无法满足。增量编译在大型项目中把已经收敛的模块锁定在固定区域只对修改部分重新布局布线可以大幅缩短编译时间。但PBlock也有代价。圈地之后工具在这个区域内的布局自由度降低如果区域形状不合理或者资源估算不准反而会导致更差的布局结果。所以PBlock的正确使用姿势是先理解设计瓶颈再决定圈哪里、圈多大、圈成什么形状。2. 画PBlock之前必须搞清楚的三个底层概念2.1 PBlock的物理实现它到底约束了什么在VIVADO的底层数据库中PBlock最终会被翻译成一组禁止区域Prohibit和允许区域Allow的集合。当你创建一个矩形PBlock时工具会把这个矩形覆盖的所有SLICE、BRAM、DSP、URAM等资源标记为“可用”矩形外的资源标记为“不可用”。布局器在放置该PBlock内的逻辑时只会从允许区域里找位置。这里有个容易忽略的细节PBlock的边界是对齐到Clock Region的。一个Clock Region是芯片上按行列划分的物理区域通常包含若干个SLICE、一个或几个BRAM列、DSP列等。你画PBlock的时候工具会自动吸附到Clock Region的边界上。这意味着你无法创建一个“半个Clock Region”的PBlock——要么整个Clock Region包含进来要么完全不包含。这个特性带来两个后果资源粒度较粗如果你的模块只需要少量LUT但PBlock覆盖了一个完整的Clock Region那这个Clock Region里的其他资源就被浪费了不能被其他逻辑使用。形状受限PBlock可以是矩形也可以是多个矩形的组合通过Add Rectangle或绘制多边形但每个矩形都必须对齐Clock Region边界。2.2 资源估算为什么你的PBlock总是“装不下”创建PBlock之前你必须知道模块需要多少资源。VIVADO在综合后的Report Utilization里会给出整个设计的资源消耗但不会按模块拆分。你需要用Report Utilization -hierarchical或者打开 synthesized design 后在Netlist窗口里选中模块右键Report Utilization来查看该模块的详细资源。一个常见的错误是看到模块用了5000个LUT就画一个能装5000个LUT的PBlock。但实际上PBlock内的资源利用率不能达到100%。原因有几个布局器的碎片化逻辑单元不能完美填充每个SLICE总会有一些空隙。控制集Control Set约束同一个SLICE里的FF必须共享时钟、时钟使能、复位信号。如果模块内控制集很多SLICE的利用率会下降。布线资源预留PBlock边界附近的布线资源需要留给跨区域的信号。根据经验PBlock内的资源利用率建议控制在60%~70%。也就是说如果模块需要5000个LUTPBlock应该覆盖能提供约7000~8000个LUT的区域。BRAM和DSP的利用率可以稍高但也不建议超过80%。2.3 时序路径与PBlock的关系圈哪里比圈多大更重要PBlock的位置选择直接影响时序。关键原则是把时序最紧张的路径两端圈在同一个PBlock里或者圈在相邻的PBlock里。举个例子假设你有一个数据通路模块A和一个控制模块BA到B之间有一条关键路径延迟主要来自布线。如果你把A圈在芯片左下角B圈在右上角那这条路径的布线延迟会非常大。正确的做法是把A和B圈在相邻的Clock Region里让它们之间的布线走短距离的相邻资源。但这里有个矛盾如果A和B的资源需求都很大把它们圈在一起可能导致PBlock过大布局器在里面找不到好的布局方案。这时候可以考虑层次化PBlock创建一个大的父PBlock覆盖A和B然后在里面创建两个子PBlock分别约束A和B。这样子PBlock可以独立调整形状和位置同时父PBlock保证它们不会离得太远。3. 手把手创建第一个PBlock从Open Synthesized Design到约束生效3.1 准备工作综合后的设计数据库PBlock约束必须在综合后的设计Synthesized Design上创建而不是在RTL或综合前。流程如下在VIVADO中打开你的工程运行Synthesis。综合完成后点击Open Synthesized Design。在左侧Flow Navigator中展开Synthesized Design点击Edit Device或者直接在菜单栏选择Window - Device。此时会打开Device视图显示芯片的物理布局。注意如果你在综合前就创建PBlockVIVADO会提示你先运行综合。因为PBlock需要知道模块的层次结构和资源估算这些信息只有在综合后才能获得。3.2 创建PBlock的两种方式方式一从Netlist窗口拖拽这是最直观的方式。在Netlist窗口中找到你想要约束的模块比如u_ddr_ctrl右键选择Create PBlock或者直接把它拖到Device视图上。VIVADO会自动创建一个PBlock并把该模块及其子模块的所有逻辑都圈进去。方式二手动绘制PBlock在Device视图中点击工具栏的Draw PBlock按钮或者右键选择Create PBlock然后在芯片上拖拽出一个矩形区域。创建完成后在PBlock属性窗口中通过Add Cells把模块添加进去。两种方式各有优劣拖拽方式快但PBlock的形状和位置是工具自动选的可能不理想手动绘制方式可以精确控制位置和形状但需要你对芯片布局有较好的理解。3.3 调整PBlock的形状和位置创建完PBlock后你可以通过以下操作调整移动选中PBlock直接拖拽到新位置。调整大小拖拽PBlock的边缘或角落。添加多个矩形右键PBlock - Add Rectangle可以创建一个不规则的PBlock由多个矩形组成。排除区域如果PBlock内某个区域不想用比如已经被其他PBlock占用可以右键 - Add Exclusion Rectangle。这里有个实用技巧在Device视图中你可以打开Resource Utilization叠加层实时查看PBlock内的资源数量。具体操作是在Device视图右侧的Layers面板中勾选Routing Placement - Utilization。这样PBlock内会显示已用资源和总资源的比例帮你判断PBlock是否够大。3.4 设置PBlock属性RESET_AFTER_DONE和CONTAIN_ROUTING创建PBlock后在Properties窗口中会看到几个重要属性属性名含义建议值RESET_AFTER_DONE配置完成后是否复位PBlock内逻辑通常为FALSE除非有特殊需求CONTAIN_ROUTING是否将布线也限制在PBlock内时序紧张时设为TRUE但可能导致布线失败EXCLUDE_PLACEMENT是否排除布局通常为FALSESNAPPING_MODEPBlock边界的吸附模式通常为ON对齐Clock RegionCONTAIN_ROUTING是一个需要特别关注的属性。默认情况下PBlock只约束布局不约束布线。也就是说PBlock内的逻辑之间的连线可以绕到PBlock外面再回来。如果你把CONTAIN_ROUTING设为TRUE所有布线都必须走PBlock内部的资源。这可以进一步缩短布线延迟但也会增加布线拥塞的风险。我的建议是先不设CONTAIN_ROUTING等布局布线跑通、时序基本收敛后如果还有关键路径延迟下不来再尝试打开它。3.5 保存约束并验证PBlock创建完成后需要保存约束。在VIVADO中PBlock约束会以XDC命令的形式保存。你可以通过以下方式查看在Tcl Console中输入report_pblock查看当前所有PBlock的信息。打开XDC文件会看到类似create_pblock u_ddr_ctrl、resize_pblock u_ddr_ctrl -add {SLICE_X10Y100:SLICE_X20Y200}、add_cells_to_pblock u_ddr_ctrl [get_cells u_ddr_ctrl]的命令。保存后重新运行ImplementationVIVADO会在布局阶段应用这些约束。你可以在Implementation完成后的Report中查看PBlock的实际利用率打开Implemented Design在Device视图中选中PBlock右键Report PBlock Utilization。4. 那些年我踩过的PBlock坑从报错到时序恶化4.1 DRC RTSTAT-2报错PBlock资源不足的典型表现这是最常见的PBlock相关报错之一。错误信息通常是DRC RTSTAT-2: PBlock u_ddr_ctrl has insufficient resources for the cells assigned to it.原因很简单PBlock内的可用资源少于模块需要的资源。但为什么你明明按Report Utilization里的数字画了PBlock还是报这个错前面提到过PBlock内的资源利用率不能达到100%。但具体能到多少取决于模块的控制集数量、LUT和FF的比例、BRAM和DSP的分布等。我遇到过最极端的情况一个模块用了3000个LUT我画了一个能装4000个LUT的PBlock结果还是报RTSTAT-2。后来发现是因为这个模块有大量不同的控制集导致SLICE利用率只有50%左右。解决方法扩大PBlock至少留出40%的余量。如果模块内有大量小模块考虑用create_pblock的-add选项把多个Clock Region加进来而不是只画一个矩形。检查模块内是否有BRAM或DSP这些资源的分布是列状的如果PBlock没有覆盖完整的BRAM列就会导致BRAM无法放置。4.2 时序反而变差PBlock不是万能药我见过一个案例设计里有一条关键路径从模块A到模块B延迟主要来自布线。工程师把A和B分别圈在两个PBlock里结果时序更差了。为什么原因是他把A圈在了芯片左上角B圈在了右下角。虽然两个模块各自内部的时序改善了但A到B的跨区域路径延迟增加了。PBlock只优化了模块内部的布局没有考虑模块之间的连接。正确的做法对于有高速通信需求的模块应该把它们圈在相邻的PBlock里或者干脆圈在同一个PBlock里。如果资源允许把A和B放在同一个PBlock内让布局器自由安排它们的位置通常能得到更好的结果。4.3 布线拥塞CONTAIN_ROUTING的副作用打开CONTAIN_ROUTING后PBlock内的所有布线都必须走内部资源。如果PBlock形状不规则比如L形或者内部有BRAM列阻挡布线资源可能不够用导致布线失败或延迟增加。我的经验是只有在PBlock形状规整矩形、资源利用率低于60%、且模块内部连线密集的情况下才考虑打开CONTAIN_ROUTING。否则保持默认的FALSE让布线器有更多自由度。4.4 增量编译失效PBlock位置漂移在增量编译流程中你希望已经收敛的模块保持在原来的位置。但如果PBlock约束没有正确保存或者工具在重新布局时移动了PBlock增量编译就会失效。解决方法在增量编译的参考设计Reference Design中确保PBlock约束已经写入XDC并锁定。可以使用LOCK_PLACEMENT属性把PBlock内的逻辑位置完全锁定set_property LOCK_PLACEMENT TRUE [get_cells u_ddr_ctrl/*]但要注意锁定布局后如果模块内部有修改工具无法重新布局可能导致时序无法收敛。所以锁定布局通常只在最终签核阶段使用。5. 进阶技巧用Tcl脚本批量管理PBlock5.1 自动创建PBlock的Tcl模板在大型项目中手动拖拽PBlock效率太低。我通常会用Tcl脚本批量创建。以下是一个模板# 定义模块和对应的Clock Region范围 set pblock_defs { {u_ddr_ctrl {SLICE_X10Y100:SLICE_X30Y200}} {u_pcie_ctrl {SLICE_X40Y100:SLICE_X60Y200}} {u_eth_ctrl {SLICE_X70Y100:SLICE_X90Y200}} } foreach def $pblock_defs { set module [lindex $def 0] set range [lindex $def 1] # 创建PBlock create_pblock ${module}_pblock resize_pblock ${module}_pblock -add $range # 添加模块 add_cells_to_pblock ${module}_pblock [get_cells -hierarchical ${module}] # 设置属性 set_property CONTAIN_ROUTING FALSE [get_pblocks ${module}_pblock] set_property RESET_AFTER_DONE FALSE [get_pblocks ${module}_pblock] }这个脚本的好处是可以版本控制方便团队共享。你只需要根据芯片型号和模块资源需求调整Clock Region范围即可。5.2 用report_pblock检查约束状态在Implementation之前用以下命令检查PBlock状态report_pblock -all输出会显示每个PBlock的名称、包含的Cell数量、覆盖的Clock Region、资源利用率等信息。如果某个PBlock的利用率超过80%就需要考虑扩大范围。5.3 动态调整PBlock基于时序报告的反向优化PBlock不是一次画好就完事的。在Implementation完成后打开Timing Report找到违例的路径看路径的起点和终点在芯片上的物理位置。如果它们距离很远可以考虑调整PBlock把相关逻辑圈得更近。具体操作在Timing Report中选中一条违例路径右键选择Highlight - DeviceVIVADO会在Device视图中高亮这条路径的起点和终点。然后你可以根据高亮位置调整PBlock。6. 多Die FPGA的PBlock策略SLR交叉是最大的敌人6.1 多Die架构下的PBlock特殊性对于SSIStacked Silicon Interconnect器件比如Virtex UltraScale的VU9P、VU13P等芯片由多个SLRSuper Logic Region组成。SLR之间的通信必须经过SLLSuper Long Line或** Laguna寄存器**延迟远大于SLR内部的布线。在多Die器件上使用PBlock核心原则是尽量把相关逻辑圈在同一个SLR内。如果一个模块的逻辑跨越了两个SLR那么跨SLR的路径延迟会非常大通常需要额外的流水线寄存器来打拍。6.2 如何判断模块是否跨SLR在Device视图中SLR的边界会以明显的分隔线显示。你可以通过以下方式检查在Device视图的Layers面板中勾选Routing Placement - SLR会显示SLR的边界。在Report Utilization中查看模块的资源是否分布在多个SLR。如果发现模块跨SLR有两种处理方式调整PBlock把模块的所有逻辑圈在同一个SLR内。如果资源不够考虑把模块拆分成两个子模块分别放在两个SLR并在它们之间插入流水线寄存器。使用Laguna寄存器对于必须跨SLR的信号使用Laguna寄存器进行跨SLR通信。Laguna是专门用于SLR间通信的寄存器可以降低跨SLR延迟。6.3 多Die PBlock的Tcl约束示例# 把DDR控制器圈在SLR0 create_pblock u_ddr_slr0 resize_pblock u_ddr_slr0 -add {SLICE_X0Y0:SLICE_X50Y200} add_cells_to_pblock u_ddr_slr0 [get_cells u_ddr_ctrl] # 把PCIe控制器圈在SLR1 create_pblock u_pcie_slr1 resize_pblock u_pcie_slr1 -add {SLICE_X100Y0:SLICE_X150Y200} add_cells_to_pblock u_pcie_slr1 [get_cells u_pcie_ctrl] # 跨SLR信号使用Laguna set_property CROSS_SLR TRUE [get_nets u_ddr_ctrl/data_to_pcie]注意Laguna寄存器的使用需要手动实例化或通过VIVADO的自动插入功能。在XDC中设置CROSS_SLR属性只是告诉工具这条信号需要跨SLR具体实现由工具决定。7. 什么时候不该用PBlock三个反模式7.1 设计还没收敛就急着画PBlock很多新手在综合后看到时序报告不好第一反应就是画PBlock。但PBlock是布局阶段的约束它不能解决RTL层面的问题。如果关键路径的延迟主要来自逻辑级数比如组合逻辑太长PBlock帮不了你你需要的是插入流水线寄存器或优化RTL。判断方法打开Timing Report看违例路径的Logic Delay和Net Delay比例。如果Logic Delay占主导超过50%PBlock效果有限如果Net Delay占主导PBlock可能有帮助。7.2 模块太小PBlock反而增加约束如果一个模块只用了几百个LUT画PBlock的意义不大。因为小模块的布局自由度本来就高工具很容易找到好的位置。强行圈一个PBlock反而限制了工具的选择可能导致更差的布局。经验法则模块资源超过芯片总资源的5%时才考虑用PBlock。低于这个比例优先让工具自动布局。7.3 全芯片PBlock等于没约束有些人为了“保险”画一个覆盖整个芯片的PBlock把所有逻辑都圈进去。这等于没有约束因为工具可以在任何地方布局。PBlock的价值在于限制范围如果范围太大就失去了约束的意义。正确做法只对关键模块画PBlock其他模块让工具自由布局。这样既能保证关键模块的布局质量又不影响整体布局的灵活性。8. 从PBlock到时序收敛的完整检查清单在实际项目中我通常按照以下清单来检查PBlock的使用检查项检查方法合格标准PBlock资源利用率Report PBlock Utilization70%关键路径是否跨PBlockTiming Report Device高亮尽量不跨多Die器件是否跨SLRDevice视图SLR边界尽量不跨CONTAIN_ROUTING设置Properties窗口默认FALSE必要时TRUE增量编译锁定LOCK_PLACEMENT属性最终签核时TRUEPBlock形状Device视图规整矩形避免L形控制集数量Report Control Sets过多时扩大PBlock这个清单不是绝对的但能帮你避开大部分常见的坑。PBlock是一个强大的工具但它的威力来自于精确使用而不是滥用。每次画PBlock之前先问自己这个模块的瓶颈在哪里PBlock能解决这个问题吗圈多大、圈哪里、圈成什么形状想清楚这三个问题再动手。我在实际项目中的体会是PBlock用得好时序收敛时间可以缩短30%以上用得不好反而会引入新的问题。最稳妥的做法是先用工具自动布局跑一遍看看时序和拥塞情况再针对性地加PBlock。不要一上来就画一堆PBlock那样只会让自己陷入无尽的调试中。
阅读完成 · 觉得有帮助?
咨询建站