逻辑综合阶段的面积优化:综合策略选择
逻辑综合,说白了就是把RTL代码映射成门级网表。这个阶段对面积的影响有多大?我跟你讲,有时候同一个设计,不同综合策略做出来,面积能差30%以上。这不是夸张,是我亲眼见过的。
面积优先 vs 时序优先
综合工具里通常有两个大方向:面积优先和时序优先。你可能会想,那我肯定选面积优先啊,这章不就是讲面积优化吗?别急,这里有个坑。
我个人的习惯是:先跑一版时序优先,看看时序裕量到底有多少。如果时序很宽松,再切到面积优先重新综合。为什么这么做?因为面积优先模式下,工具会拼命压缩逻辑,但有时候压缩过头了,路径延迟暴增,反而要花更多面积去修时序,得不偿失。
举个例子,我曾经做过一个MCU项目。一开始直接选面积优先,综合出来面积确实小,但setup violation有200多条。后来我改成时序优先先跑一遍,发现最差路径还有0.5ns的裕量。于是我把综合策略调成「面积优先,但关键路径留10%余量」,最终面积只比纯面积优先大了5%,但时序完全收敛了。
逻辑重组与资源共享
这块是综合阶段面积优化的重头戏。工具会自动做,但你要学会引导它。
逻辑重组,说白了就是改变逻辑门的连接方式。比如一个加法器链,你是做成树形结构还是链式结构?树形结构延迟小但面积大,链式结构面积小但延迟大。怎么选?看你的时序余量。
// 链式加法器(面积小)
assign sum = a + b + c + d;
// 树形加法器(时序好)
assign sum_ab = a + b;
assign sum_cd = c + d;
assign sum = sum_ab + sum_cd;
你看,同样的功能,两种写法综合出来的面积可能差20%。我建议你写RTL时,先按逻辑清晰写,然后在综合脚本里用 set_ungroup 和 set_flatten 来控制工具的重组力度。
资源共享这块更有意思。多个功能模块如果用到相同的运算,能不能共用一套硬件?
工具一般会自动做资源共享,但你可以通过 set_share 或 set_resource_sharing 来控制。我个人建议:对于数据通路宽(比如32位以上)的运算,手动做资源共享;对于窄位宽(8位以下)的,交给工具自动处理。
操作符调优:+、*、比较器
这部分是面积优化的「细节决定成败」之处。不同的操作符,面积差异巨大。
| 操作符 | 面积优化策略 | 我踩过的坑 |
|---|---|---|
| 加法器 (+) | 用进位选择加法器代替行波进位加法器 | 位宽超过16位时,行波进位延迟太大,面积反而省不下来 |
| 乘法器 (*) | 用移位加代替,或使用DSP硬核 | 曾经为了省面积用移位加实现32位乘法,结果时序完全跑不动 |
| 比较器 (==, >) | 用减法器代替,或利用格雷码特性 | 连续多个比较器串联时,面积会爆炸 |
加法器优化:你想想看,一个32位的行波进位加法器,进位要传32级。面积是小了,但延迟呢?我一般建议:位宽≤8位用行波进位,8~16位用进位选择,16位以上用超前进位。这个经验值是我从多个项目里总结出来的。
乘法器优化:这是面积大户。一个32×32的乘法器,面积能顶几百个门。怎么优化?
- 如果乘数是常数,用移位加实现。比如
a * 5可以写成(a << 2) + a - 如果精度要求不高,用截断乘法器
- 如果芯片有DSP硬核,优先用硬核
比较器优化:比较器其实是个减法器加判断逻辑。面积优化的关键是减少位宽。比如你只需要判断 a > 100,那就只比较高位,低位可以忽略。嗯,这里要注意:如果比较结果用于控制逻辑,可以提前截断位宽。
我曾经做过一个视频处理芯片,里面有个模块要比较像素值和阈值。原始代码写的是 if (pixel > threshold),两个都是10位。后来我发现阈值只有高6位会变化,低4位固定。于是改成只比较高6位,面积直接省了40%。
最后说一句,综合阶段的面积优化,其实是个平衡的艺术。你省了加法器的面积,可能就要在乘法器上多花点。你压缩了逻辑深度,可能就要增加寄存器。嗯,这就是数字后端设计的魅力所在——永远在权衡。
可可精品资料库