ARTICLE DETAIL

资讯详情

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

用Tcl脚本在Innovus中自动生成多corner的SDF、SPEF和时序报告

用Tcl脚本在Innovus中自动生成多corner的SDF、SPEF和时序报告 后端做PR的兄弟应该都有这个经历Innovus里跑到block收尾要给仿真组交SDF、给signoff流程交SPEF还得给自己留一份各个corner的时序报告。以前我是一个corner一个corner地敲命令SS一遍、TT一遍、FF又一遍中间很容易漏掉RC提取或者文件名写串。后来我把这套动作统一写成一个Tcl脚本在同一个Innovus session里一次跑完三种corner的延时文件生成今天把这个方法完整拆开讲一遍。文章主要针对数字后端实现阶段的MCMM多corner流程适合正在做block级place and route、需要向仿真或signoff环节批量提交延时数据的工程师参考。1. 三种corner的延时文件到底在给谁用1.1 先把延时文件拆清楚数字后端流程里说的延时文件不是一个单一格式而是一类包含时序信息的文件总称。最常见的是三种SDFStandard Delay Format记录cell的门延时和net的互连延时下游做门级仿真或者STA反标时靠它SPEFStandard Parasitic Exchange Format记录每根net上的R、C寄生参数是交付给signoff工具做精确时序分析的基础时序报告则是report_timing导出的文本包含WNS、TNS和关键路径明细主要用来自己看时序余量、做design review。这三类文件在三种corner下的数值差异非常明显。SS corner慢工艺、低压、高温通常是setup最紧张的场景FF corner快工艺、高压、低温通常是hold最紧张的场景TT corner是典型工作条件用来评估芯片在常见工况下的表现。只交一个corner的延时文件下游仿真和STA根本覆盖不到工艺边界条件芯片的风险会一直藏在暗处。1.2 收尾阶段这些文件在等谁以我最近做的几个block为例PR一结束同时有几拨人在等这批文件。仿真组要SDF他们拿去做带延时的门级仿真确认功能在真实时序下依然成立signoff同事要SPEF要导入Tempus或者PrimeTime做最终时序收敛确认我自己要时序报告用来核对timing修完之后WNS有没有真正改善。这三类文件缺一个后面环节都会被卡住所以一次性把三个corner的都产出来不只是省敲命令的时间更是防止交付环节出现遗漏。2. 动手前先看清Innovus里的view和corner配置2.1 MCMM机制下view、corner、mode的关系用这套脚本有个前提设计已经在MCMM模式下建好了多corner环境。MCMM把mode × corner组合成analysis view命令里真正操作的对象是view而不是corner本身。举个例子corner有ss、tt、ff三个mode有func、scan两个那view就是func_ss、func_tt、func_ff、scan_ss、scan_tt、scan_ff一共六个。进入Innovus之后先花一分钟确认当前session里的配置all_corners all_modes all_analysis_viewsall_analysis_views会把所有注册过的view打出来这正是后面映射表的依据。如果你发现view数量比预期少多半是建view时漏了某个corner或mode得先把环境补齐再跑生成脚本否则某个corner的延时文件注定是空的。这里有个细节值得提醒view的名字是建view时你自己起的跟corner的物理属性没有必然绑定关系。也就是说func_ss_0p99_125c这个名字看起来像SS corner但真正决定它是不是SS的还是背后挂载的library set和operating condition。脚本里校验view存在只是第一道保险真要较真的话还要顺手看一眼每个corner的lib和operating condition是否和预期一致。2.2 视图清单决定脚本里的映射表脚本虽然用foreach自动循环文件命名还是要有可读的短名。view名字可能是func_ss_0p99_125c你总不能直接拿它当文件名下游同事看到ss.sdf才知道这是慢工艺corner。我的做法是先把all_analysis_views的结果打出来再手工维护一个corner到view的映射表set corner_view_map { {ss func_ss_0p99_125c} {tt func_tt_0p99_85c} {ff func_ff_1p1_m40c} }这一步看一眼再写死的动作很关键因为view名字一旦对不上后面extract_rc和write_sdf报的错会让人摸不着头脑排查起来比改一行映射表麻烦得多。与其花时间在报错里猜不如最开始就打印出来确认一遍。3. 用foreach循环把三种corner的延时文件一次跑出来3.1 完整脚本先摆在前面直接贴能用的脚本。在Innovus交互session里source即可也可以放进batch启动脚本输出目录、corner映射、SDF版本都放在文件顶部方便按block调整。脚本本身不长但把该做的校验和提取都包含进去了# # gen_delay_files.tcl # 一次生成三种corner的SDF、SPEF和setup/hold时序报告 # set OUT_DIR ./delay_files if {![file exists $OUT_DIR]} { file mkdir $OUT_DIR } # corner短名 - analysis view名以all_analysis_views输出为准 set corner_view_map { {ss func_ss_0p99_125c} {tt func_tt_0p99_85c} {ff func_ff_1p1_m40c} } # 循环前先校验view都存在 set all_views [all_analysis_views] foreach item $corner_view_map { set view [lindex $item 1] if {[lsearch $all_views $view] 0} { error ERROR: view $view not found in current session! } } foreach item $corner_view_map { set corner [lindex $item 0] set view [lindex $item 1] puts puts $corner / $view # 1. 对当前view提取RC保证SPEF/SDF里的互连延时是真实值 extract_rc -view $view # 2. 写SPEF write_parasitics -view $view -format spef -output $OUT_DIR/${corner}.spef # 3. 写SDFversion按下游仿真工具支持情况选2.1或3.0 write_sdf -view $view -version 2.1 -include_wire_delay -file $OUT_DIR/${corner}.sdf # 4. 分别导出setup和hold的时序报告 redirect -file $OUT_DIR/${corner}_setup.rpt -quiet { report_timing -view $view -delay_type max -nworst 200 -path_type short } redirect -file $OUT_DIR/${corner}_hold.rpt -quiet { report_timing -view $view -delay_type min -nworst 200 -path_type short } puts Generated: ${corner}.sdf / ${corner}.spef / ${corner}_setup.rpt / ${corner}_hold.rpt } puts All corner delay files generated under $OUT_DIR3.2 extract_rc是整段脚本的基石写这类脚本最容易犯的错就是省掉extract_rc觉得PR都做完了RC数据应该还在。单corner模式下也许成立但MCMM不是这样。Innovus的RC提取数据按analysis view独立保存你对func_ss跑过一次extract_rc不代表func_tt里就有数据。write_parasitics和write_sdf都是从当前view在内存中的RC数据生成文件view没提过RC产出的SPEF要么报错要么是残缺的。具体命令选项在不同版本里略有差别跑之前先write_parasitics -help扫一眼比瞎猜稳当。所以循环里第一件事就是extract_rc不是啰嗦是为每个view建立独立且新鲜的RC数据。extract_rc也是整段脚本最耗时的一步百万门级的block单个view提取几分钟很正常三个corner串行下来大概十几分钟。想省时间就把三个corner拆到三个Innovus进程里并行跑最后汇总文件代价是内存和license都要三份block规模不大时没这个必要。3.3 write_sdf的版本和选项怎么选write_sdf里有两处选项经常让人纠结我把自己的经验直接说出来省得大家再试一遍。第一是版本。SDF 2.1最保守老仿真器基本都认3.0在条件时序检查等表达上更完整但个别老工具反标时会有告警。我的原则是下游仿真环境固定就问一句仿真同事没人能回答就默认2.1不会出大错。如果仿真那边明确说要3.0改一行版本号就行没必要两套都留。第二是是否包含wire delay。route_opt完成后的SDF如果没有互连延时路径偏乐观hold本来就风险大结果更看不清。命令里明确加-include_wire_delay或对应的interconnect选项别指望工具默认行为。不同Innovus版本的选项名略有差异以你本地的write_sdf -help为准但必须包含互连延时这条原则不变。3.4 时序报告用redirect落盘report_timing默认输出到stdout在交互session里看还行放在batch脚本里就会被log淹没想回头翻某条路径的报告非常痛苦。用redirect包一层就能干干净净落盘redirect -file $OUT_DIR/${corner}_setup.rpt -quiet { report_timing -view $view -delay_type max -nworst 200 -path_type short }-quiet的意思是文件里只保留命令结果不额外回显到终端。-delay_type max对应setup检查min对应hold检查两个都要分别跑。-nworst 200对我来说是起步值看WNS和TNS够用了真要深挖某条路径再单独rerun那条path就行。4. 实测中最容易翻车的几个地方4.1 坑一RC提取状态没有跟view走我第一次写这个循环时就在这栽过。当时把extract_rc放在循环外面只对其中一个view跑了一次然后循环里直接对三个view write_parasitics。结果ss的SPEF正常tt和ff的SPEF要么报no RC data for view要么文件size是0。排查半天才意识到MCMM下每个view的RC数据是分开存的必须逐个提取。解决办法就是脚本里的顺序每个view先extract_rc再write_parasitics再write_sdf。另外要留意凡是动过布局布线数据的操作eco_route、addMetalFill、重新跑clock_opt都会让已有RC数据失效需要重新提取。我的习惯是把这段脚本放在route_opt和eco_route全部结束后执行固定为流程最后一步确保延时文件和最终网表一致。4.2 坑二view命名和文件名映射不一致第二个坑出现在换block复用脚本的时候。新block的view命名可能跟老block不一样比如corner叫ssg、max、min还和mode拼在一起。映射表一旦没同步脚本会安静跑完但产出的文件名对不上corner下游用错文件就是事故。我现在的做法是脚本开头先set all_views [all_analysis_views]然后用lsearch把映射表里的view挨个校验任何一个不存在就直接error宁可停下来也不要生成一堆残缺文件。这个校验在当前流程里花不了几秒钟但能避免一整个目录的无效交付物下游也不用拿着文件名猜corner。4.3 顺带提醒CTS没跑完就生成SDFclock delay是假的这个严格说不算脚本的坑是流程时机的坑。placement刚结束、CTS还没做的时候跑write_sdfSDF里的clock path延迟要么是理想值要么是零hold检查会异常乐观。下游仿真拿着这种SDF等于掩耳盗铃。生成延时文件的时机必须是clock_opt和route_opt都完成后最好再确认时钟树是propagated状态。拿不准就先report_clock_timing -view看一眼clock path上有没有真实延迟数字再决定是否写SDF。5. 拿到延时文件后怎么快速验证没有白跑5.1 SDF先看头部再看关键路径文件生成不等于文件可用。每次拿到三个corner的SDF我先看头部head -30 ss.sdf这里应该能看到(SDFVERSION 2.1)、(DESIGN block_name)、(TIMESCALE 1ns)这些基本字段。DESIGN名字如果是空的或者跟你预期不符说明写SDF时design对象有误整个文件不能直接用。TIMESCALE也要留个心眼有些流程默认单位跟你的约束不一致反标出来数字差千倍不是没发生过。然后挑setup报告里WNS最差的那条路径找到终点flop的instance名再去SDF里grep这个instance看它的cell delay值和报告里的路径延迟是不是同一个量级。SDF和report_timing的颗粒度不完全一致数字不会1:1对上但差一个数量级肯定有问题。这个交叉验证五分钟左右能拦住大部分粗心错误。5.2 SPEF别只看文件存在SPEF比SDF更容易出现看着生成了其实是空壳的情况。我通常这样查grep -c *D_NET ss.spef数字不应该为0正常在几千到几万量级取决于block的net数量。再打开文件头确认*DESIGN、*DATE、*VARIATION字段齐全。想更严谨一点就在Innovus里跑一次report_parasitics把SPEF里的总电容值和工具报告对比差得多说明extract_rc参数有问题回头重新提取。另外如果SPEF文件size比同corner的SDF小很多也要警惕可能只提取了一部分net的寄生参数。5.3 顺手生成一个manifest延时文件不是这一个block的事block多了文件就会多到记不清哪批对应哪个时间点。我的习惯是在输出目录里再落一个manifest.txt记generation时间、corner到view的映射、每个文件的size和md5校验值。这一步在Tcl里就是几个puts但后续排查这批文件是不是昨天的旧货时能省下大量沟通成本。文件多了以后靠人脑记文件名是不现实的有个manifest至少有个索引可查。6. 把脚本参数化换block直接复用6.1 顶部变量改成输入项脚本用了几次之后我把它改成参数化版本顶部集中放配置set RUN_NAME blockA_v02 set OUT_DIR ./delay_files/${RUN_NAME} set SDF_VERSION 2.1 set NWORST 200 set corner_view_map { ... }换block时只改RUN_NAME和corner_view_map两处其余逻辑完全不动。输出目录按run name分开每次flow结束生成一批独立文件不会被下一次run覆盖。实测下来这个习惯对多版本迭代特别有用回溯哪个网表对应哪批延时文件几秒钟就能定位。如果不按run name分开三个版本的文件堆在一个目录里过两天自己都得懵。6.2 从view名自动推导corner短名如果设计的view命名有固定规律比如func_ss_0p99_125c这种格式可以用正则从view名里提取corner关键字连映射表都不用维护foreach view [all_analysis_views -mode func] { if {[regexp {_(ss|tt|ff)_} $view match corner]} { set short_name $corner } else { puts WARNING: cannot infer corner from $view, skipping continue } # 后续extract_rc write_sdf report_timing... }这个做法灵活但前提是命名规范长期稳定。我建议两套思路都掌握命名规矩就用自动推导省维护成本命名混乱就用显式映射表至少可控。两种方式我都实际跑过最终还是回到映射表因为团队里换人、改命名这种事太常见自动推导的脚本在命名习惯一变的时候就会悄悄跳过文件反而不如映射表报错来得直接。6.3 集成进回归流程的位置最后说下脚本放流程里的位置。我的标准做法是route_opt和eco_route全部结束后单独跑一步generate_delay_files顺手把manifest往固定目录归档。不要放在初始化脚本里也不要在CTS之前跑。之前有同事为了省时间把生成提前到CTS前结果SDF全是理想时钟仿真hold一片绿团队排查了两天才发现是流程顺序问题。这种错踩一次就够了。
返回列表