☰
set_false_path别乱用:STA时序约束原理、案例与选型边界
2026/10/6 12:04:39 网站建设 项目流程

入职第三年,我第一次独立负责一颗芯片的时序收敛。综合工具在一次全编译之后甩给我一千多条violation,我盯着report看了十分钟,脑子里只剩一个念头:要不全给它set_false_path算了。

带我的人只问了一句话:“这些路径,你确定它们真的假吗?”

这句话我记到现在。set_false_path确实是STA里被用得最频繁、也最容易被用坏的SDC约束。用对了,它能帮你把设计里那些“不需要检查、也确实没法检查”的路径排除掉,让综合、布局布线工具把精力全部集中在真正需要收敛的路径上;用错了,等于把功能bug直接送进流片,而且没有任何告警。

这篇文章不打算从SDC手册的第一章开始讲,而是直接围绕set_false_path这个约束,把它的原理、语法、真实案例、选型边界、翻车现场一次说透。适合正在做数字IC后端、或者刚接手时序收敛、想在STA上少走弯路的工程师。文章里所有案例都来自真实项目,我会尽量把当时的环境、约束写法和排查思路还原出来,你可以直接对着自己的工程去对照。

1. STA在查什么:setup/hold这条红线是怎么算出来的

1.1 一条数据路径的完整旅程:发射沿、组合逻辑、捕获沿

要理解set_false_path,先得明白STA默认在查什么。任何一条寄存器到寄存器的路径,STA都会按这样一个模型来检查:发射沿(launch edge)把数据从源寄存器的Q端推出,数据穿过组合逻辑和走线,最终到达目的寄存器的D端;捕获沿(capture edge)在下一个时钟周期到达目的寄存器的时钟端,把D端数据采进去。

这段旅程里,数据必须在捕获沿之前足够早地稳定下来,这叫setup检查;同时,在捕获沿之后的一小段时间内不能变化,这叫hold检查。前者管的是“数据来不来得及”,后者管的是“数据别变得太快”。STA把设计里所有此类路径遍历一遍,拿实际的路径延迟去和时钟周期、库单元的setup/hold时间对比,算出slack。slack为负就是violation,收敛不了就不能流片。

1.2 slack公式里每一项背后的物理含义

很多刚接触STA的同学看到公式就头疼,其实setup的slack可以简化成这么一句话:

setup slack = 时钟周期 + 时钟偏斜 - 发射延迟 - 组合逻辑延迟 - 建立时间 - 时钟不确定度

逐项拆开看:Tcycle是时钟周期,这是设计目标;Tskew指的是捕获时钟相对发射时钟的偏斜,时钟树做得越平衡,这一项越接近零;Tcko是寄存器本身从时钟到Q输出的内部延迟;Tcomb是组合逻辑和走线延迟,这是后端工具优化的主要对象;Tsetup是库单元要求的建立时间;Tuncertainty是时钟抖动和工程师自己加的悲观量。hold的公式类似,但它是用“数据最短保持时间”去和“捕获沿是否来得太早”比较,不需要乘时钟周期。

理解了这几项,你就会明白:STA本质上是在算一道“数据到达时间”和“数据要求到达时间”的比较题。工具默认认为每一条路径都需要做这道题,不管这条路径在功能上有没有意义。

1.3 为什么SDC要声明“例外”:工具的默认假设与你的真实设计差在哪

工具是“笨”的,它不知道你的设计意图。它默认所有寄存器之间都有关系、所有端口都按时钟约束工作、所有组合逻辑都必须在单周期内完成。但真实设计里总有大量路径不符合这些默认假设:

  • 输入引脚来自外部芯片,和内部时钟根本没有相位关系;
  • 某个信号在功能模式下恒为0,只有在测试模式下才翻转;
  • 某些寄存器只在芯片初始化时写一次,之后再也不会变化;
  • 两个时钟域之间完全是异步的,没有公共的时序参考点。

