资讯详情

Innovus dbGet命令实战:从PG term查询到批量脚本

📅 2026/9/17 12:27:10 | 华诺云谱 👁 阅读
Innovus dbGet命令实战:从PG term查询到批量脚本
前天有位做数字后端的朋友在群里问Innovus里怎么选中名字为biasnw的标准单元上的PG term问题看着简单底下讨论却越来越热闹有人用GUI一个个点有人用get_pins有人在数据库属性里翻半天没找到。其实这种“查对象、取属性”的操作正是Innovus里dbGet命令最擅长的场景。dbGet是Innovus/EDI里访问设计数据库的只读查询命令几乎所有需要从设计里掏出点信息来的工作——查instance坐标、查net上的sink、查PG pin接的是哪条power net、批量导出cell list——都能靠它一条命令完成。这篇文章把我在项目里用得最多的dbGet命令按场景整理一遍从语法到实战到避坑适合刚接触Innovus数字后端的工程师也适合已经写了不少脚本但想系统过一遍dbGet的老手。1. 为什么后端起流程离不开dbGet从一次PG term查询聊起1.1 “选中biasnw的PG term”到底在查什么先说术语。在Innovus的数据库里标准单元上的电源/地引脚在instance这一层一般叫pgPin在net那一层也会看到pgPins。老一点的文档和Encounter时代的脚本里它可能叫pgTerm。所以群里问的“PG term”放到dbGet语境里本质上就是查instance.pgPins这条路径。最直接的做法分成两步先确认instance存在再取它的PG pin。dbGet top.insts.name biasnw -p如果能返回biasnw说明instance在当前design scope里。接着dbGet [dbGet top.insts.name biasnw -p].pgPins.name -p这条命令会返回类似VDD VSS这样的PG pin名。如果还想进一步看每个PG pin接到哪条net上dbGet [dbGet top.insts.name biasnw -p].pgPins.net.name -p这里有一个需要特别注意的地方搜索词里“标准单元名字为biasnw”存在两种理解。一种是instance name叫biasnw另一种是cell ref name叫biasnw。如果是后一种你是想找“所有引用biasnw这个cell的instance”那就不能直接dbGet top.insts.name biasnw -p因为那是按instance名字匹配。稳妥的做法是遍历instance用cell name做过滤set target {} foreach inst [dbGet top.insts.name -p] { set cellName [dbGet [dbGet top.insts.name $inst -p].cell.name -p] if {$cellName biasnw} { lappend target $inst } } foreach inst $target { puts $inst dbGet [dbGet top.insts.name $inst -p].pgPins.name -p }这个遍历写法比一条命令慢但它不依赖版本差异出错概率低。实际项目里多数时候我们找的是instance name所以第一条路径已经够用。1.2 只读查询与集合命令的分工很多刚接触Innovus的人会把dbGet和get_cells当成同类命令其实它们的分工完全不同。get_cells、get_nets、get_pins返回的是collection对象设计上是为了继续喂给别的命令做操作比如set_dont_touch、set_property、create_route。而dbGet是只读查询直接按对象路径把属性值取出来适合查询、统计、导出报告。# 要改设计时用集合命令 set bufCells [get_cells -filter ref_name ~ BUF*] set_dont_touch $bufCells true # 只是想知道名字里带 buf_ 的instance有哪些用dbGet dbGet top.insts.name buf_* -p我自己的习惯是改设计多用get_*查信息多用dbGet。两者互补但不要随手混着用。尤其是不要指望用dbGet去改属性这个话题放到最后一章专门说。2. 先把语法拆清楚dbGet的对象路径、属性路径与-p2.1 一条最简命令的三段式看这条最常用的命令dbGet top.insts.name -p拆开来看就是三部分top是数据库根节点insts是instance对象集合name是要取的属性。从top出发把每个instance的name属性取出来加上-p之后返回纯字符串列表。如果不加-p返回的结果会带对象路径上下文打印出来可能是{top/inst1} {top/inst2}这种形式直接用字符串比较很容易被前缀坑到。所以我的经验是最终要打印、比较、写文件就加-p如果还要继续往下一层取属性就用中括号把加-p的查询包起来作为新的对象上下文继续“点路径”。再配合通配符就是最常见的过滤写法dbGet top.insts.name buf_* -p这会返回所有以buf_开头的instance名字。2.2 跨层访问靠“复数对象名”一路点下去dbGet最厉害的地方是路径可以从对象一路跨到子对象甚至孙对象。对象名基本都是复数比如insts、pins、nets、terms、pgPins。dbGet top.insts.cell.name -p dbGet top.insts.pins.name -p dbGet top.insts.pgPins.net.name -p dbGet top.nets.pins.inst.name -p最后一条从所有net出发取每条net上的pin再看pin属于哪个instance最后取instance名。这条路径读起来和思维顺序一模一样非常舒服。这也解释了为什么dbGet写起来比一堆Tcl循环要清爽——dbGet内部帮你把对象集合的遍历做掉了。如果只想针对某一个对象继续往下查就用中括号dbGet [dbGet top.insts.name U1 -p].box -p内层先定位名字为U1的instance外层再取它的box。这种嵌套是dbGet最常见的用法后面的实战命令基本都长这样。2.3 返回值不是永远适合直接比较-p的关键作用很多新手会在这里翻车。比如set instName [dbGet top.insts.name U1 -p] puts $instName加上-p后$instName就是纯字符串可以直接拿来用。如果不加-p拿到的可能就不是你期望的纯值。再比如你想取出U1的坐标dbGet top.insts.name U1 -p ;# 纯名字 dbGet [dbGet top.insts.name U1 -p].box -p ;# 纯坐标这里内层的dbGet top.insts.name U1 -p返回字符串U1外层dbGet把这个字符串当作之前定位到的对象引用继续取box。掌握这个“先取名字再以名字为索引继续点”的套路长命令就不会写乱。2.4 不知道有哪些属性时用dbGet列“家谱”dbGet不是只能查你记得住的属性它也能帮你把对象结构摸清楚。面对一个新版本、一个新库与其到处搜属性名不如直接让工具自己列出来dbGet top -p dbGet [dbGet top.insts.name U1 -p] -p dbGet [dbGet top.nets.name VDD -p] -p第一条会把顶层对象下的所有子对象和属性名列出来第二条把U1这个instance的所有属性列出来第三条把VDD这条net的所有属性列出来。我第一次接触Innovus 18版本时就是靠这几条命令摸清了pgPins、pgTerms这些属性在不同版本里的叫法。3. 最常用的几组查询instance、pin、net、term一次讲透3.1 instance与cell信息列出当前scope里所有instance是最基础的dbGet top.insts.name -p配合通配符做模糊匹配dbGet top.insts.name *buf* -p dbGet top.insts.name data_* -p查instance的坐标和方向dbGet [dbGet top.insts.name U1 -p].box -p dbGet [dbGet top.insts.name U1 -p].orient -pbox返回的是{x1 y1 x2 y2}四元组对应instance的bounding box单位由当前设计的库设置决定。orient返回的是摆放方向比如R0、MX这些。查instance引用的是哪个celldbGet [dbGet top.insts.name U1 -p].cell.name -p统计设计里有哪些cell typelsort -unique [dbGet top.insts.cell.name -p]找macro会更麻烦一些。有些版本可以直接dbGet top.insts.isMacro 1 -p但这个写法不是所有版本都稳定。最保险的写法是遍历set macros {} foreach inst [dbGet top.insts.name -p] { set isMacro [dbGet [dbGet top.insts.name $inst -p].isMacro -p] if {$isMacro 1} { lappend macros $inst } } puts $macros数据量不大时完全够用大数据量则优先考虑get_cells -filter。3.2 普通pin和PG pinPG term的查询普通信号pin在instance下面叫pinsdbGet [dbGet top.insts.name U1 -p].pins.name -p dbGet [dbGet top.insts.name U1 -p].pins.direction -p dbGet [dbGet top.insts.name U1 -p].pins.net.name -p如果想查某个具体pin的坐标需要三层嵌套dbGet [dbGet [dbGet top.insts.name U1 -p].pins.name CLK -p].box -p内层先拿到U1的CLK pin名称再取box。这个例子值得多看几眼因为它演示了“对象路径可以一级一级点下去”的完整过程。PG pin则统一在pgPins下面dbGet [dbGet top.insts.name biasnw -p].pgPins.name -p dbGet [dbGet top.insts.name biasnw -p].pgPins.net.name -p dbGet [dbGet top.insts.name biasnw -p].pgPins.direction -p普通信号pin和PG pin在Innovus的数据库里是分开的两个对象集合。很多人搜“biasnw的PG term”会卡住就是因为一直在pins里找VDD/VSS而电源地引脚其实在pgPins里。3.3 net与连接关系查net上的pindbGet [dbGet top.nets.name clk -p].pins.name -p查net上所有pin对应的instancedbGet [dbGet top.nets.name clk -p].pins.inst.name -p查VDD这条net上连了哪些instance可以分别看普通pin和PG pindbGet [dbGet top.nets.name VDD -p].pins.inst.name -p dbGet [dbGet top.nets.name VDD -p].pgPins.inst.name -p如果net对象没有暴露pgPins属性就换成遍历instance的写法。部分版本里net对象还会暴露driverPins和loadPins这类更细的连接关系但属性名随版本差异较大拿不准时先跑一下dbGet [dbGet top.nets.name clk -p] -p确认。3.4 IO term与端口信息顶层IO port在dbGet里一般叫termsdbGet top.terms.name -p查某个port的方向和坐标dbGet [dbGet top.terms.name clk -p].direction -p dbGet [dbGet top.terms.name clk -p].box -p在顶层叫terms在子block里可能需要看hierTerms这类属性。拿不准就先dbGet top -p把顶层属性列出来通常情况下能看到当前scope支持哪些对象类型。3.5 速查表查询目标命令写法备注所有instance名字dbGet top.insts.name -p当前scope名字带buf的instancedbGet top.insts.name *buf* -p支持通配符查instance坐标dbGet [dbGet top.insts.name U1 -p].box -p返回x1 y1 x2 y2查instance的cell名dbGet [dbGet top.insts.name U1 -p].cell.name -pcell ref name查instance的普通pindbGet [dbGet top.insts.name U1 -p].pins.name -psignal pin查instance的PG pindbGet [dbGet top.insts.name biasnw -p].pgPins.name -pPG term查PG pin对应netdbGet [dbGet top.insts.name biasnw -p].pgPins.net.name -p继续net.name查net上的pindbGet [dbGet top.nets.name clk -p].pins.name -p先定位net查net上的instancedbGet [dbGet top.nets.name clk -p].pins.inst.name -p沿inst.name列IO portdbGet top.terms.name -p顶层端口4. 批量处理从一条命令到一个能用的Tcl脚本4.1 通配符筛选的正确姿势dbGet支持Tcl通配符*匹配任意串?匹配单个字符[]匹配字符集。dbGet top.insts.name data_* -p dbGet top.insts.name *reg* -p dbGet top.nets.name VDD* -p注意通配符是写在属性值这个位置的格式是dbGet 对象路径 属性 pattern -p不要写反。4.2 批量导出坐标的小脚本拆解这是一段我在项目里经常用的脚本模板把名字以FT_开头的instance坐标批量导出set instList [dbGet top.insts.name FT_* -p] set fp [open ft_instances.rpt w] foreach inst $instList { set box [dbGet [dbGet top.insts.name $inst -p].box -p] if {$box {}} { puts $fp $inst NO_BOX continue } set x1 [lindex $box 0] set y1 [lindex $box 1] set x2 [lindex $box 2] set y2 [lindex $box 3] set cx [expr {($x1 $x2) / 2.0}] set cy [expr {($y1 $y2) / 2.0}] puts $fp [format %-20s %10.3f %10.3f $inst $cx $cy] } close $fp这里有几个细节值得解释。第一dbGet top.insts.name FT_* -p一次性把所有匹配的instance名字拿回来存成Tcl list。第二循环里为什么还要再dbGet top.insts.name $inst -p定位一次因为dbGet取属性必须从对象上下文出发只知道名字还不够用中括号重新“指路”才能继续取box。第三box在Tcl里是一个list用lindex拆出四个坐标再求中心点。第四format固定列宽导出的文件后面直接扔给Linux命令处理也不会乱。这个模板改一改就能导出pin坐标、net长度、cell属性几乎是万能批处理框架。4.3 两层嵌套查询把连接关系一次拉出来如果想一次把clk net上所有pin的坐标拉出来可以这样dbGet [dbGet [dbGet top.nets.name clk -p].pins.name -p].box -p这条命令从net出发先拿到pins的name集合再以这些pin名为对象继续取box。实际跑出来是一串坐标list如果数据量很大建议配合循环逐条处理否则打印会刷屏。写这种长命令时我习惯先分步验证先确认net存在再确认pins能取到最后再拼外层。不要指望一次性写对dbGet的调试成本很低分步拆开反而快。5. dbGet输出怎么配合Linux文本处理5.1 先想清楚dbGet返回的是Tcl list不是行文本搜“linux常用命令”的人数很多可见不少做数字后端的朋友习惯把工具输出拿到Linux终端里二次处理。但dbGet的输出和grep/sed/awk的输入之间有一个坎dbGet返回的是Tcl list打印出来是空格分隔的一串元素不是一行一条记录。直接把复制出来的内容丢给grep经常发现全挤在一行里根本没法处理。所以和Linux命令配合之前你要先决定输出格式。格式不是dbGet参数控制的而是你在写报告时用foreach加puts一行行写出来的。5.2 稳定的做法用foreach逐行写报告再交给sort/awk举个例子。要把所有macro的名字、cell名、坐标逐行写到文件里set fp [open macro_box.rpt w] foreach inst [dbGet top.insts.name -p] { set isMacro [dbGet [dbGet top.insts.name $inst -p].isMacro -p] if {$isMacro 1} { set box [dbGet [dbGet top.insts.name $inst -p].box -p] set cell [dbGet [dbGet top.insts.name $inst -p].cell.name -p] puts $fp $inst $cell $box } } close $fp这样写出来的每一行都是固定的空格分隔格式。回到Linux终端就能放心用awk了比如把底边坐标在5000um以上的macro挑出来awk $4 5000 {print $1, $2} macro_box.rpt5.3 常见统计需求cell type计数、宏单元坐标清单统计cell type数量是最常见的需求。先在Innovus里导出cell名dbGet top.insts.cell.name -p cell_names.txt再到Linux终端sort cell_names.txt | uniq -c | sort -rn | head -20几秒钟就能看到设计里数量最多的前20种cell。如果数据量不大也可以直接在Tcl里统计set cells [dbGet top.insts.cell.name -p] foreach c [lsort -unique $cells] { puts [format %-10s %6d $c [llength [lsearch -all $cells $c]]] }两种方式都学一下按数据量选。几十行到几百行Tcl里直接处理更省事几十万行Linux管道明显更快。6. 容易踩的坑与排查要点6.1 bus名字里的方括号让dbGet和Tcl一起“打架”数字后端最烦的就是bus名比如data[3]。在dbGet里直接写dbGet top.nets.name data[3] -p大概率会报错因为Tcl把[3]当成命令替换去执行一个叫“3”的命令。解决办法是转义dbGet top.nets.name data\[3\] -p dbGet top.nets.name {data[3]} -p set target data\[3\] dbGet top.nets.name $target -p第三种写法推荐在脚本里用把名字先放进变量再传参可读性好很多。如果库里有bus对象比如data[3:0]dbGet里匹配时可能需要按data[3]或data[3:0]分别试一下先用前面说的列属性方式确认。6.2 层次化设计里查不到子模块对象dbGet的对象路径是从当前design scope出发的。默认在top层级时top.insts只包含当前层看到的instance不会自动递归到每个子block内部。所以你跑dbGet top.insts.name -p看不到子模块内部那些std cell是正常的。想看子模块内部先把scope切到那个block再跑同样的dbGet。Innovus里常用的切换命令是setDesignWorkIndex也可以在GUI的Hierarchy面板里双击进入。如果不确定当前scope先看dbGet top.insts.name -p返回的数量数量不对就先查scope。6.3 -p加不加、filter/通配符版本差异不加-p的结果带对象路径上下文拿去做lsearch -exact常常匹配不上。我见过很多次这种问题命令本身没报错结果就是空折腾半天才发现是没加-p。另外-filter的写法在不同Innovus版本里支持程度不一样。有的版本dbGet支持-filter有的版本不支持或者属性名不同。最稳妥的组合是“对象路径 属性 通配符 -p”。非要用filter先跑help dbGet确认当前版本的选项。还有一个经验写脚本前花一分钟跑一下help dbGet把当前版本的-p、通配符、filter支持情况扫一眼能省掉后面很多改脚本的时间。版本升级后同样建议这么做。6.4 空结果时不要反复试先按这个顺序排查如果dbGet返回空先别急着改命令按顺序检查当前scope是不是目标设计名字拼写、大小写对不对名字里有没有方括号、反斜杠需要转义属性名在当前版本和库里存不存在先用dbGet top -p或dbGet [对象] -p确认。对象是不是被优化改名、删除或合并了想快速验证某个名字是否存在可以这样lsearch -glob [dbGet top.insts.name -p] *biasnw*一层层拆开验证比在完整长命令上反复试要高效得多。我踩过最多的情况是内层dbGet已经返回空外层还在继续点属性报错信息看起来很吓人其实问题就出在第一步。6.5 dbGet是只读的不是用来改设计的dbGet的本质是只读查询它把属性取出来给你看但不会改变设计。如果查到一个instance想设dont_touch应该用get_cells拿到collection再调用set_dont_touch# 不推荐dbGet返回的是字符串不是collection set bad [dbGet top.insts.name U1 -p] set_dont_touch $bad true # 正确用集合命令 set ok [get_cells U1] set_dont_touch $ok true实际项目里有人把dbGet结果直接传给别的命令偶尔也能跑通但这不是稳定用法。读归读写归写边界要清楚。7. 我的几个使用习惯7.1 先help再动手我拿到一个新版本或者新流程环境第一件事就是敲help dbGet把当前版本的选项扫一遍重点看-p、通配符、filter有没有变化。版本差异这件事靠记忆不如靠help。7.2 剥洋葱式验证不管多复杂的查询都从最内层开始验证。先确认instance或net存在再点第一层属性确认输出符合预期后再继续加下一层。长命令拼不出来不要硬拼分步验证往往几分钟就搞定。7.3 把常用查询封装成procdbGet用久了可以把高频查询封装成自己的Tcl函数放进个人tclrc里。比如proc getInstBox {name} { set box [dbGet [dbGet top.insts.name $name -p].box -p] if {$box {}} { return {} } return $box } proc getPGNet {inst pin} { dbGet [dbGet [dbGet top.insts.name $inst -p].pgPins.name $pin -p].net.name -p }下次直接在Innovus里输getInstBox U1就能拿到坐标不用每次把一长串嵌套命令重敲一遍。这算是dbGet最吸引人的地方一次整理处处复用。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。