逻辑综合(Synthesis):DC(Design Compiler)综合流程

逻辑综合,说白了就是把我们写的RTL代码,翻译成门级网表。这一步是数字后端设计的真正起点。我刚开始接触DC时,总觉得它就是个黑盒子——RTL进去,网表出来。后来踩了不少坑才明白,综合的质量直接决定了芯片能不能收敛、能不能跑出性能。

今天我就把DC综合的核心流程拆开来讲。你跟着走一遍,基本就能上手了。

综合三要素:RTL + 约束 + 库

DC综合其实就干三件事:读入你的RTL代码,施加设计约束,然后基于工艺库进行编译优化。这三者缺一不可。

核心公式:

综合结果 = f(RTL描述, 时序约束, 工艺库)

任何一个环节出问题,结果都不会好。

我个人习惯把综合流程分成五个步骤:

  1. 准备数据——RTL代码、工艺库、约束文件
  2. 读入设计——DC加载RTL和库
  3. 设置约束——时钟、输入输出延迟、面积等
  4. 编译优化——DC进行逻辑映射和优化
  5. 输出结果——网表、报告、SDF等
DC综合五步流程 ① 准备数据 ② 读入设计 ③ 设置约束 ④ 编译优化 ⑤ 输出结果 关键输入 RTL代码 → 工艺库(.db) → 约束文件(.sdc) → 脚本(.tcl) 关键输出 门级网表(.v/.vg) → 时序报告(.rpt) → SDF文件

第一步:读入RTL和库

DC读RTL的方式有两种:analyze + elaborate,或者直接用 read_verilog。我个人更推荐前者,因为analyze会做语法检查,elaborate会展开层次结构,方便后续调试。

# 方式一:analyze + elaborate(推荐)
analyze -format verilog {top.v sub_module.v}
elaborate top

# 方式二:直接读入
read_verilog {top.v sub_module.v}
current_design top
link

小技巧:读入后记得跑一下 check_design。我曾经有一次漏了一个模块的端口连接,综合出来的网表全是悬空线,查了半天才发现。check_design能帮你提前发现这类低级错误。

第二步:设置约束——这是最关键的环节

约束设得好,综合就成功了一半。我见过太多新手随便写个时钟周期就跑了,结果后端布局布线时发现时序根本收不拢。

核心约束包括:

约束类型 命令示例 说明
时钟定义 create_clock -period 10 [get_ports clk] 周期10ns,对应100MHz
输入延迟 set_input_delay -max 5 [get_ports data_in] -clock clk 数据在时钟沿后5ns到达
输出延迟 set_output_delay -max 4 [get_ports data_out] -clock clk 数据需在时钟沿前4ns稳定
面积约束 set_max_area 0 让DC尽量优化面积
驱动/负载 set_driving_cell / set_load 模拟外部环境

注意:时钟定义一定要准确。我曾经遇到一个项目,时钟周期设成了10ns,但实际PLL输出是8ns。综合出来的网表在8ns下根本跑不动,最后只能重新综合。时钟约束是后续所有时序分析的基准,千万不能错。

第三步:编译与优化

DC的编译命令很简单,就是 compile_ultracompile。但里面的门道不少。

# 基本编译
compile_ultra -no_autoungroup

# 带面积优化的编译
compile_ultra -area_high_effort_script

# 带时序优化的编译
compile_ultra -timing_high_effort_script

为什么推荐 compile_ultra?因为它比 compile 做了更多的优化,比如:

  • 结构优化——重新安排逻辑结构,减少级数
  • 数据路径优化——对加法器、乘法器做特殊处理
  • 门级优化——选择合适的标准单元

嗯,这里要注意一点:compile_ultra 默认会做自动层次分组(autoungroup),这可能会打乱你的模块边界。如果你希望保持层次结构,记得加上 -no_autoungroup

第四步:分析结果

编译完成后,一定要看报告。我每次都会跑这几个:

# 时序报告
report_timing -max_paths 10 > timing.rpt

# 面积报告
report_area > area.rpt

# 功耗报告
report_power > power.rpt

# 约束违规报告
report_constraint -all_violators > violations.rpt

你想想看,如果时序报告里全是红色违规,那这个网表基本就是废的。我曾经有一次看到setup violation有200多条,吓得赶紧回去改RTL。后来发现是约束设得太紧了——输入延迟设大了1ns。调整后,违规全消了。

我的经验:综合后的时序报告,setup slack最好留10%~15%的余量。因为后端布局布线还会引入额外的线延迟。如果综合时slack就是0,那后端基本没戏。

第五步:输出网表

综合的最后一步,就是把结果写出来:

# 输出门级网表
write -format verilog -hierarchy -output top_synth.v

# 输出SDF(标准延迟格式)
write_sdf top_synth.sdf

# 输出SDC约束
write_sdc top_synth.sdc

这三个文件是后端布局布线的输入。网表给布局工具,SDF给时序分析,SDC给时钟树综合。缺一不可。

避坑指南

做综合这么多年,我总结了几条血泪教训:

  • 不要忽略warning——DC的warning很多是良性的,但有些是致命的。比如"unresolved reference"说明你漏了模块。
  • 检查时钟门控——如果设计中用了时钟门控,记得加 set_clock_gating_check,否则DC可能优化掉你的门控逻辑。
  • 小心多时钟域——跨时钟域路径要设false path,不然DC会拼命优化一条不需要的路径,浪费面积和功耗。

最后一个小建议:综合脚本一定要版本管理。我习惯把每个版本的约束和脚本都存到Git里。这样出了问题,可以快速回退对比。别问我为什么知道——有一次我不小心改错了约束,综合出来的网表面积大了30%,还好有历史版本可以对比。

好了,DC综合的核心流程就这些。你照着走一遍,基本能跑通。但真正做好综合,还得靠多练、多踩坑。每个项目都有自己的特殊性,慢慢积累经验吧。


公众号:蓝海资料掘金营,微信deep3321