3. 综合工具入门:Design Compiler基本流程

好,咱们开始聊DC。Design Compiler,Synopsys家的看家工具。

说实话,我刚入行那会儿,第一次打开DC的界面,心里是有点懵的。满屏的英文,一堆命令行,感觉像回到了DOS时代。但用久了你会发现,这玩意儿其实挺纯粹的——它只关心一件事:把你写的RTL代码,变成门级网表。

3.1 DC能干什么?

简单说,DC就是个翻译官。它把Verilog/VHDL这种高级语言,翻译成由标准单元库里的门电路组成的网表。同时,它还要保证这个网表能满足你的时序、面积、功耗要求。

我个人习惯把DC的工作分成三步:

  • 读入设计:把RTL代码和库文件吃进去
  • 施加约束:告诉DC,你要跑多快、用多大面积
  • 综合优化:DC自己琢磨怎么映射到门级电路

核心知识点:DC综合的本质是“约束驱动”。你给什么约束,它就往什么方向优化。不给约束?那它就会随便搞,结果往往不是你想要的。

下面这张图,是我自己总结的DC综合流程,你一看就明白:

DC综合基本流程 1. 启动DC dc_shell-t 或 GUI 2. 读取设计文件 read_verilog / analyze 3. 设置约束 create_clock / set_input_delay 4. 执行综合 compile_ultra 5. 分析结果 report_timing / report_area 6. 输出网表 write -f verilog 不满足约束?返回修改约束或RTL

3.2 启动DC

启动DC有两种方式:命令行和图形界面。

我个人更推荐命令行。为什么?因为脚本可以复用,方便回归。你想想看,一个项目做几个月,每次综合都要点鼠标,那不得累死?

我的习惯:我一般用 dc_shell-t 启动命令行模式。如果想看波形或者做debug,再用 design_vision 启动GUI。

启动命令很简单:

# 启动命令行模式
dc_shell-t

# 启动图形界面模式
design_vision

嗯,这里要注意。启动之后,DC会加载你的.synopsys_dc.setup文件。这个文件里配置了库路径、搜索路径等。我见过不少新手,启动DC后报错说找不到库,其实就是.setup文件没配好。

避坑指南:我曾经在一个项目里,因为.setup文件里写错了库的路径,结果综合出来的网表全是空的。查了两天才发现是路径少了个斜杠。所以,启动后第一件事,用 list_libs 检查库是否加载成功。

3.3 读取设计文件

设计文件读入,说白了就是把你的RTL代码告诉DC。DC支持多种格式:Verilog、VHDL、SystemVerilog等。

常用的命令有两个:

  • read_verilog:直接读入Verilog文件
  • analyze + elaborate:先分析语法,再例化设计

我一般用第二种方式。为什么?因为analyze会检查语法错误,elaborate会帮你展开层次结构。如果代码里有例化错误,elaborate阶段就能发现。

# 方式一:直接读入
read_verilog {top.v module_a.v module_b.v}

# 方式二:分析+例化(推荐)
analyze -format verilog {top.v module_a.v module_b.v}
elaborate top

关键点:elaborate之后,DC会生成一个名为 top 的设计(就是你指定的顶层模块)。这时候可以用 link 命令来连接所有子模块。如果link报错,说明有模块没找到或者例化名不匹配。

我记得有一次,一个同事的代码在仿真里跑得好好的,但DC就是link不过。查了半天,发现是某个子模块的文件名和模块名不一致。DC是按模块名找文件的,不是按文件名。这个坑,你记住。

3.4 设置约束

约束,是DC综合的灵魂。没有约束,DC就不知道往哪个方向优化。

约束主要分三类:

约束类型 常用命令 说明
时序约束 create_clock, set_input_delay, set_output_delay 定义时钟周期、输入输出延迟
面积约束 set_max_area 限制综合后的面积上限
设计规则约束 set_max_fanout, set_max_transition 保证物理实现的可行性

时序约束是最核心的。我一般这样写:

# 创建时钟,周期10ns,占空比50%
create_clock -name clk -period 10 [get_ports clk]

# 设置输入延迟(假设外部延迟为2ns)
set_input_delay -clock clk 2 [all_inputs]

# 设置输出延迟(假设外部延迟为3ns)
set_output_delay -clock clk 3 [all_outputs]

# 设置面积约束(可选)
set_max_area 0

我的经验:set_max_area 0 的意思是让DC在满足时序的前提下,尽量把面积做小。但别指望它真的能到0,这只是个优化方向。实际项目中,我一般先跑一版不加面积约束的,看看时序能不能过。时序过了,再加面积约束去压面积。

你可能会问:约束设错了会怎样?

嗯,这个问题问得好。我曾经在一个项目里,把时钟周期设成了1ns(实际应该是10ns)。结果DC综合出来的电路面积巨大,功耗也高得离谱。因为DC以为你要跑1GHz,拼命插寄存器、优化路径。后来发现是约束写错了,改回来重新综合,面积直接降了一半。

避坑指南:约束不是越紧越好。过紧的约束会导致DC过度优化,增加面积和功耗。过松的约束又可能导致时序不满足。我的建议是:先按芯片目标频率的80%设约束,综合一版看看余量,再逐步收紧。

3.5 执行综合

约束设好了,就可以跑综合了。核心命令就一个:

compile_ultra

compile_ultra 是DC目前最推荐的综合命令。它比老版的 compile 优化效果更好,特别是对时序和面积的平衡。

当然,你也可以加一些选项:

compile_ultra -no_autoungroup -retime
  • -no_autoungroup:保持层次结构,不自动打平。方便后端的物理设计。
  • -retime:允许DC移动寄存器位置来优化时序。这个选项很强大,但也会增加综合时间。

综合完成后,DC会生成一系列报告。我最常看的是:

  • report_timing:看时序是否满足
  • report_area:看面积大小
  • report_power:看功耗估算

最后,把综合好的网表写出来:

write -format verilog -hierarchy -output top_synth.v

好了,DC的基本流程就是这样。启动、读设计、设约束、跑综合、出网表。每一步都有坑,但走一遍就熟了。我个人觉得,DC综合最考验人的不是命令,而是对约束的理解。约束设得好,综合就成功了一半。

总结一句话:DC综合,七分靠约束,三分靠命令。把约束想清楚,比背一百条命令都管用。

可可精品资料库