4、组合逻辑延迟优化:逻辑级数优化、扇出优化、逻辑重构、路径重定时
组合逻辑的延迟,说白了就是信号从输入到输出,在逻辑门里“跑”一趟花的时间。我早年做第一个项目时,综合后时序一片红,老板拍着桌子问怎么回事。后来发现,就是组合逻辑太深了,信号绕了太多弯。今天咱们就把这四种优化手段掰开揉碎讲清楚。
4.1 逻辑级数优化:别让信号爬太多层楼梯
逻辑级数,就是信号经过的逻辑门数量。级数越多,延迟越大。这就像爬楼梯,爬10层和爬3层,哪个快?
核心原则:尽量让关键路径的逻辑级数控制在 3-5 级以内。超过这个数,时序大概率会出问题。
我习惯在综合后先看关键路径的报告。如果发现某条路径有 8 级逻辑,那基本可以断定要优化了。怎么优化?
- 展开逻辑:把嵌套的 if-else 或 case 语句拆开。比如一个 8 选 1 的多路选择器,用 case 实现可能只有 1 级,但用 if-else 嵌套就是 8 级。
- 使用并行结构:能用并行就别用串行。比如计算 a*b + c*d,别写成 (a*b) + (c*d) 这种两级加法,而是用两个乘法器并行算,最后一级加法合并。
- 插入流水线:如果逻辑级数实在降不下来,就在中间插一级寄存器。这招叫“时间换空间”,后面会细说。
我的经验:有一次做视频处理芯片,一个 32 位加法器链用了 6 级。我把它拆成 4 级加法器 + 2 级流水线,频率直接从 200MHz 飙到 400MHz。嗯,有时候就是一层窗户纸。
4.2 扇出优化:别让一个信号带太多负载
扇出,就是一个信号要驱动多少个门。扇出越大,信号上升/下降时间越长,延迟就越大。你想想看,一个人喊话给 100 个人听,和喊给 10 个人听,哪个更累?
我见过最夸张的案例,一个时钟使能信号扇出了 2000 多个触发器。结果呢?时序收敛不了,整个芯片重做了一版。血的教训。
扇出优化的常用手段:
- 复制寄存器:把高扇出的信号复制几份,每份驱动一部分负载。比如一个信号要驱动 100 个门,复制成 4 份,每份驱动 25 个。
- 插入缓冲器:在信号路径上加缓冲器(buffer),相当于给信号“加油”。但注意,缓冲器本身也有延迟,别加太多。
- 逻辑重构:把扇出大的信号放在逻辑树的根部,而不是叶子。这样信号路径更短。
注意:复制寄存器时,要确保复制后的信号在功能上等价。我曾经犯过一个错,复制了一个复位信号,结果两个副本的时序不同步,导致部分寄存器没复位。嗯,从那以后我每次复制都会加约束。
4.3 逻辑重构:重新排列组合,让路径更短
逻辑重构,就是改变逻辑门的连接方式,但不改变功能。这有点像整理书架——书还是那些书,但摆放顺序变了,找书就更快。
举个例子,一个表达式:Y = (A & B) | (C & D) | (E & F)。如果按顺序实现,需要三级逻辑:先算三个与门,再算两个或门。但如果重构一下:
// 原始实现
wire ab = A & B;
wire cd = C & D;
wire ef = E & F;
wire y = ab | cd | ef; // 三级
// 重构后
wire ab_cd = (A & B) | (C & D);
wire y = ab_cd | (E & F); // 两级
你看,级数从三级降到了两级。虽然功能一样,但延迟少了。
我常用的重构技巧:
- 提取公因子:比如
(A & B) | (A & C)可以写成A & (B | C),减少一个与门。 - 平衡树结构:把不平衡的加法树或乘法树改成平衡结构。比如 8 个数相加,用平衡树只需要 3 级,而串行需要 7 级。
- 使用卡诺图:对于复杂逻辑,画个卡诺图,找出最简表达式。这招虽然老,但管用。
避坑指南:我曾经重构一个状态机,把组合逻辑从 5 级降到了 3 级,但忘了检查毛刺。结果仿真没问题,实测时状态跳错了。所以重构后一定要做后仿真,看看有没有 glitch。
4.4 路径重定时:把延迟“匀一匀”
路径重定时(Retiming),就是把组合逻辑的延迟在寄存器之间重新分配。说白了,就是把慢路径上的逻辑挪一点到快路径上,让所有路径的延迟差不多。
这就像分蛋糕——有人分多了,有人分少了,重新切一切,大家就都满意了。
重定时有两种方式:
- 前向重定时:把寄存器从组合逻辑的输入端移到输出端。比如一个 3 级逻辑,前两级很快,第三级很慢。可以把寄存器插在第二级之后,让第三级单独占一个周期。
- 后向重定时:反过来,把寄存器从输出端移到输入端。适用于输入路径慢、输出路径快的情况。
举个例子,一个 4 级加法器链,每级延迟 2ns,总延迟 8ns。如果时钟周期是 5ns,那肯定不行。但如果在第 2 级和第 3 级之间插一个寄存器,就变成了两个 4ns 的路径,每个都能满足 5ns 的时序。
关键点:重定时不改变功能,只改变时序。但要注意,重定时后可能会增加或减少寄存器数量。我一般用综合工具的 retime 选项自动做,但也会手动检查关键路径。
我个人习惯,在综合时先跑一遍 retime,看看时序能不能收敛。如果不行,再手动调整。有一次做网络芯片,一个 128 位加法器怎么都跑不到 1GHz。后来手动重定时,把加法器拆成 4 段,每段插一个寄存器,频率直接达标。嗯,有时候工具不如人聪明。
4.5 四种方法的对比与选择
这四种方法不是孤立的,实际项目中往往要组合使用。我整理了一个表格,方便你对比:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 逻辑级数优化 | 路径级数过多(>5级) | 效果直接,延迟降低明显 | 可能增加面积 |
| 扇出优化 | 高扇出信号(>100) | 改善信号完整性 | 增加功耗和面积 |
| 逻辑重构 | 复杂组合逻辑 | 不增加寄存器,纯组合优化 | 需要手动分析,容易引入毛刺 |
| 路径重定时 | 路径间延迟不均衡 | 自动优化,工具支持好 | 可能增加寄存器数量 |
我的建议是:先看逻辑级数,如果太高就降级数;再看扇出,如果太大就复制寄存器;然后看逻辑结构,能不能重构得更平衡;最后用重定时收尾。这四步走下来,大部分时序问题都能解决。
最后提醒:优化组合逻辑时,别忘了检查功耗和面积。我曾经为了追求极致时序,把面积翻了一倍,结果芯片成本太高,项目被砍了。嗯,平衡才是王道。