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
我的建议: 如果你做的是高性能CPU或GPU,时钟树要求极致的skew控制,Innovus更顺手。如果是大型SoC集成,时钟域多且复杂,ICC2的自动化能帮你省不少时间。

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_varset_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_MODECTS_DEBUG 不要随便设。有些调试模式会输出大量中间文件,把磁盘撑爆。我见过同事的服务器因为日志文件太大直接卡死。

3.3 基本CTS命令概览:先混个脸熟

好了,环境配好了,咱们看看最常用的几条命令。我不打算列一个长长的命令列表,那没意思。我只说几个你一定会用到的,以及它们背后的逻辑。

1. 创建时钟树定义

在Innovus里,CTS的第一步是告诉工具:哪些是时钟根节点。用 specifyClockTree 命令:

specifyClockTree -clknet CLK -bufFootprint BUF -invFootprint INV

这里 -bufFootprint-invFootprint 指定了工具可以用哪些缓冲器和反相器来构建时钟树。我一般会选驱动能力中等、延迟线性度好的单元,比如 BUFX8CLKBUFX12。驱动太小的单元会引入大延迟,太大的又容易产生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次就够了。多了反而可能把树搞乱,而且耗时很长。

核心要点: CTS不是一次就能跑好的。我通常的做法是:先跑一次全局CTS,看skew和latency;然后根据结果调整约束(比如设置 set_clock_tree_options 里的 -target_skew-target_latency);再跑一次优化。如此反复,直到满足要求。

好了,这一章就到这里。下一章我会讲如何写一个完整的CTS脚本,包括怎么处理多时钟域和异步时钟。到时候咱们再细聊。