综合实战:SMIC 28nm综合库选择、多阈值单元策略与脚本编写
各位同学,今天咱们来聊聊综合这个环节。说实话,综合在数字后端流程里,经常被低估。很多人觉得把RTL扔进去,跑个脚本就完事了。但我在28nm项目上吃过亏,才明白综合阶段的选择,直接决定了后面PR(布局布线)是顺风顺水,还是天天修时序。
SMIC 28nm这个节点,跟老工艺最大的区别是什么?是漏电和性能的矛盾变得非常尖锐。你想想看,芯片越做越小,漏电就成了大问题。所以,多阈值单元(Multi-Vt)策略,就成了我们必须掌握的核心技能。
1. 综合库的选择:别小看这一步
SMIC 28nm的综合库,通常会给几类:
- 典型库(Typical):用于功能仿真,综合时一般不用。
- 最差库(Worst Case):我们综合时最常用的。它模拟了最恶劣的工艺角(比如慢工艺、高温、低压)。
- 最佳库(Best Case):用于hold time检查,综合阶段基本不碰。
我个人习惯,综合时只选 WC(Worst Case) 库。为什么?因为综合的目标是保证setup time(建立时间)在最差条件下能过。你如果用Typical库综合,到了PR阶段,时序收敛会非常痛苦。
重点: 综合库的PVT(工艺、电压、温度)选择,一定要跟后端sign-off的corner对齐。SMIC 28nm的WC库,通常是SS(Slow-Slow)工艺角,0.9V,125°C。
2. 多阈值单元(Multi-Vt)策略:性能与功耗的平衡木
多阈值单元,说白了就是有不同开关速度的晶体管。阈值电压(Vt)越低,开关越快,但漏电越大;Vt越高,开关越慢,但漏电越小。
SMIC 28nm的库,一般提供三种:
| 单元类型 | 阈值电压 | 速度 | 漏电 | 典型应用场景 |
|---|---|---|---|---|
| LVT(Low Vt) | 低 | 快 | 高 | 关键路径、高频模块 |
| RVT(Regular Vt) | 中 | 中 | 中 | 大部分逻辑路径 |
| HVT(High Vt) | 高 | 慢 | 低 | 非关键路径、低功耗区域 |
我在项目中遇到过这样的情况:为了追求性能,整个设计全用了LVT单元。结果呢?芯片是能跑了,但功耗超标,封装散热搞不定,最后只能降频使用。这就是典型的「捡了芝麻丢了西瓜」。
所以,我的策略是:
- 先全用RVT:让综合工具先跑一遍,看看时序瓶颈在哪里。
- 局部替换LVT:只对时序紧张的路径,用LVT单元替换。工具会自动做,但我们要给工具正确的约束。
- 非关键路径用HVT:那些时序很宽松的路径,全部换成HVT,省电。
小技巧: 在综合脚本里,可以用 set_max_leakage_power 和 set_max_dynamic_power 来引导工具自动选择Multi-Vt单元。但别指望工具能完全替你决策,关键路径还是要人工review。
3. 综合脚本编写:从零到一
好,咱们直接上干货。一个典型的SMIC 28nm综合脚本,大概长这样:
# 设置库路径
set target_library "scc28nll_hvt_ss0p9v125c.db \
scc28nll_rvt_ss0p9v125c.db \
scc28nll_lvt_ss0p9v125c.db"
set link_library "* $target_library"
set symbol_library "scc28nll.sdb"
# 读入设计
analyze -format verilog {top.v sub_module.v}
elaborate top
# 设置时序约束
create_clock -name clk -period 2.0 [get_ports clk]
set_clock_uncertainty 0.1 [get_clocks clk]
set_input_delay -max 0.5 -clock clk [all_inputs]
set_output_delay -max 0.5 -clock clk [all_outputs]
# 设置功耗约束
set_max_leakage_power 0.1 mW
set_max_dynamic_power 50 mW
# 编译策略
compile_ultra -gate_clock -no_autoungroup
# 输出网表
write -format verilog -hierarchy -output ./output/top_synth.v
write_sdc ./output/top_synth.sdc
嗯,这里要注意几个点:
compile_ultra是Synopsys DC的强力编译选项,它会做更多的优化,比如retiming、边界优化等。对于28nm设计,我建议用这个。-gate_clock选项会把时钟门控逻辑综合进去,这对降低动态功耗很有帮助。-no_autoungroup是为了保持层次化结构,方便后续PR阶段做floorplan。
避坑指南: 我曾经在综合时忘了加 -no_autoungroup,结果工具把所有的子模块都打平了。到了PR阶段,floorplan完全没法做,因为关键模块的边界全没了。最后只能重新综合,浪费了两天时间。
4. 面积与功耗优化:实战中的取舍
面积和功耗,往往是矛盾的。你想省面积,就得用更小的cell,但小cell驱动能力弱,容易导致时序变差,进而需要插入buffer,面积又上去了。
我的优化思路是这样的:
- 先满足时序:时序是硬指标,不满足时序,芯片就是废的。
- 再优化面积:在时序余量允许的情况下,用面积更小的cell替换。
- 最后压功耗:通过Multi-Vt策略和时钟门控,把漏电和动态功耗降下来。
具体到脚本里,可以这样操作:
# 面积优化
set_max_area 0
compile_ultra -incremental -area_high_effort_script
# 功耗优化
set_leakage_optimization true
set_dynamic_optimization true
compile_ultra -incremental -power
这里用了 -incremental 选项,意思是增量编译。它不会推翻之前的优化结果,而是在现有基础上做微调。这样既保证了收敛速度,又不会引入新的时序问题。
个人经验: 在SMIC 28nm上,我一般会跑两轮综合。第一轮用 compile_ultra 做全局优化,第二轮用 compile_ultra -incremental 做局部微调。两轮之间,我会手动检查一下关键路径的cell类型分布,确保LVT单元没有被滥用。
最后,我想说一句:综合不是一锤子买卖。你可能会跑很多次,调整约束、换库、改策略,才能得到一个满意的结果。但正是这些反复的尝试,才让我们对工艺和设计有了更深的理解。
好了,这一章的内容就到这里。下一章,咱们聊聊布局规划(Floorplan),那可是后端设计的「地基」。