这些路径如果让工具按默认规则去查,结果必然是成百上千条violation,而且这些violation根本没法通过优化逻辑来修复,因为问题不出在延迟太大,而出在“检查本身没有意义”。SDC里各类路径例外约束,就是用来告诉工具:这些路径的行为和你的默认假设不一样,请按我说的方式处理。

2. set_false_path到底做了什么:它不是“放宽”,是“注销”

2.1 最容易搞错的认知:false path ≠ 慢路径

我见过太多人把set_false_path理解为“让这条路径慢一点也没关系”。这是完全错误的。

打个比方:考试卷子上有一道题,你说“这道题我放弃,不算分”,这是false_path;你说“这道题我做得慢,但必须做对”,那是set_multicycle_path;你说“这道题我多拿点时间,但答案必须正确”,那是set_max_delay。false_path是直接把这道题从试卷里划掉,工具对这条路径的setup和hold都不再检查,流程里也不为它做任何时序优化。

划掉以后,这条路径在工具眼里就“不存在”了。它不会被report_timing报出来,布局布线时工具不会把它当时序关键路径去处理,综合时也不会为了它去优化中间的组合逻辑。

2.2 SDC语法与三种最常用的写法

set_false_path在SDC里属于path exception,基本语法是:

set_false_path [-setup] [-hold] [-from <list>] [-through <list>] [-to <list>]

-from、-through、-to都可以省略,省略表示“对所有满足条件的路径生效”。三种最常见的写法:

# 写法1:从端口到所有寄存器(典型用于模式选择信号) set_false_path -from [get_ports test_mode] -to [all_registers] # 写法2:从一个时钟域到另一个时钟域(跨异步时钟域) set_false_path -from [get_clocks uart_clk] -to [get_clocks sys_clk] # 写法3:穿过某个mux选择端的路径(精确到一个pin) set_false_path -through [get_pins u_top/u_mux0/U0/S]

如果是FPGA,Vivado里对象集合写法略有差别,比如用get_cells配合-hier做层次匹配,但set_false_path本身的关键字和语义与PrimeTime、Tempus这些工具是一致的。还有一种少见但有用的变体是只关setup或只关hold:

# 只关掉setup检查,hold照查 set_false_path -setup -from [get_clocks clk_a] -to [get_clocks clk_b]

这种写法在极少数“数据提前到达一定没问题,但晚到可能有事”的场景会用到,日常基本用不上,知道有这回事就行。

2.3 多个例外同时命中时,工具按什么优先级裁决

一条路径可能同时被多个例外覆盖,比如你既写了false_path,又写了multicycle_path。SDC里例外之间是有优先级的,我按常用工具普遍认可的规则整理如下:

优先级约束作用
1(最高)set_disable_timing直接禁用某个timing arc,路径根本不被计算
2set_false_path不做setup/hold检查
3set_max_delay / set_min_delay覆盖默认时钟周期约束
4set_multicycle_path调整检查启动沿与捕获沿之间的周期数
5(最低)create_clock等时钟基础约束一切检查的基线

也就是说,如果同一条路径同时设了set_false_path和set_multicycle_path,工具按最高优先级执行,直接不检查。这条规则决定了你在写约束时必须想清楚:是不是有个更大的“渔网”把你的精确约束盖住了。不同EDA工具对max_delay和multicycle之间的局部细节处理略有差异,动手前查一下所用工具手册,但false_path高于multicycle这一点基本是通行规则。

2.4 设了false_path后,工具到底少做了哪些事

很多人以为false_path只是“报不报violation”的区别,其实不止。设完之后,对综合、布局布线、时序收敛的影响是实打实的:

  • report_timing不再报这条路径的violation,timing summary里看不到它;
  • 综合工具不会为了这条路径去插入缓冲器、调整单元驱动强度、优化逻辑级数;
  • 布局布线时工具不会给中间的单元分配优先级,不会为了让这条路径收敛而牺牲其他路径的资源;
  • 工具运行时间下降,拥塞(congestion)往往也会改善。

