简介:面向集成电路物理实现工程师的Cadence技术文档,聚焦Innovus 18.1/19.1中CCOpt时钟树综合与优化工具在复杂时钟网络上的配置与调试方法。内容按时钟网络分析、时钟树构建、时钟优化、后处理验证四个阶段展开,逐一说明各阶段的调试点,并涵盖时钟树调试器的使用、时钟路径追踪与设计视图交叉探测、报告命令、CCOpt属性分析,以及架构级时钟控制与sink修改等进阶议题,例如阻断数据通路、刻意制造偏斜、平衡互不相交的时钟树、管理不应被偏斜的复杂控制逻辑,适合已具备一定CTS基础、需要处理高扇出与多时钟域问题的设计者查阅。压缩包共1个PDF文件,合计约1.3MB,为2019年4月的产品文档,篇幅紧凑便于随查。已有211人学习下载,可作为CTS调优阶段的对照手册:帮助读者定位时钟树瓶颈与延迟不均,理解各阶段调试入口,串联从分析到验证的排错思路。
1. 复杂时钟网络先停在抽取后:CCOpt 不是一键 CTS
在 innovus cts 流程里,CCOpt 常被当成一个“跑完看时序”的按钮,真正麻烦的却是时钟结构复杂、SDC 无法完整描述时钟架构的设计。这份 Innovus 18.1/19.1 应用笔记把 CCOpt 拆成抽取、cluster、trial、full、路由与数据路径优化几个观察点,重点不是命令大全,而是告诉你每个阶段能推断出什么、哪些属性必须在抽取前钉死。它适合已经能跑基本 CTS、但在多时钟域、门控时钟、宏单元馈通和跨时钟平衡上反复翻车的物理设计工程师。新手可以照着属性表补配置,熟手更应该拿它做阶段停点检查。不要急着跑完整流程,先让抽取结果可解释。
2. 从 SDC 到 skew group:运行前把四类属性钉死
复杂时钟网络第一步不是打开 CCOpt 跑 full,而是承认一件事:SDC 是给时序分析用的,不是给时钟树综合用的。SDC 里写的是时钟周期、输入输出延迟、例外路径和时序检查,它不会告诉工具“这条时钟应该用哪类 buffer”“这个门控时钟单元要不要参与优化”“这个宏单元的时钟馈通要不要继续往下追”。CCOpt 能从库、设计和约束里自动抽取很多设置,但应用笔记明确提醒,这些数据源大多面向 sign-off,自动抽取的结果不一定适合生成时钟网络。真正影响结构的是抽取前那几类属性,设错一个,后面 debugger 里看到的树可能就是被裁剪过的假象。
2.1 为什么 SDC 不能直接当 CCOpt 配置
先理解两个术语的边界。skew group 是时钟网络的结构片段,CCOpt 用它来建结构、做初始平衡;clock tree 是用于平衡的时钟网络子集。多数设计里两者是一对一,复杂结构里一个 clock tree 可能对应几个 skew group。这个区别很关键:你在 SDC 里改时钟定义,不等于改掉了 skew group 的划分;你在抽取后改 clock tree,也不一定改变结构片段的归属。很多“为什么这条时钟没进树”的问题,根因不是 SDC 写错,而是抽取阶段把某个 pin 设成了 stop、ignore 或 exclude,或者 cell list 把某类单元过滤掉了。
我一般把运行前配置分成四类:单元选择、过渡与 skew 目标、sink_type 形状控制、布线规则。单元选择决定工具能用哪些 buffer、inverter、clock gating cell 和 logic cell;过渡目标决定时钟网络能做多小;skew 目标决定平衡力度;sink_type 决定时钟树追到哪儿停;布线规则决定后面 non-default rule 能不能落到 leaf、trunk、top 三类网络上。这四类不先钉死,后面在 debugger 里点半天,很可能只是在给一个错误抽取结果做“玄学调参”。
提示:抽取前设置的全局属性会改变时钟抽取过程,抽取后设置的 clock tree / skew group 属性更多是局部修正。不要把两者混在一个脚本里盲目重跑。
2.2 四类必须显式设置的属性与双写法
应用笔记同时给了传统命令和 CUI/Stylus 写法。传统写法里常见set_db cts_*,CUI 写法里常见set_ccopt_property。两套命令不要混着抄,先确认当前脚本走的是哪套接口。下面这段是运行前最值得先落地的一组配置,示例单元名和数值只是占位,实际要按工艺库替换。
# 传统命令写法:先声明可用单元,再给过渡与 skew 目标 set_db cts_buffer_cells {CLKBUF_X1 CLKBUF_X2 CLKBUF_X4} set_db cts_inverter_cells {CLKINV_X1 CLKINV_X2} set_db cts_clock_gating_cells {CLKGT_X1 CLKGT_X2} set_db cts_logic_cells {CLKLOGIC_X1} # 过渡和 skew 目标不要照搬 sign-off 的最紧值 set_db cts_target_max_transition_time 0.12 set_db cts_target_skew 0.15 # 芯片级或复杂架构常需要关掉 IO latency 自动修改 set_db cts_update_clock_latency false# CUI/Stylus 写法:同一组属性的另一套接口 set_ccopt_property buffer_cells {CLKBUF_X1 CLKBUF_X2 CLKBUF_X4} set_ccopt_property inverter_cells {CLKINV_X1 CLKINV_X2} set_ccopt_property clock_gating_cells {CLKGT_X1 CLKGT_X2} set_ccopt_property logic_cells {CLKLOGIC_X1} set_ccopt_property target_max_trans 0.12 set_ccopt_property target_skew 0.15 set_ccopt_property update_io_latency false这段代码的逻辑很直接:先把工具可选的单元范围收窄,再给过渡和 skew 一个明确目标,最后决定是否让工具改 IO latency。参数上最容易被误用的是 cell list。空列表有特殊含义,表示所有单元都可能被选中,不区分 Vt 族和驱动能力,这不是推荐做法;如果设计里有 always-on 单元,必须显式加进列表。另一个容易忽略的点是,CCOpt 属性里设置的单元会覆盖库定义的 dont_use,但从 18.1 开始,用户手动加的 don’t touch 会被尊重。也就是说,不要一边在库里标 dont_use,一边在 CCOpt 列表里把同一类单元塞进去,然后奇怪为什么工具不听话。
过渡目标和 skew 目标也不是越紧越“安全”。过渡目标过紧会把时钟网络往更大驱动、更多 buffer 的方向推;skew 目标过紧会触发过度平衡。应用笔记里专门提到,低功耗设计里过渡目标尤其重要,因为它直接影响时钟网络尺寸。我的做法是先按库的 DRV 和 sign-off 要求给一个可解释的全局值,再在抽取后对个别 clock tree / skew group 做覆盖,而不是一上来拿最紧值压全设计。
布线规则也属于运行前就该确认的设置。时钟网络通常需要 non-default rule,但规则要能落到 leaf、trunk、top 三类网络上,否则后面 route 阶段会出现“规则建了但没挂上”的情况。下面这段是常见写法,create_route_type的参数要按工艺规则补全,不能直接照抄省略号。
# 建立时钟非默认布线规则,并挂到三类时钟网络 create_route_type -name clock_non_default_rule_1 \ -top_preferred_layer M5 -bottom_preferred_layer M3 \ -shield_net VSS -snap_wire_center_to_grid set_ccopt_property route_type -net_type {leaf trunk top} clock_non_default_rule_1 # 传统接口对应写法 set_db cts_route_type_top clock_non_default_rule_1 set_db cts_route_type_trunk clock_non_default_rule_1 set_db cts_route_type_leaf clock_non_default_rule_1这里-net_type后面的{leaf trunk top}不是装饰,它决定规则覆盖哪一层时钟网络。只挂 top 不挂 leaf,leaf 段可能仍然走默认规则;只挂 leaf 不挂 trunk,主干可能没有屏蔽和线宽约束。参数值要按金属层和工艺规则改,不要硬编码别处的层号。
2.3 抽取后改 clock/skew group 与验证过滤原因
抽取完成后,应用笔记建议做的事包括:修改已创建的 clock / skew group,增加或删除 skew group,对个别 clock 或 skew group 施加属性,以及修改从 SDC 抽取出来的属性。比如 SDC 派生的过渡和 skew 目标,在没有全局目标时会被使用;如果你已经设了全局目标,就要明确哪些局部覆盖是有意为之。这个阶段最怕“只改不看”:改完 skew group 不确认 sink 是否还在树里,改完 cell list 不确认过滤原因,最后 full 跑完才发现树的结构已经偏了。
验证过滤原因的两条命令很实用:
# CUI 接口:查看 CCOpt 单元过滤原因 report_ccopt_cell_filtering_reasons # 传统接口:查看 CTS 单元过滤原因 report_cts_cell_filtering_reasons这两条命令的输出用来回答一个问题:你明明把某类 buffer 放进了列表,为什么工具没用。常见原因包括库 dont_use、驱动能力过滤、Vt 族限制、always-on 条件不满足,以及用户 don’t touch。先看过滤原因,再去调 target 或换单元,顺序不能反。下面这张表可以作为抽取后的检查顺序。
| 检查项 | 看什么 | 常见误判 |
|---|---|---|
| cell filtering | 列表里的单元为什么被过滤 | 以为设了 list 就一定会用 |
| target 生效范围 | 全局目标是否被局部覆盖 | 只看全局值,不看 clock/skew group |
| sink_type | 哪些 pin 被 stop/ignore/exclude | 把不该停的负载截断 |
| route type | leaf/trunk/top 是否都挂上规则 | 只挂 top,leaf 仍走默认规则 |
这张表的作用不是让你逐项打勾,而是建立排查顺序:先确认单元可用,再确认目标作用域,再确认时钟树追到哪儿,最后确认布线规则。顺序反了,就会在 debugger 里对着一个已经被裁剪的树找瓶颈。
3. 拆开 cluster、trial 与 full:每个阶段该看哪张表
CCOpt 的时钟构建可以拆成 cluster、trial、full 三个主要阶段。应用笔记特别提醒,停在 cluster 或 trial 阶段后,不能从停点重启 CCOpt run。这句话看起来像流程限制,实际是调试策略的分水岭:cluster 和 trial 应该被当成只读诊断点,用来观察结构和预算,不是用来“停一下改个属性再续跑”的。要改属性,就回到抽取前重跑;只想看结构,就在停点把该看的表看完。复杂时钟网络里,很多优化机会在中间阶段就能看出来,但前提是你知道每个阶段该看什么。
3.1 cluster 阶段:先看结构雏形和 sink 分类
cluster 阶段是结构雏形形成的阶段。此时工具开始根据 skew group、sink 分类、过渡目标和 skew 目标做聚类。这个阶段最值得看的是 sink 有没有被错误截断,以及 skew group 的数量有没有异常膨胀。sink_type 的 stop、ignore、exclude 会直接改变时钟网络抽取的形状;如果某个宏单元内部时钟馈通被错误地继续往下追,cluster 可能会把不该平衡的负载拉进来;反过来,如果某个门控时钟输出被过早 stop,后面的负载就不在树里,full 阶段时序看起来“干净”,实际是漏了 sink。
我一般会在 cluster 停点做三件事。第一,确认关键时钟的 sink 数量和预期一致,尤其是多路门控、宏单元馈通、输出 pin 驱动逻辑这几类边界。第二,确认 skew group 的划分没有因为 SDC 里的 generated clock 或虚拟时钟而爆炸。第三,确认 target_max_trans 和 target_skew 在这个阶段已经生效,因为这两个目标会影响 clustering;如果等到 full 阶段才发现目标过紧,cluster 阶段的结构已经定型,只能重跑。
这个阶段不要做的事也很明确:不要在这里改 cell list 然后指望续跑。cluster 停点适合观察,不适合热修改。下面这张表把阶段和观察点对齐。
| 阶段 | 主要观察点 | 不适合做的事 |
|---|---|---|
| cluster | sink 分类、skew group 数量、聚类雏形 | 改属性后从停点续跑 |
| trial | 缓冲预算、平衡策略、过渡分布 | 把 trial 结果当最终签核 |
| full | 完整时钟树、路由前结构、数据路径优化边界 | 不看抽取直接怀疑 full 算法 |
3.2 trial 阶段:平衡策略与缓冲预算的预演
trial 阶段更像一次平衡策略预演。此时可以看到缓冲器数量、时钟树层级、过渡分布和 skew 平衡趋势。应用笔记把 trial 和 cluster 放在同一个“不能重启”的限制里,意思是这个阶段的定位是诊断,不是交互式调参。trial 阶段最有价值的观察是“预算感”:如果 trial 已经出现 buffer 数量明显偏高、层级明显变深,full 阶段大概率不会自动变好,反而可能因为路由和寄生参数进一步恶化。
这里有个血泪经验:不要因为 trial 的 skew 数字漂亮就放心开 full。trial 阶段的布线寄生和抽取设置可能还不完整,真正的时钟网络在 early global route、Nanoroute 和 conditioning 之后才会暴露问题。trial 阶段应该看趋势,不是看绝对值。趋势包括:某个 skew group 是否比同类树多出明显层级;某条门控时钟分支是否出现异常 buffer 链;过渡目标是否让工具在局部反复插入小驱动单元。
如果你在 trial 阶段发现某个 slave clock 被强行和 master clock 平衡,或者两个本来不相交的时钟树被拉到一起,这时应该回到抽取阶段检查 skew group 和 sink_type,而不是在 trial 停点找“继续”按钮。应用笔记里有一整节讲架构级时钟控制,包括阻止数据路径部分进入时钟网络、对时钟点做有意偏斜、平衡不相交时钟树、阻止来自共同 master 的 slave clock 被平衡、处理宏单元时钟馈通、禁用某些时钟的综合、防止过度缓冲。这些手段都发生在结构配置层,不是 trial 停点的补丁。
3.3 full 与路由后:把时钟树和 data path 优化分开看
full 阶段是完整时钟树构建,之后还有 early global route 和 conditioning、Nanoroute 和 conditioning、数据路径优化。CCOpt 的一个特点是可选地并发优化数据路径,这对时序和功耗有好处,但调试复杂时钟网络时,它会让问题边界变模糊:时钟树变差,可能是时钟结构问题,也可能是数据路径优化把时钟拉过去了。我的建议是调试初期先把时钟树和数据路径优化的观察分开,确认时钟结构可解释后,再打开并发优化看收益。
full 之后不要只看最终时序报告。先看时钟树本身:leaf 数量、层级、过渡、skew group 内的平衡结果、有没有异常长的 buffer 链。然后再看路由后的 conditioning 有没有改变时钟拓扑。最后再看数据路径优化是否影响了时钟。应用笔记把 post-CTS 优化和时序设置放在流程前面,例子包括关闭 latency 修改和设置 OCV delay 模式。芯片级设计或复杂架构里,update_io_latency false很关键,因为工具自动改 IO latency 会让时钟路径的参考点发生变化,后面路径追踪会对不上。
# post-CTS 时序与 OCV 设置示例,参数按版本和工艺补全 set_ccopt_property update_io_latency false set_db cts_update_clock_latency false # 传统接口的 OCV 设置 setAnalysisMode -analysisType onChipVariation set_db timing_analysis_type ocv # CUI 接口按当前命令参考补 delay calculation 参数 # set_db delaycal_* ...这段代码的重点不是 OCV 的具体数值,而是两个开关:是否允许工具修改 IO latency,以及时序分析是否进入 OCV 模式。前者影响时钟路径参考点,后者影响你在 full 后看到的时序裕量。参数细节要按工艺和版本补,不能把示例当签核配置。
4. 时钟树调试器和路径追踪:把平衡结果反查到负载
复杂时钟网络调试最怕“图上看不懂,报表里对不上”。CCOpt 提供了时钟树调试器,可以用来观察时钟树结构、定位瓶颈、检查平衡结果;应用笔记还讲了时钟路径追踪和跨设计视图交叉探测,以及用报表命令和 CCOpt 属性获得设计洞察。工具给的是视图,真正要建立的是“从时钟源到负载”的反查路径:看到一个异常 skew,能追到哪个 skew group、哪类 sink、哪段布线规则、哪个被过滤的单元。没有这条反查路径,debugger 就只是一个好看的树状图。
4.1 基本检查先于 debugger:时钟路径、扇出、skew group 边界
打开调试器之前,先做基本检查。应用笔记把基本检查放在调试技术的第一项,这不是流程客套,而是因为很多“树看起来不对”的问题在基本检查阶段就能定位。检查项包括时钟路径延迟是否合理、时钟树平衡性是否在预期范围、时钟扇出比是否异常、skew group 边界是否和架构一致。比如某个门控时钟输出的扇出突然变得很大,可能是 clock gating cell 被当成了普通 logic cell 优化;某个宏单元内部时钟馈通被继续往下追,可能是 sink_type 没有在该停的地方停。
我一般会先看三类边界:时钟源到第一个缓冲器的路径、门控时钟单元前后的负载、宏单元和输出 pin 附近的时钟端点。这三类边界最容易出现“结构上不该平衡,但工具平衡了”的情况。基本检查不需要精确数值,先看数量级和拓扑是否符合预期。如果连 sink 数量都对不上,打开 debugger 只会放大困惑。
| 基本检查项 | 观察点 | 异常信号 |
|---|---|---|
| 时钟路径延迟 | 源到关键负载的级数 | 同级树延迟差异过大 |
| 扇出比 | 门控单元、宏单元边界 | 单点扇出异常膨胀 |
| skew group 边界 | 结构片段和架构对照 | 不相交时钟被分到一组 |
| sink 数量 | 关键时钟端点统计 | 比预期少或多 |
4.2 用 CCOpt Clock Tree Debugger 定位瓶颈
在 GUI 里打开 CCOpt Clock Tree Debugger 后,不要一上来就看整棵树。先选一条关键时钟或一个 skew group,按层级、过渡、skew 着色,观察异常分支。常见做法是先按过渡着色找长线和高负载段,再按 skew 着色找平衡偏差,最后交叉探测到 layout 或 schematic,确认某个缓冲器是不是被放到了不该放的位置。应用笔记提到时钟路径追踪和跨设计视图交叉探测,这个能力的价值在于把“树上的一个点”映射回“设计里的一个实例或一段网络”,否则你只知道这里慢,不知道这里为什么慢。
调试器里最容易误判的是“看起来平衡”的树。复杂时钟网络里,工具可能通过插入缓冲器把 skew 压到很小,但代价是 buffer 数量、功耗和拥塞上升。应用笔记提醒,过度紧的 skew 目标会导致过度平衡。所以在 debugger 里看到一条非常平的树时,不要先庆祝,先看它的 buffer 数和层级。如果一条树比同类树多出很多级,skew 很漂亮也可能是过度平衡。
另一个使用技巧是先确认 cell filtering,再打开 debugger。如果某类 buffer 被库 dont_use 或用户 don’t touch 过滤掉了,debugger 里看到的树是过滤后的结果,你在图上找“为什么不用更好的单元”永远找不到答案。应用笔记把报表命令和属性洞察放在调试技术里,就是为了让你在图形视图之外有一条数据反查路径。
4.3 用属性与报表反查:cell filtering、target 与 sink_type
报表反查的顺序可以固定下来:先看 cell filtering,再看 target 作用域,再看 sink_type,最后看 route type。这个顺序和第 2 章的抽取检查一致,但在调试阶段更强调“对照改前改后”。比如你为了减少 buffer 把 target_max_trans 放松了一点,就要看 cell filtering 是否导致工具换用了更小驱动的单元;你为了让某个 slave clock 不被平衡而改了 sink_type,就要看 sink 数量是否变化、debugger 里的端点是否还在。
# 调试阶段先确认单元过滤,再怀疑平衡算法 report_ccopt_cell_filtering_reasons report_cts_cell_filtering_reasons # 传统接口下可配合属性检查,确认目标是否被局部覆盖 # 具体属性查询命令按当前版本命令参考补全这两条报表命令的输出要结合属性设置看。如果过滤原因里出现大量 dont_use,而你的 cell list 又写得很窄,问题在单元选择;如果过滤原因正常,但某个 skew group 的平衡结果异常,问题更可能在 target 或 sink_type。不要把报表当日志扫一眼,报表是用来缩小范围的。我的习惯是每次改完抽取后配置,先跑一次过滤原因报表,把输出和配置一起存档;后面 full 出问题,至少能排除“单元根本没用上”这种低级原因。
交叉探测设计视图时,注意不要把“时钟路径追踪”当成“时序路径追踪”。时钟路径追踪看的是时钟网络从源到负载的结构,时序路径追踪看的是寄存器到寄存器的数据路径。复杂时钟网络里两者会互相影响,但调试时钟树时先看结构,再看时序。否则你会被一条 hold 违例带到数据路径优化里,忘了时钟树本身可能已经多插了两级 buffer。
5. 五个高频翻车现场:复杂时钟网络里的排查顺序
复杂时钟网络的坑很少是单点错误,更多是配置之间互相放大。下面五类翻车现场按排查顺序排列:先看目标是否过紧,再看单元是否可用,再看 sink 范围,再看停点使用方式,最后看数据路径是否被误纳入时钟平衡。每一类都按“现象、原因、解决”写,方便在 full 跑完后对照。
5.1 过渡目标过紧导致过度平衡
现象:full 后 buffer 数量明显增多,时钟树层级变深,功耗上升,局部拥塞变差,但 skew 报表看起来还不错。原因:target_max_trans 或 target_skew 设得比工艺和 sign-off 实际需要的更紧,工具为了满足目标不断插入更小驱动或更多缓冲器。应用笔记明确提到,过紧的 skew 目标会导致过度平衡,过渡目标在低功耗设计里尤其影响时钟网络尺寸。
解决:先把全局目标退回到可解释的值,再对个别 clock tree / skew group 做局部覆盖。不要用全局最紧值压所有树。检查时先看 cell filtering,确认工具不是因为没有合适驱动才反复插小单元;再看 trial 阶段的 buffer 预算趋势。如果一条树的 skew 很好但 buffer 数比同类树多出明显比例,优先怀疑目标过紧,而不是继续调布线规则。
5.2 空 cell list 与 dont_use 冲突
现象:明明设置了 buffer_cells,工具还是选了不希望用的单元;或者设置了一个空列表,结果全库单元都被纳入选择。原因:空列表有特殊含义,表示所有单元都可能被选中,不区分 Vt 族和驱动能力;CCOpt 属性里的单元会覆盖库定义的 dont_use,但 18.1 开始用户手动 don’t touch 会被尊重;always-on 单元如果没有加进列表,也可能在需要时不可用。
解决:显式列出可用单元,always-on 单独加进去,然后用过滤原因报表确认。下面这段是排查用的最小配置,单元名按库替换。
# 显式收窄单元列表,避免空列表导致全库扫描 set_ccopt_property buffer_cells {CLKBUF_X1 CLKBUF_X2 CLKBUF_X4} set_ccopt_property inverter_cells {CLKINV_X1 CLKINV_X2} set_ccopt_property clock_gating_cells {CLKGT_X1 CLKGT_X2} set_ccopt_property logic_cells {CLKLOGIC_X1} # 如果有 always-on 需求,必须显式加入对应单元 # set_ccopt_property buffer_cells [concat $buf_list $always_on_buf_list] report_ccopt_cell_filtering_reasons这段代码的逻辑是“先收窄,再验证”。参数上不要漏掉 clock gating cell 和 logic cell,否则门控时钟和时钟逻辑可能无法被优化,工具只能多插 buffer。空列表不要用来表示“默认”,这是最常见的误用之一。
5.3 sink_type 写错导致时钟树范围失真
现象:某些负载没有进时钟树,平衡结果看起来很好,但实际漏了 sink;或者数据路径的一部分被当成时钟端点,时钟树被拉到了不该去的地方。原因:stop、ignore、exclude 的语义用混了,或者批量套用属性时没有确认作用对象。应用笔记把 sink_type 放在抽取阶段,用来塑造时钟网络提取,说明它改变的是“树追到哪儿”,不是“树建好之后再修剪”。
解决:抽取前后都检查 sink 列表,关键宏单元、门控时钟输出、输出 pin 驱动逻辑逐个确认。不要在没有确认语义的情况下批量套用 stop/ignore/exclude。调试时用 debugger 看端点,用报表看数量,两者对不上就回到抽取阶段。下面这张表只作为排查方向,具体语义以当前版本命令参考为准。
| 设置方向 | 作用层面 | 排查动作 |
|---|---|---|
| stop | 截断追踪 | 确认被截断的负载是否真的不该进树 |
| ignore | 忽略某点 | 确认忽略后是否还有别的路径覆盖 |
| exclude | 排除对象 | 确认排除范围没有误伤同类单元 |
5.4 停在 trial 后想续跑却无法恢复
现象:在 cluster 或 trial 阶段停下来改了几个属性,想继续跑 full,发现不能从停点重启;或者强行重跑后结果和预期不一致。原因:应用笔记明确说明,CCOpt run 在 cluster 或 trial 阶段停止后不能重启。这个限制不是 bug,而是流程设计:cluster 和 trial 是构建过程中的诊断点,不是交互式调参断点。
解决:把 cluster 和 trial 当只读诊断。要改属性,回到抽取前重跑;要比较方案,保存完整配置脚本,用不同脚本跑两次,而不是在停点热改。我的血泪经验是给每次实验建一个配置快照,至少把 cell list、target、sink_type、route type 和局部 skew group 覆盖写在一个 tcl 文件里。这样 full 出问题,能回到“哪次配置变化导致”的问题上,而不是在一堆交互命令里找后悔药。
5.5 把数据路径误纳入时钟平衡
现象:为了修 hold 或跨域路径,给数据路径相关逻辑加了 skew 约束,结果时钟树被拉歪,原本正常的时钟分支出现额外缓冲。原因:CCOpt 可以并发优化数据路径,复杂控制逻辑不应该被 skew;宏单元时钟馈通、输出 pin 驱动逻辑、共同 master 派生的 slave clock 都需要单独处理。应用笔记在架构控制里专门列了这些场景,包括阻止数据路径部分进入时钟网络、管理不应被 skew 的复杂控制逻辑、保持输出 pin 驱动逻辑的相似 skew、处理宏单元时钟馈通。
解决:先确认时钟树结构可解释,再打开数据路径优化。对不该平衡的逻辑,用结构控制手段把它挡在时钟网络之外;对 slave clock,阻止它和共同 master 被强行平衡;对宏单元馈通,确认追踪是否应该继续。不要用全局 skew 目标去修局部数据路径问题,那是用时钟树的血去补数据路径的伤。
6. 架构级时钟控制:三组属性让不该平衡的时钟分开
复杂时钟网络到了架构级,命令已经不是重点,重点是“哪些结构不该被平衡”。应用笔记列了一串场景:阻止数据路径部分进入时钟网络、对时钟点做有意偏斜、平衡不相交时钟树、阻止来自共同 master 的 slave clock 被平衡、管理不应被 skew 的复杂控制逻辑、保持输出 pin 驱动逻辑的相似 skew、处理宏单元时钟馈通、禁用某些时钟的综合、防止过度缓冲。这些场景可以归成三组控制:范围控制、分组控制、目标控制。范围控制用 sink_type 和抽取设置决定树追到哪儿;分组控制用 skew group 和 exclusive skew group 决定谁和谁一起平衡;目标控制用局部 target 覆盖决定平衡力度。
6.1 先阻断再平衡:范围、分组、目标三组开关
我一般先做范围阻断,再做分组,最后调目标。范围阻断针对宏单元馈通、数据路径边界、输出 pin 驱动逻辑,先让这些点不该进树就不进树;分组针对不相交时钟树和共同 master 派生的 slave clock,先让它们分到不同 skew group,避免被强行拉平;目标针对个别树做局部覆盖,而不是全局加严。这个顺序不能反:先调目标再分组,工具已经按错误范围做了平衡,后面改分组只能重跑。
| 控制组 | 典型场景 | 验证方式 |
|---|---|---|
| 范围控制 | 宏单元馈通、数据路径边界 | sink 数量、debugger 端点 |
| 分组控制 | 不相交时钟树、slave clock | skew group 划分、平衡结果 |
| 目标控制 | 局部过渡/skew 需求 | 过滤原因、buffer 预算 |
这张表适合在改动前先写清楚“我要控制什么”,改完再用对应报表验证。不要一次改三组,否则出了问题分不清是范围、分组还是目标导致的。
6.2 用改前改后对照收住:三张表足够
验证不需要一堆报表。第一张看 sink 数量,确认范围控制没有漏负载;第二张看 skew group 划分,确认不相交时钟没有被分到一组;第三张看 buffer 数和层级,确认目标控制没有引发过度平衡。三张表在改前改后各跑一次,差异就是这次架构控制的收益或代价。应用笔记里提到用 CCOpt 属性获得设计洞察,我的理解是属性不是拿来“设完就跑”的,而是拿来建立可对照的观察点。
从那以后我每次跑复杂时钟网络,都强制先停在抽取后看一眼 sink 和 target,再决定要不要开 full;如果中途在 trial 看到漂亮 skew,也先翻 buffer 数再高兴。这份应用笔记最适合放在手边,跑 CCOpt 前翻到对应阶段对照一遍,比 full 跑完再回头找原因省时间。希望帮到你。
本文还有配套的精品资源,点击获取