找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4595

积分

0

好友

593

主题
发表于 1 小时前 | 查看: 3| 回复: 0

本文收获
✅ 分清 set_false_path / set_clock_groups / set_multicycle_path 三条例外约束的使用边界
✅ 搞懂「报告红了就加 false_path」错在哪,CDC 到底该怎么约束
✅ 避开 multicycle 最隐蔽的坑:hold 值忘了配,hold 违例被掩盖

做时序收敛久了,你会发现最诱人的一行 XDC 不是 create_clock,是 set_false_path

原因很简单。

跑完综合,report_timing_summary 一片红,红的路径五花八门,但网上给的答案高度统一:「这是假路径,加个 set_false_path 就行」。

你照着贴一行,报告秒绿。

那一刻的爽感,跟删了堆积一个月的未读邮件差不多。

但这一行恰恰最容易埋雷。

它告诉时序工具:这条路径不用查了。

工具很听话,真的不查了。

报告绿得越干净,你离真实风险越远。

等板子上电偶发出错,回头查,才发现是当初那行「让它变绿」的约束把问题盖住了。

这篇把XDC 例外约束三件套讲透:什么时候真的能用 set_false_path,什么时候该用 set_clock_groups,multicycle 那个没人提醒就必踩的 hold 坑在哪。

一、set_false_path 到底在说什么

一句话:让 STA 完全跳过某条路径的 setup/hold 检查。

适合它的只有三类「真不用管」的路径:

# 1. 复位释放路径:复位信号本身不用做时序收敛
set_false_path -to [get_pins -hierarchical -filter {NAME=~*rst_reg*/R}]

# 2. 测试/调试逻辑:比如 JTAG、chipscope 探针
set_false_path -from [get_ports test_mode]

# 3. 经过合格同步器/异步 FIFO 的跨时钟路径(配合 clock_groups 用,见第四节)

注意看第 1 条的范围:*rst_reg*/R,只匹配复位寄存器的 R 脚,不是 *rst* 通配整棵时钟树。范围写多宽,是后面最大的坑之一。

XDC 例外约束三件套对照:set_false_path、set_clock_groups、set_multicycle_path 用法边界

二、最常见的三个错误用法

错误 1:拿它处理所有跨时钟域

这是被引用最多的「标准答案」,也是错得最隐蔽的。

两个时钟域之间有些信号确实跨过去了,但跨的方式不同:有的经过两级同步器,有的直接进了异步 FIFO,有的只是普通寄存器对打。你把 clk_aclk_b 之间一刀切:

# 错误示范:两个时钟域之间所有路径全部豁免
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]

工具从此不再报告这两个域之间的任何时序问题,包括你漏同步的那些信号。

CDC 最怕的不是报红,是报了红没人看,更怕的是连红都不报。

跨时钟域的正解是 set_clock_groups,见第四节。

set_false_path 一刀切后果:跨时钟域漏同步信号不再报红

错误 2:范围写得太宽

get_clocks 一写就是一整片。

clk_a 域里可能有 200 个寄存器,其中只有 3 个是真正异步的,剩下 197 个是同步逻辑,跟 clk_b 有真实的数据依赖。

你一条 set_false_path 全豁免,等于把 197 条本应被检查的路径的检查全关了。

范围越宽,隐患越大。能精确到引脚就精确到引脚,能精确到单元就精确到单元,别偷懒写时钟域。

错误 3:把功能路径误判成假路径

异步 FIFO 的读写指针、握手协议的 req/ack,看着都「跨时钟」,但它们承载的是真实数据流,是设计里最需要时序保证的部分。

把它们 false 掉,FIFO 空满标志错乱、握手丢一拍,都是这种「绿油油的隐患」。

这类路径要么用 multicycle 放宽到真实周期数,要么用 max_delay 限定最大延迟,而不是完全不管。

三、什么时候真的该用

写每一条 set_false_path 之前,先过一道自问:这条路径为什么不需要时序检查?

答得上来的,才写。答不上来的,先别写,去读报告搞清楚它为什么红。

能答上来的典型就三类:复位释放(异步复位本来就不吃时钟沿)、测试/调试逻辑(只在特定模式下生效)、以及确实异步、且已经用同步器或异步 FIFO 正确处理的跨域信号。

这三类之外,set_false_path 基本都是在掩盖问题。

四、CDC 的正确姿势:set_clock_groups

处理跨时钟域,XDC 里有专门命令,叫 set_clock_groups

它声明「这两组时钟之间没有确定的相位关系」,工具会自动把组间路径当作异步处理,语义清晰、可维护、报告可读。

单 bit 信号跨域,标准三件套:

# RTL 里:两级同步器
# always @(posedge clk_b) begin
#     sync_ff1 <= data_from_clk_a;
#     sync_ff2 <= sync_ff1;
# end

# XDC 里:声明两域异步
set_clock_groups -asynchronous \
-group {clk_a} \
-group {clk_b}

# 让 Vivado 把同步器两个触发器紧挨放置,减小亚稳态窗口
set_property ASYNC_REG TRUE [get_cells u_sync/*]

多 bit 数据跨域,用异步 FIFO(格雷码指针),约束写法一样,把读写时钟划成两组。这里没有 set_false_path 什么事。

区别记牢:set_false_path 是豁免某条具体路径,set_clock_groups 是声明两组时钟无相位关系

后者是 CDC 的标准做法,前者只是它的一种特例表达,用错了地方就会变成错误 1。

set_multicycle_path hold 必须写 N-1 才能避免掩盖 hold 违例

五、那个没人提醒就必踩的坑:set_multicycle_path

最后说 multicycle。

它解决的问题是:数据不是每个周期都变,默认按 1 周期检查太严了,放宽到真实周期数。

比如一个模块每 3 个周期才采一次数:

# 正确写法:setup 放宽到 3,hold 必须跟着写 2
set_multicycle_path 3 -setup -from [get_cells u_slow/data_reg] -to [get_cells u_slow/out_reg]
set_multicycle_path 2 -hold -from [get_cells u_slow/data_reg] -to [get_cells u_slow/out_reg]

坑就在这:很多人只写 setup 那条。

set_multicycle_path -setup 3 会把 hold 检查按默认规则推到 N-1=2。表面看只是 setup 放宽了,实际上 hold 检查的窗口也大幅放松,真实 hold 违例被掩盖——报告全绿,时序却是坏的。

所以铁律只有一条:setup 与 hold 成对出现,hold = setup - 1,缺一条都在埋雷

FPGA 时序约束的水很深,先把这三条例外约束的分寸拿捏住,报告才值得信。更多时序收敛与 FPGA 实战资源,欢迎到云栈社区交流。




上一篇:AI自改进与破解风险齐发,Dario呼吁放慢前沿研究真的对吗?
下一篇:DDD 聚合根怎么画边界:订单支付的不变量、Outbox 与并发一致性实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-9-13 19:45 , Processed in 0.318624 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表