反过来想,风险也在这一条上:一旦设错,工具完全不管,没有任何人会提醒你。这就是为什么说false_path是把双刃剑——它太“好用”了,以至于很多人拿它当时序violation的删除键,而不是约束。

3. 真实案例一:UART异步接收端的两级同步器

3.1 问题现场:从虚拟时钟到sys_clk域的一千条violation

这是我在一颗MCU芯片上遇到的实际问题。UART的接收引脚uart_rxd从外部进来,芯片内部用100MHz的sys_clk采样。由于外部数据和sys_clk完全没有相位关系,RTL里放了一个经典的两级同步器:sync_ff1先采原始输入,sync_ff2再采sync_ff1的输出,然后才把数据交给UART接收状态机。

当时的约束文件给uart_rxd这个端口定义了一个虚拟时钟,频率按UART波特率时钟给了个14.7456MHz,然后又set_input_delay设了一个大概一个周期的输入延迟。结果STA一跑,从虚拟时钟的启动沿到sys_clk域的捕获沿,setup slack全线是负的,最差的大约-30ns。整个timing report里UART相关的violation有上千条,占了全芯片违规的八成。

为什么修不动?因为这根本就不是延迟问题。uart_rxd外部数据和sys_clk的相位关系每个bit都在变,所谓input delay只是拍脑袋给的经验值,setup检查从物理上讲就没有意义。你让后端工具优化这条路径,优化一万遍也不可能把两个时钟域之间不存在的相位关系“优化”出来。

3.2 正解:只把“到第一级同步器”设成false path

正确做法是把“从异步输入端口到第一级同步器输入”的路径设为false path:

# uart_rxd是异步输入,先过两级同步器 # 只对“到sync_ff1的D端”设false_path set_false_path -from [get_ports uart_rxd] \ -to [get_pins u_uart/u_sync/sync_ff1_reg/D]

为什么只到第一级?因为第一级同步器本身就是用来吸收亚稳态的。外部数据什么时候跳变、是否正好落在采样窗口上,设计上就是不管的,所以这一段的setup/hold本来就不成立。真正要保证的是sync_ff1的输出传到sync_ff2的路径——如果这段不满足时序,亚稳态可能穿透第二级继续向后传播,同步器就白做了。所以sync_ff1到sync_ff2这段路径必须正常检查,而且后端布局时还要把它们放得很近、走线很短。

如果芯片里有很多类似的异步输入,比如一组GPIO都接同步器,可以用通配符批量处理:

set_false_path -from [get_ports {gpio_in[*]} ] \ -to [get_pins -hier *sync_*_reg/D]

注意这里仍只到同步寄存器那一级,千万不要把“到所有寄存器”当省事的写法往下套。

3.3 常见错误:把整条同步链都设成false path

对照我见到的实际工程,最容易犯的错是把两级的时序一并划掉:

# 错误示范:把整条同步链都划掉 set_false_path -from [get_ports uart_rxd] \ -to [get_pins u_uart/u_sync/sync_ff2_reg/D]

这么写了以后,sync_ff1到sync_ff2之间不检查,工具也就不会在布局时把这两个触发器放近。结果就是MTBF无法保证,高辐射环境或者外部信号正好踩在窗口边缘的时候,亚稳态透过两级同步器的概率显著上升,芯片表现为偶发性的误码或死机。这种bug在仿真里永远复现不出来,只有到了现场才冒头,而且极难定位。

所以这个案例里最关键的一句话是:false_path的范围要精确到“问题的边界”,精确地划掉异步的那一段,而不是把整条链都捆在一起划掉。这也是你对SDC里每个from/to对象都要有清晰物理认知的原因。

3.4 进阶提醒:多bit跨时钟域不能靠多个单bit同步器硬凑

