逻辑综合入门:DC工具、综合策略与时序约束基础
逻辑综合,说白了就是把 RTL 代码翻译成门级网表。你写的是 always @(posedge clk),DC 会把它变成一堆与门、或门、触发器的连线。这个过程听起来简单,但里面门道不少。我刚开始做后端时,总觉得综合是前端的事,后来发现——综合做不好,后端跑死也修不了时序。
DC 工具到底在干什么?
Design Compiler 是 Synopsys 家的旗舰综合工具。它的核心任务就三件事:
- 翻译:把 Verilog/VHDL 转成 GTECH 网表(通用工艺无关的网表)
- 映射:把 GTECH 网表映射到目标工艺库的单元上
- 优化:在面积、时序、功耗之间找平衡
我见过不少新人,上来就丢一个 compile 命令,然后等着出结果。嗯,这样也能跑,但出来的网表质量嘛……你想想看,DC 有几十个优化选项,你不告诉它重点优化什么,它只能按默认策略来。默认策略往往不是你要的。
DC 综合的输入输出
- 输入:RTL 代码 + 工艺库 + 时序约束
- 输出:门级网表 + 时序报告 + 面积报告
- 中间产物:GTECH 网表、DDC 文件(可增量综合)
三种综合策略,你选哪种?
DC 提供三种综合策略,我按实际项目中的使用频率排个序:
| 策略 | 适用场景 | 我个人的看法 |
|---|---|---|
| Top-down | 小模块、单芯片 | 简单直接,但大芯片跑不动 |
| Bottom-up | 大芯片、多模块 | 我最常用的方式,灵活可控 |
| Incremental | ECO、微调 | 修时序时救命用的 |
Top-down 综合:把整个芯片当黑盒,一次跑完。好处是全局优化好,坏处是——我遇到过 500 万门的模块,Top-down 跑了两天没出结果。后来拆成 Bottom-up,半天搞定。
Bottom-up 综合:先综合每个子模块,设好边界约束,再拼起来。这样做的好处是:
- 每个模块可以单独调优
- 并行跑,节省时间
- 某个模块改了,只重跑那个模块就行
Incremental 综合:在已有网表上做增量优化。我曾经有个项目,时序差了 20ps,重新跑一遍综合要 6 小时。用 Incremental 模式,只花了 40 分钟就修好了。
我的建议:新项目先用 Top-down 跑一版,看看整体时序和面积。然后切到 Bottom-up 做精细调优。最后用 Incremental 收尾。
时序约束,综合的灵魂
没有约束的综合,就像没有地图的导航。DC 不知道你要跑多快,它只会往面积最小的方向优化。结果就是——网表面积很小,但时序一塌糊涂。
最基本的时序约束包括:
# 时钟定义
create_clock -name clk -period 10 [get_ports clk]
set_clock_uncertainty -setup 0.2 [get_clocks clk]
set_clock_latency -source 0.5 [get_clocks clk]
# 输入输出延迟
set_input_delay -max 2.0 -clock clk [get_ports data_in]
set_output_delay -max 1.5 -clock clk [get_ports data_out]
# 伪路径
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
# 多周期路径
set_multicycle_path -setup 2 -from [get_pins reg_a/CK] -to [get_pins reg_b/D]
这里我重点说几个容易踩坑的地方:
时钟不确定性:很多人只设 setup 的 uncertainty,忘了 hold。我曾经吃过这个亏——综合时 hold 没设 uncertainty,结果后端修 hold 修到崩溃。
输入输出延迟:这个值怎么设?我的经验是:看芯片的接口协议。比如 DDR 接口,你要算清楚 PCB 走线延迟、片外负载、时钟偏斜。别随便填个 2ns 就完事。
伪路径:跨时钟域的路径,一定要设 false_path。不设的话,DC 会花大量时间去优化这些根本不需要关心的路径,浪费资源。
注意:多周期路径的约束,setup 和 hold 要分开设。很多人只设了 setup 的 multicycle,hold 没设,结果 hold 检查还是按单周期来算,导致误报。
综合流程,一步都不能少
我总结了一套综合流程,项目里用了好几年:
- 读入设计:
read_verilog或read_vhdl,记得加上-sv选项读 SystemVerilog - 链接库:
link命令,检查所有实例化是否都能找到对应的库单元 - 加约束:时钟、IO 延迟、伪路径、多周期路径
- 选择策略:Top-down / Bottom-up / Incremental
- 编译:
compile_ultra或compile - 分析结果:看时序报告、面积报告、功耗报告
- 输出网表:
write -f verilog写出网表,write_sdc写出约束
这里面最容易出问题的是第 2 步。我遇到过好几次,link 时报错说某个模块找不到。查了半天,原来是库路径没设对。所以我现在习惯在脚本开头就设好 search_path 和 target_library。
综合后的检查清单
综合跑完,别急着往后端交。先过一遍这个清单:
- 时序报告里有没有 setup 违例?hold 违例?
- 面积是不是在预期范围内?
- 有没有未约束的路径?
report_analysis_coverage看一下 - 有没有悬空端口?
report_bus检查一下 - 时钟门控有没有正确插入?
我一般会跑一个 check_design,看看有没有设计规则违例。这个命令会检查最大扇出、最大电容、最大转换时间等。如果这些不过,后端会很难受。
小技巧:综合完成后,用 write -f ddc 保存一份 DDC 文件。这样下次做增量综合时,可以直接读 DDC,不用重新编译,能省不少时间。
知识结构图:逻辑综合的核心脉络
这张图把逻辑综合的核心脉络串起来了。你从 DC 工具出发,往左走是工具本身的能力,往中间走是策略选择,往右走是约束设置。三者缺一不可。
最后说一句:综合不是一次就能搞定的。我一般会迭代 3-5 轮,每轮看报告、调约束、改代码。别指望一次跑出完美结果,那不太现实。