ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Innovus dbGet实战:高效查询PG term与版图对象

Innovus dbGet实战:高效查询PG term与版图对象 没有哪个做数字后端的工程师敢说自己没用过Innovus的GUI去点选对象。但真到了项目后期几千上万个instance堆在版图里你想选中一个叫biasnw的标准单元它的PG term或者想快速统计某条net下面到底挂了哪些pin鼠标在版图里戳半天都点不中。这时候你才意识到真正高效的姿势是在控制台敲一行dbGet。dbGet是Innovus里最核心的数据库查询命令底层直接对接设计数据库Design Database能查instance、net、pin、term、path、cell等等几乎所有对象的属性。它的强大之处在于不需要打开GUI不需要一层层翻属性面板一条命令就能把所有目标对象的信息抓出来还能直接配合Tcl脚本做批量处理和自动化流程。这篇东西不是官方文档的翻译而是我把这几年在后端项目里实际用dbGet总结出来的常用命令、过滤写法、避坑经验一次性整理出来。不管你是刚接触Innovus的学生还是已经跑过几个项目的一线工程师这份命令合集都能帮你在日常操作和脚本编写上节省大量时间。我会尽量把每个命令的使用场景讲清楚而不是单纯堆命令列表。1. 搞懂dbGet的查询逻辑比背命令更重要1.1 Innovus数据库里到底存了什么要理解dbGet先得理解Innovus背后的数据模型。可以把它想象成一棵很大的树树根就是设计本身top下面挂着各种类型的对象。最常用的几类对象是instsinstance也就是你摆放在版图上的标准单元、宏单元、IP等实例。netsnet就是连线负责连接各个instance的pin。pinspin通常指物理上的引脚是instance上用于布线的物理端口。termsterm逻辑上的端口一般指module的输入输出端口或者instance上的逻辑引脚。cellinstance对应的工艺库单元例如INV_X1、NOR2_X2这种。fpath这条路径上的时序或物理路径对象。boxbounding box对象在版图上的矩形区域。layer金属层、过孔层这些工艺层的属性。dbGet的语法核心就是“从哪个对象往下查哪个属性”。比如你想知道顶层有哪些instance就直接对top下手查询它的insts属性然后继续往下一层拨。这种层级式访问方式和我们平时在GUI里点开属性面板查看信息是一样的逻辑只是它变成了一条条可直接复制、可写进脚本的命令。1.2 为什么不用GUI而要用dbGet很多刚入行的朋友会问GUI属性面板不是也能看到这些信息吗确实能但GUI有几大痛点。第一当你需要获取的信息是批量化的比如要把所有fanout大于50的net挑出来在GUI里操作会非常低效第二GUI查询结果不方便二次处理你没法直接把抓到的结果扔给下一步脚本使用第三在跑flow的过程中所有操作都是通过脚本来执行的不可能每一步都停下来手动点GUI。dbGet本质上是一个“面向脚本的查询接口”它的返回值可以被Tcl变量直接接收也可以直接作为条件判断这就意味着你可以在Innovus的自动化流程里大量使用它来做对象选择、参数统计、逻辑判断。举个例子你在做floorplan阶段想看看所有macro摆放在什么位置一条dbGet [dbGet top.insts -if {.isMacro true}].box就能把坐标全部抓出来。这种能力是GUI无法比拟的。2. 基本语法和参数先看懂再动手2.1 dbGet的基本调用格式dbGet的调用格式可以理解为三段拼接dbGet 对象.属性 [-if 过滤条件] [-p] [-regexp] [-v]最基础的用法是直接dbGet加上对象.属性。例如dbGet top.insts.name这条命令会返回当前设计里所有instance的名字。这里top是查询的起点insts表示从顶层往下取所有instance对象name表示每个instance对象的name属性。连起来就是取顶层所有instance的名字。再往下走如果你想查看某个特定instance的cell类型可以先根据名字选中这个instance再取它的cell属性dbGet [dbGet top.insts -if {.name u_clock_inv1}].cell.name这里外层dbGet的内层方括号先执行返回的是u_clock_inv1这个instance的对象句柄带0x开头的对象引用随后外层对这个对象句柄取cell.name。这就是dbGet非常经典的嵌套用法。你会在后面看到大量这种写法的变体。2.2 理解返回值类型字符串、列表、对象句柄dbGet的返回值并不总是一个简单的字符串。你需要分清三种情况当你查的是属性值比如name、cell.name、box返回的结果通常是一个字符串或者Tcl列表。当你查询的对象集合本身比如top.insts返回的是一串对象句柄形如0x1a2b3c4d 0x5e6f7a8b ...。如果你在查询属性时加了-p参数返回结果的层级会被展平方便进一步处理。初学最容易困惑的是我明明查top.insts.name返回结果怎么是一串奇怪的0x...这通常是因为你写成了dbGet top.insts加上别的拼接方式或者查询的对象层级没有被正确解析。建议在写嵌套命令时先用单独的dbGet top.insts看看返回的是不是对象句柄再做下一步。2.3 head和top两个很实用的查询起点dbGet里除了top还有一个很常用的起点叫head。top指的是当前设计顶层而head指的是当前被选中的对象集合如果你在脚本或GUI里选中了一些instance这些被选中的对象就是“head”。这在交互式操作里特别有用。比如你在版图里用鼠标选中了一堆instance然后在控制台输入dbGet head.name它就会返回当前选中对象的名字列表。这比来回切换GUI属性面板快得多。head在某些脚本场景里也非常有用比如你通过select_insts之类的命令选中了目标集合后续所有针对选中对象的操作都可以用head来承接。2.4 -p参数的用途-p参数的作用是把返回结果从“对象句柄”变为“属性值”并且保持层级结构。举个例子dbGet top.insts.cell.name这条命令在某些版本里可能不会直接返回所有instance的cell名字因为中间隔着cell这一层对象。但如果你写作dbGet [dbGet top.insts].cell.name就能正常返回。而-p的作用是在你希望将对象列表“平铺”时使用它可以把多级嵌套对象转成一个扁平列表方便用foreach遍历。实际使用中-p通常长这样dbGet -p top.insts.cell.name这样可以把所有cell名字平铺成一个列表输出。如果你发现输出结果里混着很多0x...句柄而不是清晰的字符串试试在命令里加上-p。3. 高频实用模板照着抄就能用3.1 查instance和cell相关属性日常工作中查instance和cell属性是最频繁的需求。比如你接到一个重要任务统计当前设计里所有标准单元的cell面积总和。你可以先把所有cell.area取出来再用Tcl的循环累加set inst_cells [dbGet top.insts.cell.name] set total_area 0 foreach cell_name $inst_cells { set cell_area [dbGet [dbGet top.cells -if {.name $cell_name}].area] if {$cell_area ! } { set total_area [expr {$total_area $cell_area}] } } puts Total area: $total_area不过上述写法在大型设计里会比较慢更高效的办法是直接用dbGet配合-if条件过滤。比如想知道哪些instance的cell类型是BUF_X2dbGet top.insts.cell.name -if {.cell.name BUF_X2}这条命令查询的对象是top.insts但筛选条件是每个instance的cell.name属性。注意-if里用的是带点前缀的.cell.name表示针对当前查询对象的属性做判断。如果你要查所有名字以u_clk_开头的instancedbGet top.insts.name -regexp {^u_clk_}-regexp参数表示后面的匹配方式采用正则表达式而不是精确匹配。正则里^表示开头.*表示任意多个字符用起来非常方便。想查特定类型的所有instance时还可以在-if里写更复杂的逻辑dbGet top.insts.name -if {.cell.name BUF_X2 || .cell.name BUF_X4}3.2 查net和pin的常用姿势查net和pin的信息是后端项目里最常做的事。想查某条net下挂了哪些pindbGet [dbGet top.nets -if {.name clk_net}].allPins.pin.name这里allPins是net对象下一个属性表示这条net连接的所有pin对象.name取pin的名字。如果你还想进一步知道这些pin分别属于哪个instancedbGet [dbGet top.nets -if {.name clk_net}].allPins.inst.nameallPins返回的是pin对象列表每个pin对象下面有inst属性指向它所属的instance然后继续取name。查某个instance的pin也很简单比如想看看u_reg0这个instance上有哪些pindbGet [dbGet top.insts -if {.name u_reg0}].pins.name这里pins是instance对象下的pin属性取每个pin的name。如果还想知道每个pin对应的net就把.net.name接上dbGet [dbGet top.insts -if {.name u_reg0}].pins.net.name这条命令会输出u_reg0所有pin所连接的net名字非常实用。经常有人问怎么快速判断某个pin是否悬空就可以用这个命令看pin对应的net名是不是空。3.3 查PG pin/PG term直接命中热搜里的问题热搜里有一个很典型的场景怎么选中标准单元里名字为biasnw的PG term。这个问题在跑IR drop分析或者做power intent相关操作时非常常见。PG term是instance上和电源地网络连接的引脚。要选中任意标准单元中名字为biasnw的PG term写法如下dbGet top.insts.pgTerms.name -if {.name biasnw}如果你确定只查某个具体的instance比如叫u_bias_cell的单元那就加一层instance过滤dbGet [dbGet top.insts -if {.name u_bias_cell}].pgTerms.name -if {.name biasnw}很多新版工艺库里的标准单元PG pin有两种名称一种叫pgPinName一种叫pgTermName两者可能不一样。遇到查不到PG term名字的情况可以先看看这个单元到底有哪些PG termdbGet [dbGet top.insts -if {.name u_bias_cell}].pgTerms.name再看每个PG term对应的pg pin名字dbGet [dbGet top.insts -if {.name u_bias_cell}].pgTerms.pgPinName如果你不仅仅想查看还想“选中”这些对象可以配合addToSelected或者直接在当前会话中把查询结果传给选中命令。比如set sel_terms [dbGet top.insts.pgTerms -if {.name biasnw}] select_obj $sel_terms不同版本里选中对象的命令名不完全一致常见的是select_obj或addToSelected需要根据你所用版本做微调。但核心思路是一致的先用dbGet抓到对象句柄再交给选中命令。3.4 查box、area、fence等物理信息dbGet不仅查逻辑连接关系还能直接查物理坐标信息。想知道某个宏单元在版图上的坐标范围可以直接用dbGet [dbGet top.insts -if {.name u_macro1}].box返回结果通常是x1 y1 x2 y2四个值代表矩形左下角和右上角的坐标。如果你想获取所有macro instance的坐标可以加条件过滤dbGet top.insts.box -if {.isMacro true}dbGet里还有很多带is前缀的布尔属性比如isMacro、isPad、isFiller、isEndCap等用来做对象分类筛选特别方便。查filler有多少个就可以用dbGet top.insts.name -if {.isFiller true}想把结果数量统计出来就可以用llengthllength [dbGet top.insts.name -if {.isFiller true}]这是后续做项目报表时非常高频的写法。4. 进阶条件过滤、正则与批量处理4.1 -if表达式深入理解-if是dbGet强悍过滤器。它的本质就是一个布尔表达式针对查询结果中的每个对象判断条件是否成立成立才输出。可以用、!、、、~匹配、!~不匹配等操作符。注意~和!~用于字符串模式匹配这里有个常见的坑-if里使用~做通配符匹配时模式串里的*不是正则的*而是通配符的*。例如dbGet top.insts.name -if {.name ~ *u_clk*}这样才能匹配所有名字里包含u_clk的instance。如果你用的是那就是精确匹配不带通配符功能。处理数字属性时-if的数值比较很直观比如拿所有fanout大于50的netdbGet top.nets.name -if {.fanout 50}注意fanout这个属性并不是所有版本都能直接访问有些版本里要写成.numPins或者先获取allPins再用llength处理。如果发现属性不存在可以先通过dbGet top.nets.???查看该对象支持哪些属性具体方法见下一节再做调整。4.2 正则表达式的使用场景-regexp参数配合正则表达式能实现很多精确筛选。比如你想找出所有名字以u_开头且后面跟着数字的instancedbGet top.insts.name -regexp {^u_[0-9]}这比用-if加~通配符更加精准。正则能力尤其适合处理lib cell命名很不规则的工艺库比如一个工艺库里混着INV_X1、INV_X2、BUF_X1、CKND2_X1你想把所有INV和BUF类cell找出来dbGet top.insts.name -regexp {_(INV|BUF)_X[0-9]$}正则表达式写熟了以后你会发现它在做cell类型归类、模块边界识别、特殊走线命名筛选中非常高效。不过正则表达式有个性能问题在几百万instance的设计里用过于复杂的正则会有明显延迟。建议能用-if精确匹配解决的就别用正则确实需要模糊匹配时再上-regexp。4.3 配合foreach做批量操作dbGet真正的威力在于和脚本逻辑结合起来。举一个我实际项目里的例子要把所有fanout大于100的net的负载cell都找到并把它们的size改大。核心思路就是先用dbGet筛出目标net再对每条net的allPins逐一处理。set high_fanout_nets [dbGet top.nets -if {.numPins 100}] foreach net $high_fanout_nets { set load_pins [dbGet $net.allPins] foreach pin $load_pins { set inst [dbGet $pin.inst] puts Net [dbGet $net.name] pin [dbGet $pin.name] belongs to [dbGet $inst.name] } }这里有个细节当你已经拿到一个对象句柄比如代码里的$net继续用dbGet $net.allPins时$net后面跟allPins会被正确地解析成该对象下的子对象列表。这种在循环里动态拼接属性的方式在实际脚本里非常常见。还有一种是批量导数据到外部文件比如你要把所有instance的名字、cell类型、坐标导出来做检查set all_insts [dbGet top.insts] set fh [open inst_list.rpt w] foreach inst $all_insts { set n [dbGet $inst.name] set c [dbGet $inst.cell.name] set b [dbGet $inst.box] puts $fh $n $c $b } close $fhdbGet配合Tcl的循环和文件操作就能很轻松地生成自定义报表。这也是很多大型项目里做signoff check、做设计审查QA报表的标准手段。4.4 对象属性查找小技巧有时候你并不能确定某个对象下面有哪些属性。dbGet这里也留了后门直接查???可以列出所有可用属性dbGet top.insts.???这条命令会输出insts对象下的所有属性名比如name、cell、box、pins、pgTerms、isMacro等。同样的方法还可以用在net、pin、cell等对象上dbGet top.nets.??? dbGet top.insts.pins.???这个技巧在刚接触一个新工艺库或者新版工具时特别有用。官方文档虽然全但翻起来远不如直接在命令行里敲???来得快。我自己的习惯是遇到不确定的属性名先???扫一遍再挑几个关键属性做测试。5. 实战中容易踩的坑和调试技巧5.1 命令返回空先检查对象层级最常见的问题是dbGet返回空结果但明明GUI里能看到对象。这种情况十有八九是对象层级写错了。比如dbGet top.insts.pins.name -if {.name A}这种写法-if中的.name匹配的到底是哪个.name是pins的name还是insts的name这种歧义很容易导致过滤条件作用在错误的层级上。建议把查询拆开先查中间对象再加过滤dbGet [dbGet top.insts -if {.name u_cell}].pins.name这样逻辑会清晰很多层级不太容易出错。如果还是返回空就只查一层看看是不是instance名大小写搞错了或者单元名字包含了特殊字符。5.2 属性不存在或类型是列表dbGet返回结果有时候看上去是空格分隔的一串字符串实际上它是Tcl的list。你要把它当列表操作就得用llength、lindex、foreach这类命令。不要试图用string match或者regexp直接处理整个返回值容易出问题。如果dbGet top.insts.name返回了一大串名字而你想数一下有多少个instancellength [dbGet top.insts.name]注意有些属性返回的是“一个元素的列表”和“裸字符串”在Tcl里其实没差别但如果你把返回值简单用[string]方式拼接可能因为引号或空格处理不当导致后续解析出错。稳健的做法是统一用set变量接收再在上下文中使用。5.3 性能问题筛选尽量前置在大规模设计里dbGet的性能需要特别重视。我见过有人写脚本时先dbGet top.insts拿到全部instance再在foreach循环里逐个判断isMacro之类属性结果几百万instance的循环跑了十几分钟。正确的姿势是把能放进-if的筛选条件都放进-if里让dbGet自己先做一轮过滤能大幅减少脚本循环次数。另外如果一个操作需要反复查询同一批对象建议把查询结果缓存到Tcl变量里复用不要每个属性都重新写一遍dbGet。比如我经常把某个模块的所有instance句柄先存到一个变量里后面所有属性查询都基于这个变量展开这样速度会快很多。5.4 在脚本里用dbGet的规范性建议写长脚本时dbGet建议不要直接裸写在复杂表达式里而是拆成变量赋值增加可读性。同时dbGet返回空集的情况在Tcl里是空字符串这在做条件判断时很容易误导。比如if {[dbGet top.insts.name -if {.name u_not_exist}]} { # 这里可能不会执行因为返回空 } else { # 空结果走else分支 }如果你期望的是“只要没查找到就报warning”那就要显式检查返回结果是否为空。我习惯用llength来判断set result [dbGet top.insts.name -if {.name u_not_exist}] if {[llength $result] 0} { puts Warning: no instance found }这种写法更安全也方便加日志定位。6. 把dbGet用顺手的几条心得dbGet命令单独看很简单但真正用顺手需要积累。我自己的习惯是每次遇到新对象结构就先敲???看看属性列表把这个对象能查什么都记在脑子里遇到复杂过滤条件先在命令行小批量试一下确认结果正确再写进长脚本。熟练掌握dbGet之后你会发现很多曾经需要打开GUI反复点击确认的信息现在一行命令就出来了。再配合foreach、llength、open这类Tcl标准操作几乎可以做出任何自定义的分析报表和后处理脚本。最后再分享一个小技巧在写自动化脚本时可以把dbGet的查询结果用puts先打印出来人工确认一遍确认无误后再继续后面对这个结果的操作。这位博主踩过太多因为层级写错、属性名拼错导致的静默出错打印一遍至少能很快发现问题出在哪一行。
返回列表