顺便说一个相关性很强的坑。好几bit的控制信号要从异步时钟域传到sys_clk域,如果每个bit都单独加两级同步器,然后一股脑把所有这些同步器的入口都设成false path,看起来似乎没问题,实际上隐患很大。多bit信号在跨时钟时,每一bit的同步器输出可能在同一个捕获沿上还是新的、还在变化的、已经稳定的状态里交错,组合在一起会出现一个“不是任何一拍合法值”的中间态,功能性上直接挂掉。

这类多bit跨时钟域的正确做法是FIFO加握手,或者用异步FIFO、格雷码指针同步。数据路径本身是有意义的路径,不能因为“在这个时钟域里产生、在那个时钟域里消费”就随手false掉。很多人把“跨时钟域”等同于“false path”,这是最容易把设计埋掉的一个等式。

4. 真实案例二:test_mode、scan_enable这类“功能模式恒定”的信号

4.1 场景:DFT信号连进了功能逻辑

再讲一个更常见的场景。芯片为了可测试性,会引入test_mode、scan_enable这类DFT信号。它们会连接到功能逻辑里的mux选择端、时钟门控逻辑、甚至数据通路上,用来切换功能模式和测试模式。在功能状态下,这两个信号由芯片外部拉死:test_mode恒为0,scan_enable恒为0。

但STA不知道这件事。工具看到的是一个普通端口,默认它会和内部所有寄存器建立路径检查。结果就是test_mode和scan_enable端口到几百上千个寄存器D端的路径都被查了一遍,还因为输入端口没有合理的input delay,报出一堆莫名其妙的violation或者无约束路径。这类violation看起来很多,实际上完全没有意义——因为真机功能模式下,这两个信号根本不会翻转,不存在数据从它们出发的“功能事件”。

4.2 为什么可以设为false path,前提又是什么

把这类信号设成false path的合理性在于:它们的功能模式行为是“恒定”,路径上没有真实的数据翻转,那么基于翻转产生的setup/hold检查确实不适用于功能模式。

但这里有一条硬前提:必须是真恒定。很多工程师不假思索地写了下面这行:

# 功能模式下test_mode恒为0,这条路径不检查 set_false_path -from [get_ports test_mode]

然后过了三个月,前端在test_mode上接了功能逻辑,让它在正常运行的一个特殊阶段翻转一次,做芯片内部的一个模式切换。这时候你再回头看这条false_path,它已经悄悄把一条真实路径盖住了。工具不报警,仿真因为激励没跑到那种情况也不报警,直到样片测试才暴露。

所以每写一条“功能模式恒定”的false_path,都得有RTL层面的设计依据,最好能在SDC里把设计依据写清楚,方便事后review的人一眼看出“这个恒定假设还成不成立”。

4.3 约束写法与范围控制

对test_mode、scan_enable这类端口的常规约束有两种流派。一种是直接用false_path:

# 功能STA:这两个端口在功能模式下恒为0 set_false_path -from [get_ports test_mode] set_false_path -from [get_ports scan_enable]

另一种更“干净”的做法是用set_case_analysis把端口固定成常数值:

set_case_analysis 0 [get_ports test_mode] set_case_analysis 0 [get_ports scan_enable]

两者区别在于:case_analysis是把端口值固定在0,工具在延迟计算时只激活对应的timing arc,mux不选的路径直接不计算,连“路径存在”都不存在;false_path只是不检查这两条路径,但路径本身在timing graph里还是存在的。对模式选择信号来说,case_analysis在语义上更贴合“恒定”的本意,也更利于下游工具(功耗、形式验证)理解设计。对纯粹不想检查的异步路径,则用false_path。

4.4 DFT/scan模式不能直接复用功能模式的false path

这是我在多个项目code review里反复强调的一点。很多团队的SDC是按一个文件从头用到尾的,功能模式里写了对test_mode、scan_enable的false_path,到了scan模式的STA还接着用。结果就是scan模式下,scan_enable明明是要翻转的扫描移位控制信号,它的时序却被当成了“假路径”完全不检查。扫描链数据能不能在移位时满足时序、能不能正确捕获,全都成了一笔糊涂账。

