第二章:逻辑综合——Design Compiler 基本流程

逻辑综合,说白了就是把 RTL 代码翻译成门级网表。这一步做不好,后面时序收敛基本没戏。我刚开始做后端时,总觉得综合是前端的事,后来被坑过一次才明白——综合质量直接决定了芯片能不能跑起来。

2.1 Design Compiler 的基本流程

DC 的流程其实不复杂,核心就三步:读入、约束、输出。但每一步都有讲究。

第一步:准备数据

你需要准备好 RTL 代码、库文件(.db)、以及约束文件。我个人习惯把库文件路径写在 .synopsys_dc.setup 里,省得每次都要敲。

set search_path {. /home/libs/synopsys}
set target_library {tcbn28hpcplus.db}
set link_library {* tcbn28hpcplus.db dw_foundation.sldb}

第二步:读入设计

analyzeelaborate 命令。注意,analyze 会检查语法,elaborate 会展开层次结构。我遇到过有人直接用 read_verilog 跳过 analyze,结果综合出来的网表少了一堆逻辑——嗯,千万别省这一步。

analyze -format verilog {top.v sub_module.v}
elaborate top

第三步:施加约束

这是最核心的一步。没有约束,DC 就不知道往哪个方向优化。约束包括时钟定义、输入输出延迟、以及一些特殊路径。

第四步:编译与输出

运行 compile_ultra,然后写出网表和 SDC。

compile_ultra -no_autoungroup
write -format verilog -hierarchy -output top_synth.v
write_sdc top_synth.sdc

2.2 时序约束(SDC)编写

SDC 是综合的灵魂。你想想看,如果约束写错了,综合出来的网表时序全是假的,后面 STA 再怎么修也白搭。

时钟定义

最基本的,定义时钟周期和占空比。注意,create_clock 要指定时钟源端口,别漏了。

create_clock -name clk -period 10 [get_ports clk]
set_clock_uncertainty -setup 0.2 [get_clocks clk]
set_clock_transition -rise 0.1 [get_clocks clk]

输入输出延迟

这个我踩过坑。有一次我把输入延迟设得太紧,结果 DC 拼命优化组合逻辑,面积大了 30%。后来才明白,输入延迟要参考前级芯片的 Tco 和 PCB 走线延迟。

set_input_delay -max 2.5 -clock clk [get_ports data_in]
set_output_delay -max 3.0 -clock clk [get_ports data_out]

个人经验: 对于跨时钟域路径,记得用 set_false_pathset_clock_groups 告诉 DC 不要优化。我曾经忘了设 false path,结果 DC 花了两天时间优化一个根本不需要关心的路径——白白浪费了项目时间。

2.3 综合策略与优化技巧

DC 的优化策略有很多,但常用的就几种。我一般会根据设计规模来选择。

策略适用场景注意事项
compile_ultra高性能设计面积会变大,慎用
compile -map_effort high中等规模速度与面积的平衡
compile -incremental小改动只做增量优化,快

优化技巧一:分组约束

对于复杂设计,别把所有路径混在一起。用 group_path 把关键路径和非关键路径分开,DC 会优先优化关键路径。

group_path -name critical -from [all_inputs] -to [all_outputs] -weight 5

优化技巧二:避免过度优化

DC 有时候会为了满足时序而疯狂插入 buffer,导致面积爆炸。我建议设一个 set_max_area 约束,让 DC 在面积和时序之间找平衡。

set_max_area 0

注意,设成 0 表示面积越小越好,但别指望 DC 能自动收敛到最优——它只是尽量做。

避坑指南: 我曾经在一个项目中用了 compile_ultra -retime,结果 DC 把寄存器位置全改了,导致后端布局布线时发现时序完全对不上。后来我学乖了——除非你非常清楚 retime 的影响,否则别轻易用。

2.4 综合后网表质量检查

综合完别急着往后端送。先做几个检查,能省掉后面一堆麻烦。

检查一:网表完整性

check_design 看看有没有悬空端口、未连接的线。我遇到过有人综合出来的网表里有个模块的时钟没连上——结果仿真能过,但流片回来芯片不工作。

check_design -summary

检查二:时序报告

report_timing 的 slack。如果 slack 是负的,说明时序没满足。但别只看最差路径,也要看看分布情况。如果大部分路径 slack 都很好,只有一两条很差,那可能是约束写错了。

report_timing -max_paths 10 -nworst 5

检查三:面积和功耗

report_areareport_power 看看综合结果是否合理。如果面积比预期大了 50%,那肯定有问题——要么是约束太紧,要么是代码风格不好。

report_area -hierarchy
report_power -analysis_effort low

核心要点: 综合后的网表质量检查,说白了就是确认三件事——功能对不对、时序能不能跑、面积功耗是否可控。这三件事都过了,才能放心往后端送。

嗯,逻辑综合这部分内容其实挺多的,但核心就是这些。我个人觉得,综合做得好不好,关键看你对约束的理解深不深。别急着跑流程,先把 SDC 写对,后面会省很多事。