第三章 逻辑综合面积优化:综合工具的面积约束、compile_ultra命令、门级网表优化、消除冗余逻辑

逻辑综合,说白了就是把RTL代码翻译成门级网表。但翻译得好不好,直接决定了芯片的面积和功耗。我做了这么多年后端,见过太多因为综合没做好,导致后面布局布线跑不动的案例。今天咱们就聊聊面积优化这块硬骨头。

3.1 面积约束:别让工具瞎猜

综合工具默认是偏向时序优化的。你不给它面积约束,它就会拼命加buffer、插大驱动单元,面积自然就上去了。我刚开始做项目时吃过这个亏——综合出来的网表比预期大了30%,后面怎么压都压不下来。

面积约束的写法其实很简单:

set_max_area 0
set_max_area 10000
set_max_area -ignore_clock_gating true

这里有几个关键点:

  • set_max_area 0:让工具尽可能优化面积,但注意别设得太死,否则工具会为了面积牺牲时序
  • 单位问题:不同工艺库的单位不一样,有的用um²,有的用gate count。我建议先跑一版不加约束的,看看默认面积是多少,再逐步收紧
  • 时钟门控:时钟门控单元本身会占用面积,但省掉的寄存器功耗远大于这点开销。所以一般建议忽略时钟门控的面积

重要经验:面积约束和时序约束是矛盾的。我一般先保证时序收敛,再回头压面积。如果时序裕量够大,可以适当放松时序约束来换取面积。

3.2 compile_ultra:综合工具的杀手锏

说到面积优化,就绕不开compile_ultra这个命令。它比普通的compile强在哪?说白了就是更智能的优化引擎。

我常用的命令组合:

compile_ultra -area_high_effort_script \
              -no_autoungroup \
              -retime \
              -gate_clock

各选项的作用:

选项 作用 我的建议
-area_high_effort_script 启用面积优化脚本,会多跑几轮优化 面积敏感的设计必开
-no_autoungroup 禁止自动打平层次 保留层次结构,便于后续分析
-retime 寄存器重定时,平衡路径 能省面积,但会改变时序行为
-gate_clock 自动插入时钟门控 功耗和面积双赢,强烈推荐

小技巧:如果设计特别大,可以先跑compile_ultra -incremental做增量编译。这样只优化关键路径,速度快很多。

3.3 门级网表优化:从网表里挤水分

综合完成后,网表里其实还有很多优化空间。我习惯做三步检查:

  1. 检查驱动强度:工具经常选过大的驱动单元。我会手动把扇出小的单元换成低驱动版本
  2. 检查多余的反相器:两个反相器串在一起就是浪费,直接删掉
  3. 检查组合逻辑深度:太深的组合逻辑会迫使工具用大驱动单元,适当插入寄存器可以减小面积

举个例子,我遇到过这样一个情况:

// 原始代码
assign y = ~(a & b & c & d);

// 综合后网表里可能变成
NAND2 U1 (.A(a), .B(b), .ZN(n1));
NAND2 U2 (.A(c), .B(d), .ZN(n2));
NOR2  U3 (.A(n1), .B(n2), .ZN(y));

这里其实可以用一个4输入的NAND门代替,面积能省30%。

3.4 消除冗余逻辑:别让工具做无用功

冗余逻辑是面积的隐形杀手。我总结了几种常见情况:

  • 恒值逻辑:比如assign y = a & 1'b1,直接删掉
  • 重复计算:同一个表达式算了两遍,工具不一定能自动合并
  • 未使用的输出:模块里有些输出端口根本没连出去,但工具还是会综合出逻辑

避坑指南:我曾经在一个项目里发现,综合工具对casez语句的处理特别差。如果case条件里有无关位,工具会生成大量比较器。后来我改成casex,面积直接降了15%。

消除冗余逻辑的实用方法:

// 不好的写法
always @(*) begin
  if (sel) 
    y = a + b;
  else
    y = a + b;  // 两个分支一样,冗余
end

// 好的写法
assign y = a + b;

3.5 面积优化的整体流程

下面这张图是我自己总结的面积优化流程,你可以参考:

面积优化核心流程 RTL代码输入 设置面积约束 set_max_area compile_ultra -area_high_effort_script 门级网表优化 消除冗余逻辑 面积达标?→ 输出网表 不达标,调整约束

这个流程我用了很多年。核心思路就是:先给工具一个合理的面积目标,然后用compile_ultra做第一轮优化,最后人工检查网表,把明显浪费的逻辑去掉。

个人习惯:我一般会跑两轮综合。第一轮不加面积约束,看时序能不能过。第二轮加上面积约束,在时序裕量允许的范围内压面积。这样既保证了时序,又不会让面积失控。

嗯,面积优化这块其实还有很多细节。比如不同工艺库的单元选择、多阈值电压的搭配使用等等。但掌握了上面这些核心方法,大部分面积问题都能解决。记住一点:工具是死的,人是活的。别完全依赖工具,多看看网表,多想想为什么工具会这么选,你的优化能力就会越来越强。

可可精品资料库