3、时钟树综合工具入门:主流CTS工具介绍(Innovus、ICC2)、工具环境配置、基本CTS命令概览
好,咱们进入第三章。这一章我打算聊聊CTS工具本身。你可能会想,工具嘛,不就是跑个命令?其实没那么简单。我见过不少新手,上来就敲 clockDesign,结果跑出来的时钟树歪歪扭扭,setup和hold全崩。嗯,工具是死的,但怎么用它,是门手艺。
3.1 主流CTS工具:Innovus vs ICC2
目前业界主流的物理实现工具,说白了就两家:Cadence的Innovus和Synopsys的ICC2。这两家我都用过,各有各的脾气。
Innovus(Cadence)
我个人习惯用Innovus做CTS。它的时钟树引擎叫 Clock Design(简称CD)。我觉得它最大的优点是——灵活。你可以用Tcl脚本把整个流程串起来,每一步都能干预。比如,你可以先做一条长时钟线的延迟补偿,再做全局平衡。我在项目中遇到过一条时钟线横跨了整个芯片,Innovus的 specifyClockTree 命令让我能精细控制每一段走线,最后skew压到了20ps以内。
ICC2(Synopsys)
ICC2的CTS引擎叫 Clock_CT。它的特点是自动化程度高,尤其擅长处理多时钟域和复杂分频场景。你想想看,一个SoC里可能有几十个时钟域,ICC2的 create_clock_tree 命令能自动识别时钟源和同步器,省去不少手动标注的功夫。不过,它的脚本语言是Tcl + 一些Synopsys特有的命令,刚开始上手会觉得有点绕。
| 特性 | Innovus | ICC2 |
|---|---|---|
| 引擎名称 | Clock Design (CD) | Clock_CT |
| 脚本语言 | Tcl | Tcl + Synopsys扩展 |
| 灵活性 | 高(可精细控制) | 中(自动化强) |
| 多时钟域处理 | 需手动设置 | 自动识别 |
| 典型命令 | clockDesign |
create_clock_tree |
3.2 工具环境配置:别让环境坑了你
配置工具环境,听起来像是个杂活,但这里坑特别多。我曾经因为一个环境变量没设对,CTS跑了一整天,结果发现工具根本没读到时钟约束文件。嗯,从那以后我每次跑CTS前都会检查三样东西。
第一,库文件路径
工具需要知道标准单元库、IO库、特殊单元库(比如时钟缓冲器)在哪里。在Innovus里,用 set_db 命令设置:
set_db library {/path/to/your/lib/slow.lib /path/to/your/lib/fast.lib}
set_db lef_library {/path/to/your/lef/tech.lef /path/to/your/lef/cells.lef}
在ICC2里,用 set_app_var 或 set_db:
set_app_var target_library "slow.db fast.db"
set_app_var link_library "* $target_library"
注意顺序——慢库在前,快库在后。为什么?因为工具默认用第一个库做优化基准,慢库更保守,能避免过度乐观。
第二,时钟约束文件
CTS的核心输入是SDC约束。你需要在SDC里定义好时钟周期、波形、生成时钟、以及时钟组。我习惯在CTS前单独跑一遍 check_timing,确保没有未约束的路径。命令很简单:
# Innovus
check_timing -verbose
# ICC2
check_timing -verbose
如果报出 unconstrained_path,千万别跳过。我曾经跳过了一次,结果CTS把一条异步路径当同步路径处理了,插了一堆缓冲器,功耗直接炸了。
第三,工作目录和日志
每次CTS跑完,我都会把日志、报告、数据库存到以时间戳命名的目录里。比如:
mkdir -p ./cts_runs/$(date +%Y%m%d_%H%M%S)
cd ./cts_runs/$(date +%Y%m%d_%H%M%S)
这样万一跑崩了,还能回滚到上一个版本。别问我怎么知道的——有一次我忘了备份,结果CTS把整个设计搞乱了,重跑了三天。
CTS_MODE 或 CTS_DEBUG 不要随便设。有些调试模式会输出大量中间文件,把磁盘撑爆。我见过同事的服务器因为日志文件太大直接卡死。
3.3 基本CTS命令概览:先混个脸熟
好了,环境配好了,咱们看看最常用的几条命令。我不打算列一个长长的命令列表,那没意思。我只说几个你一定会用到的,以及它们背后的逻辑。
1. 创建时钟树定义
在Innovus里,CTS的第一步是告诉工具:哪些是时钟根节点。用 specifyClockTree 命令:
specifyClockTree -clknet CLK -bufFootprint BUF -invFootprint INV
这里 -bufFootprint 和 -invFootprint 指定了工具可以用哪些缓冲器和反相器来构建时钟树。我一般会选驱动能力中等、延迟线性度好的单元,比如 BUFX8 或 CLKBUFX12。驱动太小的单元会引入大延迟,太大的又容易产生EM问题。
2. 运行时钟树综合
这是核心命令。Innovus里是 clockDesign,ICC2里是 create_clock_tree。用法:
# Innovus
clockDesign -specFile clock.spec -outDir cts_output -updateTiming
# ICC2
create_clock_tree -clock_trees {CLK} -name cts_main
跑完后,工具会生成一个 .cts 文件(Innovus)或 .ctstch 文件(ICC2),里面记录了时钟树的拓扑结构。我建议你打开看一眼,确认时钟源、分支点、末端寄存器都连对了。
3. 检查时钟树质量
CTS跑完,别急着往下走。先看看skew和latency。Innovus用 report_clock_timing:
report_clock_timing -type skew -nworst 10
ICC2用 report_clock_skew:
report_clock_skew -clock CLK -verbose
我一般会关注两个指标:全局skew(所有寄存器之间的最大差值)和局部skew(同一时钟域内相邻寄存器之间的差值)。局部skew更重要,因为它直接影响hold timing。如果局部skew超过50ps,我会考虑调整时钟树结构。
4. 优化时钟树
如果skew不满足要求,可以用 refineClockTree(Innovus)或 optimize_clock_tree(ICC2)做局部优化:
# Innovus
refineClockTree -targetSkew 30ps -maxIterations 5
# ICC2
optimize_clock_tree -clock_trees {CLK} -target_skew 30ps
注意,迭代次数别设太大,3到5次就够了。多了反而可能把树搞乱,而且耗时很长。
set_clock_tree_options 里的 -target_skew 和 -target_latency);再跑一次优化。如此反复,直到满足要求。
好了,这一章就到这里。下一章我会讲如何写一个完整的CTS脚本,包括怎么处理多时钟域和异步时钟。到时候咱们再细聊。