正确做法是SDC按模式拆分:func.sdc、scan.sdc、mbist.sdc各管各的。func.sdc里的false_path只对功能模式负责;scan.sdc里要把scan_enable当作真实路径去约束并检查。如果你发现自己的项目里还在一份SDC跑所有模式,建议趁早改掉,这个弯绕回来的成本比一开始分开写高得多。

5. 真实案例三:软件复位与“一次性配置”路径

5.1 场景:软复位寄存器把外设的复位树拖出了长组合链

第三个案例来自一颗带CPU核的SOC。外设模块里有一个soft_rst_reg,软件通过APB总线写1再写0来复位该外设。这个寄存器的输出没有直接接FF的异步复位端,而是经过一大串复位分配逻辑,生成各个子模块的同步复位信号,再进到数据通路里。复位树的组合逻辑级数非常深,导致从soft_rst_reg/Q端到下游所有FF的D端路径,在100MHz下出现了几十条setup violation。

从功能上讲,这条路径真的假吗?我们梳理了使用场景:软件配置soft_rst寄存器时,外设模块本身处于复位状态,它的功能时钟被门控;软件先把复位配置好,再等上若干个时钟周期、确认配置稳定后,才通过另一个使能寄存器把外设放出来开始工作。也就是说,在任何一个真正发生功能捕获的时钟沿上,soft_rst这条路径的数据早就稳定了。STA拿一个周期去卡这条路径,卡的是“配置窗口内”而不是“功能窗口内”的事,这个检查没有意义。

5.2 约束写法:需要硬保证的false path

针对这类“一次性配置”路径,约束可以这样写:

# soft_rst_reg只在配置窗口内变化,外设时钟门控,配置后多拍稳定 # 参考需求单:PERIPH-0173(复位释放时序分析见doc) set_false_path -from [get_pins u_sys/u_apb/soft_rst_reg/Q] \ -to [all_registers]

讲清楚这里的两个硬保证:一是配置发生时外设时钟确实被门控,不存在“配置数据变化那一拍还被同一时钟采走”的竞争;二是配置完成后有足够的空窗周期,保证数据在功能使能到来之前已经稳定。这两条如果有一条不成立,这条false_path就是错的。

这类约束比前两个案例更危险,因为它依赖的不是“信号永远不变”,而是“变化发生的窗口和功能捕获窗口物理上错开”。这种依赖只有在RTL、验证、架构三个层面都被确认过之后,才允许落到SDC里。我在实际review时,对这类约束的要求是必须能指到一份文档或一个RTL注释,证明这个空窗确实存在。

5.3 翻车故事:把“低频翻转”当“恒定”的教训

有一次接手的项目里,某人给一个分频系数寄存器的数据路径留了这么一条false_path,理由是“这个寄存器只有系统初始化时配一次,平时不动”。但debug下来发现,这个分频系数在实际运行中会被软件动态改写,用于调整外设的输出频率。改写发生在功能运行期间,下一拍分频计数器就要按新系数工作——也就是说,改写那一拍就是真实的捕获,和普通数据路径没有任何区别。

当初写约束的人把“改得少”和“不用查”画了等号。低频翻转确实不容易导致功能问题,但它不是“不需要满足时序”的理由。那条路径后来被删除,真实的violation暴露出来,最后由架构师用multicycle加流水线的方式去解决。这个教训值得记住:判断一条路径是真是假,不看它翻转的频率,而看它在功能上是否要求“在某个捕获沿上输出有效且确定的值”。只要有一个捕获沿要求它有效,它就是真路径。

6. 选型边界:false_path、multicycle_path、clock_groups、case_analysis怎么选

6.1 一张表看清四种约束的语义差异

做STA的人迟早会面对一个问题:同样是路径不收敛,到底该用哪一种例外?我用一张表说明它们的核心差异:

