课程介绍:LINCS约束激增问题背景与课程目标
做数字芯片设计的朋友,十有八九都遇到过这种场景:晚上十一点,综合跑完了,打开日志一看——unconstrained endpoints 报了两千多个。你开始一条一条加 set_case_analysis,加到凌晨两点,编译又崩了。这种经历,我有过,而且不止一次。
约束激增,说白了就是你的 SDC 文件越写越长,但芯片时序反而越来越难收敛。这不是你一个人遇到的问题。在大规模 SoC 项目里,约束文件从几百行膨胀到几万行,是常有的事。我个人习惯先问一句:这些约束,真的每条都必要吗?
约束激增是怎么发生的?
我给你画个场景。一个典型的中高端 SoC,模块数量大概在 30 到 50 个。每个模块有自己的 RTL 设计师,每个人都要写自己的约束文件。然后到了顶层集成阶段,这些约束被拼接在一起。你想想看,五个人各写 50 条 set_case_analysis 和 false_path,最后叠在一起是什么效果?
- 重复约束:同一个信号被两条 set_case_analysis 同时指定
- 矛盾约束:有人设 false_path,有人设 max_delay,工具不知道该听谁的
- 冗余约束:芯片在测试模式下的约束,被复制了五份
- 遗漏约束:关键路径没人设,P&R 完全不知道要优化这
这就是典型的约束管理失控。我曾经见过一个项目,SDC 文件里光是注释掉的约束就占了三千行。没人敢删,因为不知道删了会出什么事。这不是技术问题,这是管理问题。
约束膨胀的连锁反应:约束越多,STA 运行时间越长。约束越多,综合工具越容易误判。约束越多,P&R 的优化策略越模糊。最终结果就是——流片回来后,芯片在某个 corner 上翻车了。
一个真实案例
我记得有次做一颗 AI 推理芯片,顶层 SDC 文件到了两万四千行。我们花了两周把所有约束重写了一遍,从结果中删掉了将近一半。具体怎么做的?我先从日志里捞出了所有 unconstrained 和 multi-driven 的警告,然后一条一条追根溯源。
举个例子,有个模块的约束文件长这样:
# 这是原始约束,看了让人头大
set_case_analysis 0 [get_ports scan_enable]
set_case_analysis 0 [get_ports scan_mode]
set_case_analysis 0 [get_ports test_mode]
set_case_analysis 0 [get_ports mbist_enable]
set_false_path -from [get_clocks clk_scan]
set_false_path -from [get_clocks clk_mbist]
set_false_path -from [get_clocks clk_test]
set_false_path -through [get_nets scan_chain_*]
set_false_path -through [get_nets mbist_chain_*]
你看看,这里 scan_mode 和 test_mode 其实是在不同阶段使用的。但工具不会帮你区分,它会同时应用所有约束。结果就是正常功能模式下的路径也被 false_path 了。我建议的做法是:按模式分组,每个模式只激活自己的约束集。
# 改造后的约束,按模式分组
set_case_analysis 0 [get_ports scan_enable]
set_case_analysis 0 [get_ports scan_mode]
set_false_path -from [get_clocks clk_scan]
# 功能模式:没有 false_path,只有真实时序约束
# 测试模式:单独文件,仅在测试时 include
就这么简单的一个改动,该模块的时序 WNS 从 -0.3ns 变成了 +0.07ns。你觉得为什么?因为 false_path 不会撒谎,但它会掩盖真正的问题。
什么是 LINCS 方法?
LINCS 是五个阶段的缩写。它不是那种花哨的方法论,而是一套能落到命令行的操作规程:
| 阶段 | 全称 | 核心动作 |
|---|---|---|
| L | Locate | 定位约束冲突和冗余 |
| I | Identify | 识别每条约束的来源和目的 |
| N | Normalize | 标准化约束写法,消除重复 |
| C | Consolidate | 合并同类约束,按模式分组 |
| S | Simplify | 化简冗余,只保留必要约束 |
你看这个顺序,从发现问题到最后清理干净,是一条清晰的流水线。我自己在之后的每个项目里都套用这个流程,再也没有被两万行的 SDC 逼疯过。
LINCS 的核心思想:约束不是越多越好。约束要精准、可追溯、按模式隔离。一个好的约束文件,应该像一份干净的设计文档,而不是一本混乱的笔记。
约束激增问题的演进路径
我画了一张图来展示约束问题是怎么一步步变严重的。从最初的一条约束,到最后变成一团乱麻,每个阶段都有不同的特征。
嗯,这里要强调一下。很多团队等到 P&R 跑不动了才去查约束,那时候已经晚了。正确的做法是在模块集成阶段就引入 LINCS 的 L 阶段——先定位问题,再去修。我自己就吃过这样的亏:一个项目在布局布线阶段发现约束冲突,结果回溯浪费了两周。从那以后,我在 RTL freeze 之前就做完 Locate 和 Identify。
课程目标:你学完能干什么?
这门课你别指望听完就能自动把两万行的 SDC 变成两千行。但学完之后,你会具备以下几个能力:
- 能快速定位约束冲突——不再靠肉眼扫几千行的 SDC
- 能识别冗余和矛盾的约束——知道哪些可以删,哪些必须改
- 能标准化约束写法——团队里所有人都按同一套规则写
- 能做约束按模式分组——功能模式、测试模式互不干扰
- 能把约束文件化简到最低必要程度——只保留能影响结果的约束
说白了,最终目标就是一个:让你的 STA 跑得更快、更准、更稳定。不会再有那种 check_timing 报了几百条 warning 的尴尬局面。
学习建议:每个阶段学完之后,找你们项目当前的 SDC 文件练练手。不用全改,挑一个模块,跑 check_timing,看你能找出几条真正的问题。这个过程中你会学到很多。
这就是第一章。我们不会马上进到具体的排查命令,但你现在应该对约束激增从哪来、到哪去,以及 LINCS 大概做什么,有了一个整体印象。后面每个阶段我们都会详细拆解,配合命令和工具实战。