3. Design Compiler综合流程实战

本节用一个简单的组合逻辑模块,把 Design Compiler(下称 DC)从启动到产出网表的完整链路走一遍。重点不是背命令,而是理解每一步在“喂”给工具什么信息,以及这些信息如何影响最终的综合结果。示例模块是一个 8 位带进位输入的加法器,纯组合逻辑,没有时钟,便于把注意力集中在库、约束和映射关系上。

一、综合流程的整体数据流

DC 的综合本质是把“工艺无关的 RTL”翻译成“绑定到具体工艺库的门级网表”,中间需要三类输入:设计文件、工艺库、约束。三者缺一不可,且加载顺序会影响工具对设计的理解。下图给出本节示例的完整数据流与关键命令的对应关系。

RTL 源文件 adder8.v 工艺库 target / link library 约束文件 adder8.sdc read_verilog 解析 RTL,建立 GTECH 网表 set target_library / link_library 指定映射目标与解析库 read_sdc 加载时序与设计规则约束 compile_ultra 逻辑优化 + 工艺映射 时序/面积/DRC 权衡 输出门级网表 输出产物 adder8_netlist.v / .sdc / .sdf report_timing / report_area 加载顺序:库 → RTL → 约束 → 综合;约束必须在 compile 之前生效

二、准备工艺库与启动环境

DC 启动前需要确定工艺库路径。示例使用一个假设的 40nm 库,库文件为 slow.db(典型慢角)和 fast.db(快角),综合阶段通常先用慢角做时序收敛。启动脚本中通过变量指定库路径,避免硬编码:

set LIB_PATH "/pdk/40nm/lib"
set target_library "$LIB_PATH/slow.db"
set link_library   "* $LIB_PATH/slow.db"
set symbol_library "$LIB_PATH/slow.sdb"

target_library 决定综合时把逻辑映射成哪些标准单元;link_library 用于解析设计中例化的子模块和已映射单元,开头的 * 表示先查内存中已加载的设计,再查库。若只设 target 不设 link,工具在解析层次时会报 “unresolved reference”。

三、读取 RTL 并检查设计

示例 RTL 是一个带进位输入的 8 位加法器:

module adder8 (
  input  [7:0] a,
  input  [7:0] b,
  input        cin,
  output [7:0] sum,
  output       cout
);
  assign {cout, sum} = a + b + cin;
endmodule

读取命令为 read_verilog adder8.v,随后用 current_design adder8 指定当前设计,再用 link 解析引用。此时可以用 check_design 检查是否有悬空端口、多重驱动等问题。一个常见误区是读完 RTL 直接 compile,结果因为没设 current_design 而报 “no design specified”。

四、编写并加载 SDC 约束

组合逻辑没有时钟,但依然需要约束输入到达时间、输出外部延时和设计规则。示例 SDC 如下:

set_input_delay  -max 1.5 -clock virtual_clk [get_ports {a[*] b[*] cin}]
set_output_delay -max 2.0 -clock virtual_clk [get_ports {sum[*] cout}]
set_max_area 0
set_load 0.05 [get_ports {sum[*] cout}]
set_driving_cell -lib_cell BUFX2 -pin Z [get_ports {a[*] b[*] cin}]

这里用 virtual_clk 作为虚拟时钟,仅用于定义输入输出延时参考,不需要在设计中真实存在。set_max_area 0 表示让工具尽量优化面积,但实际会受时序和 DRC 限制。set_load 模拟输出端接的电容负载,set_driving_cell 模拟输入驱动能力,这两项直接影响缓冲器插入和单元选型。加载命令为 read_sdc adder8.sdc,加载后可用 report_timing_requirements 确认约束是否被正确识别。

SDC 中的 virtual_clk 不需要 create_clock 定义在端口上,但必须先用 create_clock -name virtual_clk -period 5 创建,否则 set_input_delay 会报找不到时钟。

五、运行 compile_ultra 与结果观察

约束加载完成后执行 compile_ultra。该命令会依次进行结构优化、逻辑优化和工艺映射。对于纯组合逻辑,工具主要做布尔化简、公共子表达式提取和单元映射。综合完成后,用以下命令观察结果:

report_area
report_timing -max_paths 5
report_constraint -all_violators
write -format verilog -hierarchy -output adder8_netlist.v
write_sdc adder8_out.sdc

在示例假设条件下,综合后面积约为 320 μm²,关键路径为 a[7]→sum[7],延迟约 1.8 ns,满足 1.5 ns 输入延时加 2.0 ns 输出延时构成的 3.5 ns 预算。若 report_constraint 报出 setup violation,优先检查输入输出延时是否过紧、驱动单元是否过弱,而不是直接改 RTL。

六、完整脚本与执行方式

把上述步骤串成一个可执行脚本 run_dc.tcl:

set LIB_PATH "/pdk/40nm/lib"
set target_library "$LIB_PATH/slow.db"
set link_library   "* $LIB_PATH/slow.db"

read_verilog adder8.v
current_design adder8
link
check_design

read_sdc adder8.sdc
check_timing

compile_ultra

report_area
report_timing -max_paths 5
report_constraint -all_violators

write -format verilog -hierarchy -output adder8_netlist.v
write_sdc adder8_out.sdc
exit

执行方式为 dc_shell -f run_dc.tcl | tee dc.log。日志中重点关注 check_design 的 warning、check_timing 的 unconstrained 提示,以及 compile 后的面积和时序报告。若 check_timing 提示有端口未约束,说明 SDC 中遗漏了对应端口,需要补齐后再综合。

综合脚本中不要用 source 加载 SDC 后再修改约束,容易造成约束叠加。建议每次综合前清空约束或用 reset_design 重新开始。