约束核心语义典型场景最大风险
set_false_path该路径不需要时序检查异步同步器、模式恒定信号、复位空窗掩盖真实功能bug
set_multicycle_path路径需要多个周期完成大乘法器、RAM读、长组合链多周期假设不成立
set_clock_groups -asynchronous两组时钟之间无相位关系异步时钟域全局声明掩盖漏同步的CDC
set_case_analysis将端口/引脚固定为常数模式选择、PLL lock信号与真实硬件行为不符
set_max_delay / set_min_delay覆盖默认周期的特定约束IO边界、跨时钟路径特殊要求约束设得不符合物理实际

选型的原则很朴素:先问“这条路径在功能上到底需不需要满足时序”,需要,就用multicycle或者正常收敛;不需要,再看“是哪一种不需要”,是异步的,用false_path;是恒定的,用case_analysis;是一组时钟整体无关系,用clock_groups。

6.2 多周期路径的正确姿势:setup N 之后记得hold N-1

很多刚入门的人分不清false_path和multicycle_path。multicycle_path的意思是:这条路是真的,但数据有多个周期的时间去传播。比如一个组合乘法器,输入数据每两个时钟周期更新一次,那么默认按单周期检查必然violation,正确做法是:

# 数据每2个周期更新一次,组合逻辑需要2个周期完成 set_multicycle_path -setup 2 \ -from [get_clocks clk_a] \ -through [get_pins u_mul/mul_out] \ -to [get_clocks clk_b] # 注意:设了setup 2,必须同步设hold 1 set_multicycle_path -hold 1 \ -from [get_clocks clk_a] \ -through [get_pins u_mul/mul_out] \ -to [get_clocks clk_b]

这里有一个初学者必踩的坑:只写setup多周期,不写hold。默认的hold检查仍然发生在同沿,数值上会变得过分严格,导致本来合理的hold也会被报成violation。行业惯例是setup改成N,hold就要跟着改成N-1。这也是multicycle_path比false_path复杂的地方——它不是在“删题”,而是在“重新定义题的边界”。

6.3 set_clock_groups与false_path的覆盖范围之争

set_clock_groups -asynchronous是另一个容易和false_path混在一起的概念。它声明两组时钟之间完全没有时序关系,工具会隐式地对所有跨这两组时钟的路径不做检查。写法上是一条命令覆盖全局:

set_clock_groups -asynchronous \ -group [get_clocks {clk_a clk_a_derived}] \ -group [get_clocks {clk_b}]

而在实际项目里,工程派别大概分两种:一种喜欢用clock_groups做全局声明,配合一份CDC审查清单兜底;另一种喜欢逐条写false_path,让SDC文件里每一个例外都能对应到RTL里一个同步器或一个设计注释。

我个人的偏好是第二种。原因是review的时候,“每一个例外都有据可查”比“一个全局命令省事”重要得多。全局clock_groups一旦写下去,它覆盖的所有跨时钟路径都沉默了,如果里面有一条漏了同步器、没有真正异步化处理,你根本不知道。等芯片回来偶发故障,再想靠review找回那条路径,成本高得离谱。如果你一定要用clock_groups,那么请务必配套做完整的CDC交叉点审查,并且把审查结果存档。

6.4 case_analysis和false_path:一个管“值”,一个管“路径”

再补充一下case_analysis和false_path的使用边界。case_analysis是给某个端口或引脚赋予一个固定逻辑值,工具据此推导下游逻辑行为,只激活与这个值一致的部分;false_path则是针对路径本身的例外,不改变任何逻辑值。

对test_mode这类模式选择信号,用case_analysis更干净,因为它连mux里没有被选中的那一路的延迟计算都省了。但对异步输入信号,就不能用case_analysis——它不是恒定电平,只是相位不定,你需要的是“不检查”,而不是“固定成0”。选错工具的结果往往是约束文件看着整齐,实际行为和设计意图完全拧着。

7. 误用false_path的翻车现场与自查清单

7.1 翻车一:一条全局命令掩盖了漏同步的CDC

