3. 逻辑综合优化:综合策略、资源利用率与面积优化
逻辑综合,说白了就是把你的 RTL 代码翻译成门级网表。这一步做得好不好,直接决定了你的芯片能跑多快、占多大面积、功耗高不高。我刚开始做 FPGA 设计那会儿,总觉得综合是工具自动干的事,跟我没啥关系。后来被坑了几次才明白——不懂综合优化,你写出来的代码可能就是一颗定时炸弹。
3.1 综合策略的选择:速度优先还是面积优先?
综合工具通常提供几种策略。最常见的就是「速度优先」和「面积优先」。你可能会问:我能不能既要速度又要面积?嗯,理论上可以,但现实中你得做取舍。
我个人习惯的做法是:先跑一次默认策略,看看时序和资源报告。如果时序紧张,就切到速度优先;如果资源快爆了,就切到面积优先。别一上来就选极端策略,那样反而容易出问题。
核心原则:综合策略不是一成不变的。同一个设计,在不同阶段可能需要不同的策略。前期验证阶段我通常用面积优先,因为跑得快;后期时序收敛阶段再切到速度优先。
3.2 资源利用率的监控与优化
资源利用率,说白了就是你的芯片用了多少 LUT、FF、BRAM、DSP。我见过不少新手,写代码时完全不考虑资源,结果综合出来发现 LUT 用了 120%,然后开始疯狂改代码……
这里我分享一个我在项目中用过的技巧:用综合报告里的「资源占用明细」来定位问题。比如某个模块 LUT 占用特别高,那多半是组合逻辑写得太复杂了。
| 资源类型 | 常见浪费原因 | 优化方向 |
|---|---|---|
| LUT | 复杂的组合逻辑、多级 MUX | 拆分逻辑、使用查找表替代 |
| FF | 不必要的流水线、冗余寄存器 | 精简流水线深度、合并寄存器 |
| BRAM | 大位宽小深度、未对齐的数据宽度 | 调整位宽与深度比例、使用分布式 RAM |
| DSP | 乘法器未复用、位宽浪费 | 共享 DSP 单元、截断位宽 |
小技巧:综合报告里有个「资源利用率百分比」,别只看这个数字。我建议你重点关注「LUT 与 FF 的比例」。如果 LUT 比 FF 多很多,说明你的设计偏组合逻辑,时序可能不好收敛。
3.3 面积优化的核心方法
面积优化,说白了就是让芯片更小、更省资源。我总结了几种最实用的方法:
3.3.1 资源共享
这是最直接的面积优化手段。比如两个模块都用到了乘法器,但不同时工作,那就可以共用一个 DSP。我曾经在一个视频处理项目中,通过资源共享把 DSP 用量从 48 个降到了 16 个。
// 不共享:两个乘法器
assign result1 = a * b;
assign result2 = c * d;
// 共享:一个乘法器,通过 MUX 选择输入
assign mul_in1 = sel ? a : c;
assign mul_in2 = sel ? b : d;
assign mul_out = mul_in1 * mul_in2;
assign result1 = sel ? mul_out : 0;
assign result2 = sel ? 0 : mul_out;
3.3.2 状态机优化
状态机的编码方式对面积影响很大。我建议:状态数少于 16 个时用独热码,多于 16 个时用二进制编码。独热码虽然占的 FF 多,但译码逻辑简单,LUT 用得少。
注意:别为了省面积把状态机写成「格雷码」。格雷码虽然省 FF,但译码逻辑复杂,反而可能增加 LUT 用量。我踩过这个坑,后来老老实实按状态数选编码方式。
3.3.3 数据路径优化
数据路径的位宽直接影响面积。比如你只需要 8 位精度,就别用 32 位总线。我见过有人把整个设计都定义成 32 位,结果资源翻了好几倍。
另外,能用移位代替乘除法的,尽量用移位。比如乘以 2 用左移一位,除以 4 用右移两位。这样能省下 DSP 资源。
3.4 综合优化的知识体系
下面这张图是我自己总结的综合优化知识体系,你可以对照着看看自己哪块还不太熟:
3.5 综合优化的避坑指南
做综合优化这么多年,我踩过的坑不少。这里挑几个典型的说说:
- 别过度优化:我曾经为了省几个 LUT,把代码改得面目全非,结果综合出来时序全乱了。后来我学乖了——先保证功能正确和时序收敛,再考虑面积优化。
- 综合报告要仔细看:很多人只看资源利用率,忽略了「警告信息」。其实很多警告都在提示你代码有问题,比如「inferred latch」、「unused signal」这些。
- 不同工具结果不同:Vivado 和 Quartus 的综合策略不一样。同一个代码,在 Vivado 上可能资源很省,换到 Quartus 就爆了。所以别只依赖一个工具的报告。
我的经验:综合优化不是一蹴而就的。我通常的做法是:先写代码 → 综合看报告 → 定位瓶颈 → 局部优化 → 再综合验证。这样迭代 3-5 轮,基本就能达到满意的效果。
3.6 综合优化的实践建议
最后,我总结几条实践建议:
- 写代码时就要考虑综合:别等到综合出问题了再改。比如写组合逻辑时,尽量用 case 代替 if-else 链,这样综合出来的 LUT 更少。
- 善用综合属性:Vivado 里有 KEEP、DONT_TOUCH 这些属性,可以控制综合工具的行为。比如某个关键路径,你可以用 KEEP 防止工具优化掉。
- 多做对比实验:同一个功能,用不同的写法综合,结果可能差很多。我习惯把几种写法都跑一遍综合,选资源最省的那个。
嗯,综合优化这块内容不少,但核心就三点:选对策略、盯紧资源、持续优化。你只要把这三点做到位,综合这一步基本不会出大问题。