第四章:综合策略与优化

4.1 逻辑综合到底在干什么?

说实话,很多刚入行的朋友把综合想得太神秘了。其实说白了,综合就是把你的 RTL 代码——也就是我们写的 Verilog 或 VHDL——翻译成门级网表的过程。嗯,你可以把它想象成一个翻译官,把「高级语言」翻译成芯片能理解的「底层语言」。

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

  • 转换(Translation):把 RTL 读进来,转成内部统一的布尔等式表达
  • 逻辑优化(Logic Optimization):化简冗余逻辑,去掉没用的电路
  • 映射(Mapping):把优化后的逻辑映射到目标工艺库的标准单元上

我在项目中遇到过一件事:有个同事写了一段很复杂的 case 语句,综合出来面积大得吓人。后来我帮他改成优先级编码器结构,面积直接砍掉 40%。你想想看,同样的功能,不同的写法,综合结果天差地别。

核心要点:综合不是黑盒子。你给工具什么代码,它就给你什么结果。代码风格直接影响综合质量。

逻辑综合核心流程 RTL 代码输入 Verilog / VHDL 转换 (Translation) 布尔等式表达 逻辑优化 化简 / 重定时 映射 (Mapping) 工艺库单元绑定 门级网表输出 .v / .ddc 时序不满足时迭代优化 时序约束 SDC 文件

4.2 面积与速度的权衡——没有免费的午餐

做芯片设计,最常听到的一句话就是:「又要马儿跑,又要马儿不吃草」。但现实是,面积和速度永远是一对矛盾体。你想想看,想让电路跑得快,就得加流水线、加并行逻辑,面积自然就上去了。反过来,想省面积,就得共享资源、串行处理,速度肯定受影响。

我记得有一次做通信芯片,客户要求面积控制在 2mm² 以内,同时频率要跑到 500MHz。当时团队里吵翻了天,有人说不可能,有人说试试看。最后我们是怎么解决的?

核心思路就四个字:抓大放小。

优化方向 面积影响 速度影响 我的建议
流水线插入 增加 10-30% 提升 20-50% 关键路径必加
资源共享 减少 15-40% 降低 10-20% 非关键路径可用
逻辑复制 增加 20-50% 提升 15-30% 扇出太大时使用
操作数重排 几乎不变 提升 5-15% 免费优化,必做

实战技巧:我一般先跑一次综合,看看时序报告里哪些路径是红色的。只优化那几条关键路径,其他地方不动。这样面积损失最小,效果最明显。

4.3 综合脚本编写——工具是你的好兄弟

很多工程师觉得写综合脚本是件苦差事。其实不然,好的脚本能帮你省下大量重复劳动。我个人习惯把脚本分成三个模块:

  • 环境设置模块:定义工艺库、搜索路径、变量
  • 约束模块:时钟定义、输入输出延迟、时序例外
  • 编译策略模块:选择综合策略、优化选项、输出格式

下面是我常用的一个综合脚本模板,你可以直接拿去用:

# ============================================
# 综合脚本模板 - 适用于 DC/Genus
# 作者:资深工程师的经验之谈
# ============================================

# 1. 环境设置
set search_path [list . /path/to/lib /path/to/db]
set target_library "typical.db slow.db fast.db"
set link_library "* $target_library"

# 2. 读取设计
analyze -format verilog {top_module.v sub_module.v}
elaborate top_module

# 3. 时钟约束 —— 这里最容易出错
create_clock -name clk -period 2.0 [get_ports clk]
set_clock_uncertainty -setup 0.15 [get_clocks clk]
set_clock_uncertainty -hold 0.05 [get_clocks clk]

# 4. 输入输出延迟
set_input_delay -max 0.6 -clock clk [all_inputs]
set_output_delay -max 0.5 -clock clk [all_outputs]

# 5. 时序例外 —— 小心使用
set_false_path -from [get_ports rst_n]
set_multicycle_path -setup 2 -from [get_pins reg_a/Q] -to [get_pins reg_b/D]

# 6. 综合策略选择
# 我一般用 compile_ultra,效果比 compile 好很多
compile_ultra -gate_clock -retime

# 7. 报告输出
report_timing > reports/timing.rpt
report_area > reports/area.rpt
report_power > reports/power.rpt

# 8. 保存网表
write -format verilog -output output/top_netlist.v
write_sdc output/top_constraints.sdc

注意:set_multicycle_path 这个命令,我曾经吃过亏。有一次我设了一个 2 周期的 multicycle,但忘了检查 hold 时间,结果芯片流片回来,数据保持不住,整个批次报废。教训深刻啊!

4.4 综合策略的选择——因地制宜

不同的设计目标,要用不同的综合策略。我一般把策略分成三类:

  1. 面积优先策略:适合低成本芯片,比如 MCU、IoT 芯片。工具会尽量共享逻辑,减少冗余。
  2. 速度优先策略:适合高性能芯片,比如 CPU、GPU。工具会插入流水线,复制关键逻辑。
  3. 平衡策略:大多数场景的选择。先满足时序,再优化面积。

你可能会问:「那我怎么选?」我的经验是:先跑一次平衡策略,看看时序余量。如果 slack 是正的,说明还有优化空间,可以试试面积优先。如果 slack 是负的,那就老老实实上速度优先吧。

一句话总结:综合不是一锤子买卖。多跑几次,对比报告,找到最适合你设计的那个点。工具是死的,人是活的。

好了,这一章的内容就到这里。记住,综合脚本写得好,下班回家走得早。多花点时间在脚本上,后面会省下大把调试时间。

可可精品资料库