4. 逻辑综合优化技术
Design Compiler 在把 RTL 映射到工艺库之后,真正决定 PPA(功耗、性能、面积)的往往是优化阶段。综合优化不是单一动作,而是一组可以按层次、按边界、按资源分别施加的策略。理解这些策略的适用条件,比记住命令本身更重要。本节围绕结构化(Structural)、展平化(Flattening)、边界优化(Boundary Optimization)和资源共享(Resource Sharing)四类技术展开,并用一个面积与速度权衡的案例说明参数调优思路。
一、四类优化策略的定位
结构化优化保留设计的层次,在每一层内部做逻辑重构,例如提取公共子表达式、重排布尔网络、合并等价逻辑。它的优点是编译快、可读性好、便于后续 ECO,缺点是跨层次共享机会被层次边界挡住。展平化则把指定层次“打平”,让优化器看到全局逻辑,从而获得更大的重组空间,代价是网表可读性下降、编译时间上升、增量修改困难。边界优化介于两者之间:它不破坏层次,但允许优化器跨越边界移动、复制或重组逻辑,典型手段包括边界常量传播、寄存器边界重定时(retiming)和端口逻辑吸收。资源共享则针对算术与比较类算子,在互斥或时序错开的运算之间复用同一个硬件单元,用面积换吞吐或延迟。
二、结构化与展平化的实际操作
在 Design Compiler 中,层次控制通过 set_ungroup 与 ungroup 完成。常见做法是:对时序关键路径所在的子模块设置 set_ungroup false 保留层次,对纯组合、无复用价值的中间层设置 set_ungroup true 允许展平。例如:
# 保留顶层与关键子模块层次
set_ungroup [get_designs "top"] false
set_ungroup [get_designs "u_core/u_alu"] false
# 允许展平纯组合中间层
set_ungroup [get_designs "u_core/u_mux_tree"] true
# 编译时启用边界优化
compile_ultra -boundary_optimization -gate_clock
# 对特定模块做局部展平
ungroup [get_designs "u_core/u_mux_tree"]
需要注意,ungroup 一旦执行,原层次名在网表中消失,后续用 report_area、report_timing 定位问题时路径名会变化。因此建议在综合脚本中保留一份“展平前”的层次快照,便于对比。边界优化通常与 compile_ultra 配合使用,它会尝试把端口上的常量、寄存器或组合逻辑吸收到相邻层次,减少边界上的冗余缓冲与逻辑。
三、资源共享的触发条件
资源共享不是自动发生的,它依赖两个前提:运算在时间上互斥,或运算结果在不同周期被使用。Design Compiler 在 compile_ultra 中会识别互斥条件(如 if/else 分支、case 分支),并尝试复用算术单元。若设计中有两个加法器分别位于互斥分支,工具可能合并为一个加法器加多路选择器。但若两个加法器在同一周期都被使用,则无法共享。可以通过 set_resource_allocation 与 set_implementation 对特定算子施加约束,例如指定加法器使用何种架构(行波进位、超前进位等)。
四、面积与速度权衡案例
假设一个示例设计:数据通路包含 4 个 16 位加法器,分别用于四个互斥的运算模式,目标工艺库为 40nm,时钟周期约束 2.0ns。初始综合采用全展平、不共享资源的策略,得到面积约 18500 μm²,关键路径 1.72ns,时序满足。若把面积作为首要目标,可尝试以下调优:
| 调优项 | 操作 | 面积变化(示例) | 时序变化(示例) |
|---|---|---|---|
| 资源共享 | 合并互斥加法器 | 约 -12% | 关键路径 +0.15ns |
| 局部展平 | 仅展平 mux 树 | 约 -4% | 基本不变 |
| 边界优化 | 开启 boundary_optimization | 约 -3% | 可能略优 |
| 过度展平 | 全部 ungroup | 约 -6% | 编译时间 +40% |
表中数据为教学示例的合理假设,用于说明趋势,并非实测结果。实际调优时,建议按“先边界优化、再局部展平、最后资源共享”的顺序逐步施加,每步后用 report_area 和 report_timing -max_paths 5 观察变化。若资源共享后关键路径超出约束,可对共享后的加法器单独设置 set_max_delay 或改用更快实现架构,而不是直接放弃共享。
五、参数调优的检查清单
- 确认时钟约束与输入输出延迟已正确设置,否则优化方向会偏离。
- 先用
check_design排除悬空端口、多驱动等结构问题。 - 对关键模块保留层次,对纯组合中间层允许展平。
- 开启
-boundary_optimization,观察端口逻辑是否被吸收。 - 识别互斥运算,评估资源共享的面积收益与延迟代价。
- 每次调优后对比面积、时序、编译时间三项指标,避免单指标优化。
综合优化的本质是在约束空间内寻找可行解,而不是追求某一项指标的极值。结构化、展平化、边界优化和资源共享各自解决不同层面的问题,理解它们的作用范围与代价,才能在面积与速度之间做出有依据的取舍。