3. Design Compiler综合自动化基础

Design Compiler(DC)的综合过程本质上是一系列 Tcl 命令按特定顺序作用于设计对象的过程。手工在交互式 shell 中逐条敲命令只适合探索,真正可交付的综合流程必须固化为脚本。一个可维护的 DC 综合脚本通常由四段构成:环境与库设置、设计读入与链接、约束施加、编译与报告输出。理解这四段之间的依赖关系,比记住某条命令的选项更重要。

脚本骨架与变量组织

环境设置段负责告诉 DC“用什么工艺、去哪里找库”。典型写法是设置 search_path、target_library、link_library、symbol_library 与 synthetic_library。其中 target_library 决定综合映射到的标准单元库,link_library 用于解析实例引用,通常需要把 * 放在最前以优先解析当前设计。为避免路径硬编码,建议把工程根目录、库目录、结果目录抽成变量:

set PRJ_ROOT   /proj/uart_ctrl
set LIB_DIR    $PRJ_ROOT/lib
set RPT_DIR    $PRJ_ROOT/rpt
set NET_DIR    $PRJ_ROOT/netlist
set search_path [list . $LIB_DIR $RPT_DIR]

set target_library "sc9_cln40lp_tt_1v0_25c.db"
set link_library   "* $target_library dw_foundation.sldb"
set symbol_library "sc9_cln40lp.sdb"
set synthetic_library "dw_foundation.sldb"

把库名、时钟周期、输入输出延迟等参数集中定义在脚本头部,后续命令只引用变量,是脚本可复用的关键。例如 set CLK_PERIOD 2.5、set IN_DELAY 0.8、set OUT_DELAY 0.6,当工艺或频率目标变化时只需改一处。

设计读入与链接

读入阶段常用 analyze -format verilog 配合 elaborate,或直接用 read_verilog。区别在于 analyze 会生成中间格式并支持增量,适合多文件工程;elaborate 负责展开参数、解析层次并建立设计对象。链接用 link 检查所有实例是否能在 link_library 中找到,未解析的引用会在此阶段报 warning,必须清零后再进入约束阶段。常用检查命令是 check_design,它会报告悬空端口、多驱动、组合环等问题。

时序与面积约束

约束是综合质量的分水岭。时序约束的核心是时钟定义与 I/O 边界条件。以 2.5 ns 周期时钟为例:

create_clock -name clk -period $CLK_PERIOD [get_ports clk]
set_clock_uncertainty 0.15 [get_clocks clk]
set_clock_transition  0.10 [get_clocks clk]
set_input_delay  $IN_DELAY  -clock clk [remove_from_collection [all_inputs] [get_ports clk]]
set_output_delay $OUT_DELAY -clock clk [all_outputs]
set_driving_cell -lib_cell BUFFD2BWP -pin Z [all_inputs]
set_load 0.05 [all_outputs]

这里 set_clock_uncertainty 为时钟抖动与偏斜预留余量,set_driving_cell 与 set_load 描述真实驱动与负载,避免 DC 用理想环境估算出过于乐观的时序。面积约束用 set_max_area 给出上限,但更推荐用 set_max_area 0 让工具在满足时序前提下尽量优化面积,再通过报告评估。此外还需处理 set_false_path、set_multicycle_path 等例外,例如跨异步时钟域路径应设为 false path,否则会引入无意义的优化压力。

约束施加后必须用 check_timing 验证:未约束端点、无时钟寄存器、组合反馈等都会在此暴露。一个常见错误是只约束了时钟却忘了 I/O delay,导致边界路径被当作零延迟处理,综合结果与后端严重不符。

编译与报告自动生成

编译用 compile_ultra,可加 -gate_clock 启用门控时钟、-retime 做寄存器重定时。编译完成后进入报告阶段,这是自动化脚本最容易被忽视却最有价值的部分。建议至少生成四类报告:时序报告 report_timing、面积报告 report_area、约束违例报告 report_constraint -all_violators、功耗报告 report_power。用 redirect 把输出写入文件:

redirect $RPT_DIR/timing.rpt  { report_timing -max_paths 20 -nworst 5 -delay max }
redirect $RPT_DIR/area.rpt    { report_area -hierarchy }
redirect $RPT_DIR/viol.rpt    { report_constraint -all_violators -verbose }
redirect $RPT_DIR/power.rpt   { report_power -analysis_effort high }
write -format verilog -hierarchy -output $NET_DIR/uart_ctrl_syn.v
write_sdc $NET_DIR/uart_ctrl.sdc

报告生成后应做自动判读,而不是靠人翻文件。可在 Tcl 中提取关键指标并打印汇总行,例如用 get_attribute 读取 slack,或对 report_constraint 的输出做文本匹配统计违例条数。若 WNS(最差负裕量)小于 0 或违例数大于阈值,脚本应返回非零退出码,让上层 CI 流程感知失败。

DC 综合脚本四段结构与数据流 ① 环境与库 search_path target_library link_library 变量集中定义 ② 读入与链接 analyze / elaborate link check_design 未解析引用清零 ③ 约束施加 create_clock set_input/output_delay set_max_area check_timing ④ 编译与报告 compile_ultra redirect 报告 write netlist/sdc 自动判读 约束参数关系(示例:周期 2.5 ns) 时钟周期 T = 2.5 ns uncertainty = 0.15 输入延迟 = 0.8 ns 输出延迟 = 0.6 ns 驱动单元 BUFFD2BWP 负载 0.05 pF 可用组合逻辑时间 ≈ T − uncertainty − 输入延迟 = 2.5 − 0.15 − 0.8 = 1.55 ns(示例估算) 报告输出与判读 timing.rpt WNS / TNS area.rpt 总面积 / 层次 viol.rpt 违例条数 power.rpt 动态 / 静态功耗 自动判读条件(示例) WNS ≥ 0 且 违例数 = 0 → 通过,退出码 0 否则 → 失败,退出码非 0,阻断后续流程 违例反馈:调整约束或优化策略后重跑