这是一个真实的debug经历。某子系统把两个异步时钟域整体设了false_path,理由是“反正跨时钟域,本来就没法查”。但CDC审查时漏掉了一条路径:clk_a域有个寄存器输出直接进了clk_b域的组合逻辑,中间没有同步器,也没有FIFO。正常情况下STA会把这个跨时钟路径报出来,即使不报violation,至少也会在报告里暴露这个交叉点。可那条全局false_path把所有跨时钟路径全部塞住了,漏同步的事实被隐藏得干干净净。

芯片回来后表现为偶发死机,现场复现概率极低,最后是通过逐条对照CDC交叉点清单才定位到问题。从那时起我对全局性的false_path就非常警惕。如果你发现自己写下了一条“从clk_a到clk_b所有路径”的约束,先花半小时把两个时钟域的所有交叉点过一遍,确认每一个都有同步机制。

7.2 翻车二:范围设太宽,把同域真路径一起注销

另一个常见问题是范围写得太宽。比如设计师本意只想划掉“从UART发送模块到同步器的路径”,结果写成了:

# 危险写法:范围太宽 set_false_path -from [get_clocks uart_clk] -to [get_clocks sys_clk]

如果这两个时钟域里除了同步器路径之外,还有一条经过异步FIFO读指针同步、但数据通路本身仍然需要时序约束的路径,这条命令就会把所有跨时钟路径全部划掉,FIFO相关检查形同虚设。

约束范围要尽可能窄。能精确到pin的地方不写到module,能到module的地方不写到clock group。窄范围约束更难写,但它逼着你把每一条例外都想清楚,这正是它价值所在。

7.3 翻车三:把“改得少”当成“不用查”

在5.3里已经讲过分频系数的案例,这里再强调一遍量化思维:信号翻转频率和路径真假没有必然关系。判断标准永远是“在某个捕获沿上,功能是否要求这个数据有效且确定”。如果要求,即使一年只变一次,也是真路径;如果不要求,即使每个周期都在变,也可以合理使用例外。把“慢”和“假”混为一谈,是新手写false_path最危险的心智模型。

7.4 动手前逐条对照的检查清单

最后把我整理的自查清单分享出来。每次往SDC里加一条set_false_path之前,我都会逐条过一遍:

  1. 这条路径在功能模式下是否真的不影响功能?是恒定、异步、还是空窗配置?原因能否用一句话说清。
  2. 我依赖的“恒定”或“空窗”假设,有没有RTL、验证或架构上的文档支撑?还是我拍脑袋想的。
  3. 范围能否再窄?能精确到pin就不写到module,能到module就不写clock group。
  4. 这条例外会不会和已有例外重叠?用report_exceptions检查全项目的路径例外,防止高优先级约束盖掉本意。
  5. SDC注释里是否写明了理由、责任人、需求单号?
  6. 跑完布局布线后,有没有做过一次反向验证:把新增的false_path临时去掉,确认暴露出来的violation正是你预期要隐藏的那几条?这个方法叫“负向验证”,是我认为性价比最高的SDC检查手段。

实际工具操作上,每次做完约束变更,我习惯把下面几条命令的产物存档:report_exceptions列出全部例外;report_clock_interaction看时钟间关系;report_timing_summary看整体收敛情况。有了这些基线,后续再有人改动约束,diff一眼就能看出来。

做SDC review这些年,我最深的体会是:set_false_path不是用来“删violation”的,而是用来“表达设计意图”的。每写一条false_path,都是在向工具、向后端、向下一代接手的人声明:这里,我们设计上就是不管的。声明要有依据,要有注释,要经得起追问。我现在的习惯是,拿到一份新项目的SDC,第一件事就是把所有set_false_path导出来,对着RTL逐条问为什么。答得上来、有注释、有单号的留下;答不上来的当场删掉,让工具重跑,让真相浮出水面。

宁可看到几百条真实的violation,也不留一条说不清道理的false_path。这个原则帮我避开了很多坑,也希望对你管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询