OpenSTA generated clock 源引脚找不到:create_generated_clock 报 pin not found 的排查
更新时间:2026-11-12。长尾速查篇,属于 EDA 报错排查系列,汇总入口见 开源 EDA 报错排查导航。
静态时序分析(STA,Static Timing Analysis)里,派生时钟(generated clock)用 create_generated_clock 描述分频、倍频、门控后「从主时钟长出来」的新时钟域,命令的 -source 参数指定从哪个引脚或端口取主时钟波形做参考。这个源点名字写错时,OpenSTA 会直接以 Error 中止该命令,派生时钟根本建不出来。本篇用一份两级缓冲器的最小工程,把 OpenSTA generated clock 这类「源引脚查无对象」故障从报错到修复跑透;派生时钟的完整建模规则(分频、倍频、相移、门控四类形态)见 派生时钟约束:create_generated_clock 建模规则,本篇只讲源点找不到这一种故障。
首屏答案:坏例把 -source 写成 [get_pins u_buf2/CLKX],而网表里 u_buf2 是 BUF_X1,只有 A、Y 两个引脚,get_pins 匹配为空集合、Tcl 替换成空串,OpenSTA 2.0.17 先 Warning pin 'u_buf2/CLKX' not found,再 Error pin not found 中止命令,all_clocks 里只剩主时钟。修复方式是把 -source 改指主时钟的真实源点 [get_ports clk]——源点必须落在已有时钟的传播路径上,而不是派生时钟自己的输出点;复跑后 report_clock_properties 给出 clk 10.00ns 与 gclk 20.00ns (generated) 两行,建钟闭环。
这张流程卡对应本文的排查主线:先把报错两行当成一条链读,再回到网表核对引脚名,接着用源点规则判断正确的引用对象,最后以时钟属性表而不是退出码作为验收依据。跳过网表核对、凭信号名猜引脚,是这类问题最常见的弯路。
本文要回答的问题
- OpenSTA generated clock 建钟失败时,Warning 与 Error 两行报错的完整原文是什么,为什么 Error 行里的引脚名是空的?
create_generated_clock的-source到底该指向哪里,为什么不能指向派生时钟自己的输出引脚?get_pins找不到对象时 Tcl 层面发生了什么,排查时用哪些命令列出可引用的引脚和已建时钟?- 修复后
all_clocks遍历时 gclk 的 period 显示 0.0,为什么report_clock_properties却显示 20.00ns,应以哪个为准?
一、完整报错原文:OpenSTA generated clock 建钟命令被 Error 中止
最小工程的顶层 top 是两级 BUF_X1 组合链:d 经 u_buf1、u_buf2 到 q,另外保留一个 clk 端口专门承载时钟约束。坏脚本 bad.tcl 先在 clk 端口建周期 10ns 的主时钟,再试图在 u_buf2/Y 上建二分频派生时钟,但把 -source 写成了网表里不存在的 u_buf2/CLKX。在容器内执行 sta -exit -no_init -no_splash bad.tcl,完整输出原样摘录如下:
===== [1] 复现原始报错:e136-bad.tcl(-source 引用不存在的引脚 u_buf2/CLKX) =====
Warning: e136-bad.tcl, 5 pin 'u_buf2/CLKX' not found.
Error: e136-bad.tcl, 5 pin not found.
generated clocks=_40834a3484550000_p_Clock报错要分两行读。Warning 行点名缺失对象:e136-bad.tcl 第 5 行的引脚 u_buf2/CLKX 在链接后的网表里查无此脚。Error 行紧随其后,但引脚名位置是两个空格——pin not found,这不是排版问题,而是 [get_pins u_buf2/CLKX] 匹配为空集合、Tcl 把它替换成空串后,命令收到一个空的源点参数,只能报「空引脚找不到」并中止。最后一行 puts 证明后果:all_clocks 只返回主时钟对象(打印为内部句柄),名为 gclk 的派生时钟没有建立。命令中止与仅警告跳过的故障形态不同,SDC 语法本身写错时的表现可对照 OpenSTA SDC 语法错误排查。
二、工具与版本
本次实验在 macOS 上用 Docker 镜像 geek-eda:0.3-sta 运行,容器内 OpenSTA 版本为 2.0.17,统一带 -exit -no_init -no_splash 走批处理模式。版本先固定,因为报错措辞和对象访问命令的行为随版本演进,本文原文只对 2.0.17 这个构建负责。
另一个方言边界:OpenSTA 2.0.17 没有 all_corners、current_corner 这类 PrimeTime 命令,跨工具照抄手册会撞「未知命令」,动手前先确认命令在当前版本存在。本篇的对象属性读法是 OpenSTA 自己的 Tcl 接口:get_name 取名、is_generated 判断是否派生、period 取周期。
三、根本原因:-source 必须落在已有时钟的传播路径上
create_generated_clock 的语义是「参照一个已有时钟的波形,经过分频、倍频或相移变换,在另一个节点上定义新时钟」。因此 -source 引用的引脚或端口必须位于某个已建时钟的传播路径上——通常是主时钟源点本身,或主时钟往下游经过的时钟引脚。工具在源点取主时钟波形,按 -divide_by、-multiply_by、-edge_shift 变换后挂到命令末尾的目标引脚上。目标引脚才是新时钟域的起点,源点与目标点不能混为一谈。
图中蓝色是主时钟入口,灰色是传播与检查环节,紫色是源点引用,橙色是波形变换,绿色是派生时钟落地。读这张图抓住一条主线:源点回答「参照谁的波形」,目标点回答「新时钟挂在哪」。坏例的 u_buf2/CLKX 连对象都不存在,参照关系无从建立;更隐蔽的变体是引脚存在却不在任何已建时钟的传播路径上(如把组合数据通路输出当时钟源点),同样建钟失败。
坏源点与好源点的分叉对比如下图,红色是本例实际走到的失败支路,绿色是修复支路:
两条支路的唯一差异在 -source 的参数:失败支路引用了不存在的层次引脚,成功支路引用主时钟源点端口。这也解释了为什么排查的第一动作是「让对象访问命令自己说话」,而不是对着网表信号名人工猜测。
四、排查清单:先确认对象存在,再确认时钟路径
- 按行号读两条报错:Warning 行引号内是缺失对象全名;Error 行引脚名为空,佐证
get_pins返回空集合,而非权限或库文件问题。 - 用
get_pins -hierarchical列真实引脚:执行get_pins -hierarchical u_buf2/*列出该实例全部引脚,BUF_X1 只返回u_buf2/A与u_buf2/Y,CLKX是否存在一查便知;层次化设计记得带全路径,分隔符用/。 - 核对单元类型而非信号名:引脚名由单元库决定,不由 Verilog 网名决定,BUF_X1 的库定义里没有 CLKX;综合后引脚改名、层级打平的场景,同样以该命令输出为准。
- 用
report_clocks盘点已建时钟:确认主时钟 clk 已建立,再判断候选源点是否在它的传播路径上;一个时钟都没建时先解决主时钟问题,可对照 OpenSTA 无时钟报告排查。 - 区分源点与目标点:
-source给参照波形,命令末尾的引脚给派生时钟落点;真实设计里落点通常是分频寄存器 Q 端或门控单元输出,源点回指主时钟经过的时钟引脚。 - 改完用属性表验收:复跑后执行
report_clock_properties [all_clocks],派生行带(generated)标记且周期符合分频关系才算闭环,不要只看退出码。
五、修复代码与复跑确认
修复只动 -source 一个参数:从不存在的层次引脚改为主时钟源点端口,目标引脚 u_buf2/Y 与分频系数保持不变,保证两次实验的唯一变量就是源点引用。
create_clock -name clk -period 10 [get_ports clk]
-create_generated_clock -name gclk -source [get_pins u_buf2/CLKX] -divide_by 2 [get_pins u_buf2/Y]
+create_generated_clock -name gclk -source [get_ports clk] -divide_by 2 [get_pins u_buf2/Y]修复后的 good.tcl 用 foreach 遍历 all_clocks,通过对象方法逐个打印时钟名、是否派生、周期三个属性,最后再出一张时钟属性表:
read_liberty tiny.lib
read_verilog top.v
link_design top
create_clock -name clk -period 10 [get_ports clk]
create_generated_clock -name gclk -source [get_ports clk] -divide_by 2 [get_pins u_buf2/Y]
foreach c [all_clocks] {
puts "clock=[get_name $c] generated=[$c is_generated] period=[$c period]"
}
report_clock_properties [all_clocks]同一条容器命令复跑,Warning 与 Error 都不再出现,终端记录如下:
输出里有一个需要说明的细节:遍历对象方法时 clk 显示 generated=0 period=9.99999993922529e-9(10ns 的浮点表示),gclk 却显示 generated=1 period=0.0。派生时钟的 period 方法在 OpenSTA 2.0.17 里返回 0,不代表没有周期——权威答案在紧随其后的 report_clock_properties 表格:clk 周期 10.00ns、波形 0.00/5.00,gclk 周期 20.00ns、波形 0.00/10.00 并带 (generated) 标记,恰为主时钟的二分频。验收以属性表为准,对象方法只用来确认 is_generated=1。约束落地后若仍有路径报无时钟起点,排查方向转到 OpenSTA 时序路径无时钟起点排查;SDC 约束的完整编写顺序见 OpenSTA SDC 约束编写流程。
实验环境
- 机器/系统:macOS 本机,Docker 镜像
geek-eda:0.3-sta(容器内 Linux 环境) - 工具版本:OpenSTA 2.0.17,批处理命令
sta -exit -no_init -no_splash <tcl> - 日期:2026-11-12
- 完整命令:在实验目录执行
bash run.sh,脚本依次跑sta bad.tcl复现-source引用不存在引脚的 Warning 与 Error、sta good.tcl验证改指get_ports clk后派生时钟建成并输出时钟属性表。
代码获取
完整源码与复现脚本位于公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-opensta-generated-clock-source-missing,含 tiny.lib、top.v、base.sdc、好坏两份 Tcl(bad.tcl 与 good.tcl)与 run.sh。本地装好对应 Docker 镜像后,在该目录执行 bash run.sh 即可原样复现「报错中止、改源点修复、属性表复核」两步运行。
这一篇在知识体系里的位置
本篇属于 开源 EDA 报错排查导航 的静态时序分析分支,回答「派生时钟的源引脚名字写进约束后为什么建不出钟」。同系列的 OpenSTA read_spef 寄生文件读取失败排查 覆盖寄生标注阶段的名映射故障,与本篇同属「名字写进约束却在网表查无对象」家族;延迟反标阶段的同类问题见 OpenSTA read_sdf 标注失败排查。想系统理解 -source 选型与漏约束的假乐观风险,回到 派生时钟约束:create_generated_clock 建模规则;全系列入口见 EDA 报错排查系列。
总结
OpenSTA generated clock 建钟时报 pin not found,本质是 create_generated_clock 的 -source 在链接后的网表里查无对象:坏例引用 BUF_X1 上不存在的 u_buf2/CLKX,get_pins 返回空集合并被 Tcl 替换为空串,OpenSTA 2.0.17 先 Warning 点名缺失引脚、再 Error 中止命令,派生时钟 gclk 缺失,相关路径失去时钟约束。根因规则一条:源点必须落在已有时钟的传播路径上,取主时钟波形做变换参照,不是派生时钟自己的输出点。排查按「读报错两行、get_pins -hierarchical 列真实引脚、核对单元库引脚表、report_clocks 盘点已建时钟、区分源点与目标点」推进;修复把 -source 改指主时钟源点 [get_ports clk],复跑零报错,report_clock_properties 给出 gclk 20.00ns (generated) 即闭环。对象方法 period 对派生时钟返回 0.0 是该版本正常表现,周期以属性表为准;OpenSTA 2.0.17 没有 all_corners 等 PrimeTime 命令,Tcl 方言不要跨工具照抄。