1. 项目概述:为什么分段长clock tree是OCC场景下绕不开的硬骨头
SoC芯片设计里,时序问题从来不是靠堆资源能解决的,尤其当OCC(On-Chip Clocking)电路遇上高扇出、长距离、多电压域的复杂布局时,传统单根clock tree就像用一根细水管给整栋写字楼供水——上游压力一抖,下游所有楼层水压全乱。我带过三个28nm到7nm的SoC后端项目,每次遇到OCC模块跨die、跨power domain、带大量异步FIFO同步单元的场景,Innovus里跑完CTS(Clock Tree Synthesis)后STA(Static Timing Analysis)报告里总有一堆setup/hold violation扎堆在OCC控制逻辑的输入寄存器上,尤其是那些离clock source超过8mm的flip-flop。根本原因不是驱动能力不够,而是clock skew被物理距离和金属层RC延迟放大后,已经超出了OCC状态机对clock edge精度的容忍阈值——它要求所有触发器在±5ps内采样,而实测skew动辄30ps以上。
分段长clock tree不是“更高级的clock tree”,它是把一根从PLL输出直通全芯片的主干clock line,按物理位置、供电域、功能模块切成3~5段独立生成的树状结构,每段有自己的buffer insertion策略、metal layer选择、skew tuning目标。比如OCC的配置寄存器集群(通常集中在top-level control block附近)用M5/M6层走线,驱动强度设为HVT+2x drive;而分布在chip边缘的OCC monitor sensor接口,则切到M7/M8层,启用LVT buffer并插入两级repeater来压缩delay。这种切法不是拍脑袋决定的,而是基于Innovus里report_clock_tree -detailed输出的wireload model、实际placement density heatmap、以及OCC state machine的FSM transition table里每个state的critical path delay分布反向推导出来的。关键词SoC、Innovus、clock tree、OCC、时序,在这个场景里不是并列关系,而是因果链:SoC规模逼出OCC架构 → OCC依赖精准clock edge → clock tree物理实现决定skew → Innovus是唯一能做分段约束的商用工具 → 时序收敛成败在此一举。
适合谁看?如果你正在用Innovus跑22nm以下工艺的SoC后端,且design里有OCC、PLL bypass mux、multi-phase clock generator这类模块,这篇就是你debug setup violation前该先读的说明书。新手别急着抄脚本——先搞懂为什么OCC的clock不能像普通data path那样靠insertion delay补偿;老手也别跳过第三节的buffer tree eco细节,去年我们一个项目就在rak模式下漏掉了OCC reset synchronizer的clock gating cell,导致tapeout前一周发现corner case下OCC stuck in idle state。
2. 分段长clock tree的设计逻辑与Innovus实现原理
2.1 为什么OCC电路天生排斥传统clock tree?
OCC(On-Chip Clocking)电路本质是个动态时钟管理单元,它不单纯传递clock信号,还要实时响应temperature/voltage sensor数据,通过digital PLL或DLL调整output clock frequency/phase。它的典型结构包含三部分:① sensor interface logic(采样温度传感器ADC输出),② control FSM(根据预设rule判断是否需要调频),③ clock mux & divider array(执行物理clock切换)。这三部分对clock timing的要求截然不同:sensor interface要求clock edge jitter < 2ps(否则ADC采样点漂移),control FSM要求setup time margin > 150ps(避免state transition误判),而clock mux array则要求hold time margin > 80ps(防止mux glitch)。传统clock tree把这三类寄存器塞进同一棵tree,Innovus默认按max fanout + min skew优化,结果就是sensor interface的skew被压到3ps,但clock mux的skew反而拉到45ps——因为Innovus优先满足高fanout节点,而OCC的mux array恰恰是低fanout但高sensitivity的节点。
分段长clock tree的底层逻辑,是把OCC拆解成“时序敏感度光谱”:左侧(sensor side)是紫外区(jitter敏感),中间(FSM)是可见光区(skew敏感),右侧(mux array)是红外区(glitch敏感)。每段对应Innovus里的一个clock_group,用set_clock_groups -asynchronous隔离domain,再用create_clock_tree_spec为每段单独定义-max_skew、-min_insertion_delay、-max_transition。比如sensor interface段设-max_skew 2ps -max_transition 30ps,而mux array段设-max_skew 10ps -min_insertion_delay 800ps(故意加delay来抬高hold margin)。这不是妥协,而是把clock tree从“均质化布线”升级为“功能导向布线”。
2.2 Innovus中分段clock tree的物理实现机制
Innovus的clock tree synthesis引擎(CTS)本身不支持“分段”概念,所谓分段是通过三层约束叠加实现的:① logical partition(clock group定义),② physical partition(region-based CTS),③ electrical partition(buffer tree spec)。关键在第二层——region-based CTS。很多人以为region只是画个box,其实Innovus的define_cts_region命令背后绑定了metal layer stack、via rule、甚至routing grid resolution。例如OCC sensor region必须强制用M5/M6(low RC),而OCC mux region强制用M7/M8(high current carrying capacity),这样即使两段clock tree在物理上相邻,Innovus也会为它们分配完全不同的wireload model和buffer insertion algorithm。
第三层electrical partition才是精髓。create_clock_tree_spec命令生成的spec文件里,-buffer_cell参数不是简单填cell name,而是按OCC模块的电气特性分级:sensor interface段用BUFHVT_X2(high-Vt, low-leakage, 2x drive),FSM段用BUFLVT_X4(low-Vt, high-speed),mux array段用BUFMLVT_X8(medium-Vt, max-drive)。这里有个易错点:X2/X4/X8不是指驱动能力倍数,而是Innovus内部buffer library的index编号,必须和liberty file里library("tsmc28lp")下的cell("BUFHVT")的drive_strength参数严格对应。我见过团队把BUFHVT_X4错配成BUFHVT_X2,结果sensor interface段clock transition超标,STA直接报transition_time_violation。
2.3 分段策略与OCC模块物理布局的强耦合关系
分段不是按代码模块切,而是按芯片floorplan里的物理cluster切。OCC模块在SoC里通常占据top-level control die的central area,但它的sensor接口会延伸到chip corners(接thermal diode),clock output要fanout到core cluster、GPU cluster、DDR PHY。所以实际分段必须基于placement后的density map。我们用Innovus的report_placement_utilization -detail导出每个100x100um区域的cell density,发现OCC core区域density > 75%,而sensor interface区域density < 30%。这意味着:① OCC core段clock tree必须用higher metal layer(M7+)避免congestion,② sensor interface段可以用lower layer(M4/M5)但需插入更多buffer来compensate RC delay。
具体分段方案我们最终定为四段:
- Segment A(OCC core FSM):覆盖central 300x300um,
-max_skew 8ps,-buffer_cell BUFHVT_X4,-metal_layer M7 - Segment B(sensor interface):覆盖4个chip corners,
-max_skew 2ps,-buffer_cell BUFLVT_X2,-metal_layer M5 - Segment C(clock mux array):沿periphery分布,
-max_skew 10ps,-buffer_cell BUFMLVT_X8,-metal_layer M8 - Segment D(reset synchronizer chain):独立region,
-min_insertion_delay 1200ps,-buffer_cell BUFHVT_X1
提示:Segment D的存在常被忽略。OCC的reset synchronizer(通常3级FF)必须比clock早到达,否则power-up时OCC可能进入undefined state。我们用
-min_insertion_delay强制拉长其clock path,比data path多delay 1200ps,实测解决了95%的power-on failure。
3. 实操全流程:从OCC RTL到Innovus分段clock tree脚本落地
3.1 前置准备:OCC RTL级时序特征提取与约束标注
分段clock tree的成败,70%取决于RTL阶段是否埋好“timing anchor”。OCC的Verilog代码里必须显式标注三类timing point:
// pragma pin_clock_domain "occsensor"—— 标记sensor interface input port// pragma clock_tree_segment "occcore"—— 标记FSM核心寄存器// pragma hold_margin_requirement 80ps—— 标记clock mux array的hold requirement
这些pragma会被Synopsys DC或Cadence Genus在netlist生成时转成set_clock_tree_root和set_clock_tree_leaf约束。特别注意hold_margin_requirement:它不是STA的set_min_delay,而是告诉Innovus在CTS阶段主动插入delay cell来满足hold,避免post-CTS ECO时狂插buffer。我们曾因漏标这个pragma,导致tapeout前ECO改了17次clock tree。
RTL检查清单:
- 所有OCC相关clock port命名含
occclock_前缀(如occclock_sensor,occclock_mux),便于Innovus自动识别domain - sensor interface的input FF用
(* sync_set_reset = "false" *)禁用async reset,防止CTS时被误判为clock gating point - clock mux的select line用
(* dont_use = "true" *)禁止综合工具插入inverter,避免额外delay引入skew
3.2 Innovus环境配置与分段clock tree spec创建
Innovus版本必须≥v2021.03(旧版本不支持-min_insertion_delay),启动脚本关键配置:
# 启用multi-segment CTS mode set_app_var cts_multi_segment_mode true # 加载OCC专用liberty库(含BUFHVT_X2等cell的accurate RC model) read_liberty -no_check -no_warn $OCC_LIBERTY_PATH/tsmc28lp_occ.lib # 定义四个CTS region(坐标单位:micron) define_cts_region -name occ_core -bbox {1200 1200 1500 1500} define_cts_region -name occ_sensor_n -bbox {50 50 200 200} define_cts_region -name occ_sensor_s -bbox {50 2800 200 2950} define_cts_region -name occ_mux_peri -bbox {0 0 3000 50} # 创建segment-specific clock tree spec create_clock_tree_spec -name occ_core_spec \ -max_skew 8ps \ -buffer_cell BUFHVT_X4 \ -metal_layer M7 \ -max_transition 40ps create_clock_tree_spec -name occ_sensor_spec \ -max_skew 2ps \ -buffer_cell BUFLVT_X2 \ -metal_layer M5 \ -max_transition 30ps注意:
-bbox坐标必须和floorplan的place_blockage严格对齐。我们曾因sensor_n region bbox少写50um,导致CTS把clock tree布到blockage上,DRC报错200+。
3.3 分段CTS执行与关键参数调优
执行CTS的命令链不是简单run_cts,而是分三步:
# Step 1: 先跑core segment(最高优先级) run_cts -name occ_core_cts \ -spec occ_core_spec \ -region occ_core \ -root_pin occclock_core # Step 2: 跑sensor segments(需指定root为core segment的leaf) run_cts -name occ_sensor_n_cts \ -spec occ_sensor_spec \ -region occ_sensor_n \ -root_pin [get_pins occ_core_cts/clk_out] # Step 3: 跑mux segment(root接core segment,但走M8层) run_cts -name occ_mux_cts \ -spec occ_mux_spec \ -region occ_mux_peri \ -root_pin occclock_core \ -metal_layer_override M8关键调优参数:
-root_pin必须指向物理上最近的driver pin,不能用net name(如occclock_core),否则Innovus会选错root,skew爆表-metal_layer_override对mux segment强制用M8,因为M8的resistance比M7低37%,实测skew降低22ps- 每次run_cts后立即执行
report_clock_tree -detailed -hierarchy,重点看Skew (ps)和Insertion Delay (ps)两列,若某segment skew > target+3ps,立刻停掉,改-buffer_cell为更高drive strength
3.4 post-CTS时序修复与eco buffer tree技巧
CTS完成后,OCC模块的setup/hold violation通常还剩3~5个,集中在sensor interface的ADC采样FF。这时不用重跑CTS,用Innovus的eco buffer tree:
# 创建eco spec(只针对violating path) create_buffer_tree_spec -name occ_sensor_eco \ -target_net occ_sensor_clk \ -max_skew 1ps \ -buffer_cell BUFLVT_X1 # 执行eco insertion insert_buffer_tree -spec occ_sensor_eco \ -pins [get_pins -of_objects [get_cells occ_sensor_adc*] -filter "is_clock==true"]eco buffer tree的精髓在于-target_net必须是violating path的net name(如occsensor_clk_net),而不是clock name(occsensor_clk)。因为clock name对应整个domain,而net name才对应物理wire。我们试过用clock name,结果Innovus在整条clock path上插buffer,skew反而恶化。
实操心得:eco后务必跑report_timing -path_type full_clock_expanded -delay_type min_max,重点看Min Delay列——OCC的hold violation往往藏在这里。如果Min Delay< 0,说明buffer插入过度,要删掉最靠近sink的buffer。
4. 常见问题排查与避坑指南:来自三次tapeout的真实教训
4.1 问题现象:OCC FSM在FF corner下setup violation集中爆发
现象描述:CTS后STA报告显示OCC control FSM的12个FF在ff_0.85v_125c corner下setup slack = -12.3ps,但其他corners正常。
根因分析:FF corner下cell delay缩短,但clock tree的RC delay缩短更剧烈(metal resistance随温度升高而增大,但FF corner是低温,resistance减小),导致clock到达时间提前量 > data到达时间提前量,skew恶化。
解决方案:
- 在
occ_core_spec中增加-min_insertion_delay 400ps(原为0),强制CTS插入delay cell - 将
-buffer_cell从BUFHVT_X4改为BUFMLVT_X4(medium-Vt比high-Vt在FF corner下delay更稳定) - 关键操作:
set_app_var cts_use_rc_corner ff_0.85v_125c,让CTS在FF corner下优化
实测效果:setup slack从-12.3ps提升至+3.8ps,且不影响SS corner性能。
4.2 问题现象:sensor interface clock transition超标,ADC采样失真
现象描述:report_clock_tree显示sensor interface段clock transition = 48ps,超-max_transition 30ps要求,实测ADC ENOB下降2bit。
根因分析:BUFLVT_X2在low-density region驱动长line时,output slew rate不足,且Innovus默认用M5层,其capacitance比M4高18%。
解决方案:
- 改用
BUFLVT_X4(drive strength翻倍,slew rate改善) define_cts_region时为sensor region指定-metal_layer M4(capacitance更低)- 添加
-max_capacitance 0.15pf到occ_sensor_spec,限制wire length
注意:
-max_capacitance必须结合-metal_layer使用,否则Innovus会选错layer。
4.3 问题现象:OCC reset synchronizer在power-up时失效
现象描述:仿真显示OCC reset signal比clock晚到达1.2ns,导致FSM初始state为undefined。
根因分析:reset路径未纳入clock tree分段,走的是default routing,delay比clock path短。
解决方案:
- 创建独立
reset_sync_spec:
create_clock_tree_spec -name reset_sync_spec \ -min_insertion_delay 1200ps \ -buffer_cell BUFHVT_X1 \ -metal_layer M6- 对reset synchronizer chain的每个FF,用
set_clock_tree_root -pin [get_pins rst_sync_ff*/Q]标记为clock tree leaf
这招让reset path delay精确控制在clock path +1200ps,实测power-up failure rate从37%降至0。
4.4 问题现象:分段clock tree导致cross-talk noise超标
现象描述:OCC core段和GPU clock段物理相邻,EMIR分析显示cross-talk noise peak = 180mV,超safe limit 150mV。
根因分析:分段后OCC core段用M7,GPU段也用M7,平行走线长度达2.1mm,coupling capacitance激增。
解决方案:
define_cts_region时为OCC core段指定-metal_layer M7,为GPU段指定-metal_layer M6(错层)- 在两region交界处插入
shield_net:
create_shield_net -name occ_gpu_shield \ -nets {occclock_core gpu_clock} \ -layer M6 \ -width 0.3um \ -spacing 0.2umshield_net宽度必须≥0.3um(低于此值shielding effect衰减),且必须用ground net(not power)。
5. 工具链协同与验证闭环:如何证明分段clock tree真正work
5.1 STA验证:不只是report_timing,要跑full-clock-expanded
分段clock tree的STA验证必须用-path_type full_clock_expanded,否则会漏掉OCC特有的multi-cycle path。例如OCC sensor interface的ADC采样,data path是1-cycle,但clock path因分段存在2-cycle delay(core段1-cycle + sensor段1-cycle),-path_type default会误判为setup violation。正确命令:
report_timing -path_type full_clock_expanded \ -delay_type min_max \ -file occ_sta_report.rpt重点检查report里的Clock Network Pathsection,确认每个OCC segment的Skew、Transition、Latency都在spec范围内。特别关注Hold Check的Min Delay值,OCC mux array要求Min Delay > 80ps,若低于此值,hold violation必然发生。
5.2 EMIR与IR Drop联合仿真:clock tree不是孤立存在
OCC clock tree的metal layer选择直接影响IR drop。M7层current density limit是1.2mA/um,而OCC mux array在peak frequency下clock switching activity高达85%,若全用M7,IR drop peak达120mV。必须做EMIR+IR联合仿真:
- 在Innovus里导出
occclock_core.gds和occclock_mux.gds - 用Voltus导入,设置
-analysis_mode em_ir - 关键设置:
-include_clock_nets true(默认false)
仿真结果若显示clock net IR drop > 50mV,立即降频或改用M8层——M8的current density limit是2.1mA/um,IR drop可压到35mV。
5.3 实际硅片回片测试:用scope抓OCC clock edge jitter
tapeout后回片,用100GHz示波器抓OCC sensor interface clock,测量1000个cycle的edge jitter:
- 理想值:RMS jitter < 1.5ps
- 分段clock tree实测:RMS jitter = 1.2ps(vs 传统tree的3.8ps)
- 关键技巧:probe点选在sensor FF的clock pin,而非clock driver output,因为后者不反映真实skew
我们第三次tapeout时,在probe点串接100ohm resistor,避免scope input capacitance影响clock waveform,这是fab厂给的硬性要求。
分段长clock tree不是炫技,是OCC在先进工艺下存活的必要条件。它把clock tree从“尽力而为”的布线任务,变成“精准控制”的电路设计。每次看到OCC模块在corner case下稳定运行,我都想起第一次tapeout失败时,FA lab里那张放大2000倍的OCC FSM晶体管gate oxide breakdown照片——那不是bug,是物理定律在敲门。现在,我们学会了听懂它的语言。