ARTICLE DETAIL

资讯详情

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

VCS后仿真SDF警告处理:编译选项实战指南

VCS后仿真SDF警告处理:编译选项实战指南 在门级仿真后仿真的现场我大概见过太多这样的场景一段SDF反标注打印刷过去终端里全是Warning: ...开头的信息多到让人的眼睛自动过滤。你心里很清楚真正的时序违例可能就藏在最后一万多条警告里但当你试图去找的时候却根本不知道从哪下手。更麻烦的是这些SDF警告里面有一部分其实并不会对仿真结果造成实实在在的影响但另外一部分如果你忽略它等到流片回来才发现问题那时候就不是重新编译一回就能解决的事了。我写这篇内容就是想把和SDF处理相关的VCS编译选项、运行选项逐个掰开来讲清楚。哪些选项能帮你把警告“压掉”哪些选项能让警告背后的真实问题浮出水面各自的原理是什么在什么场景下应该用哪种组合。这不是一篇照着用户手册抄的说明而是多年跑后仿真、被各种SDF警告折磨过之后整理的实操笔记。1. SDF警告到底是什么它为什么这么“吵”1.1 先搞懂SDF在门级仿真里的角色SDF全称是Standard Delay Format标准延迟格式。它的本质是一个文本文件里面记录的是从版图提取出来的寄生参数、经过时序标注STA计算之后得到的各条路径延迟数据。门级仿真本身并不知道每一级门电路到底该延迟多少它只知道逻辑功能所以必须通过SDF文件把延迟“反标”进去仿真器才会按照真实的时序行为去跑。正因为SDF文件结构复杂而且它要和网表、标准单元库、时序检查模型三方对应任何一方对不上都会触发警告。比如SDF里的某个实例路径在网表里根本找不到或者SDF里的延迟值超出了库模型允许的范围又或者SDF某些时序检查类型比如hold time是负值和库单元的定义不一致VCS都会给出一条甚至很多条警告。后仿真的日志动辄上万行SDF警告占大头是非常正常的现象。真正的问题不是警告多而是你无法快速判断“这些警告里有没有要命的”。1.2 VCS处理SDF的两层机构编译期与运行期这里有个关键点需要明白VCS处理SDF并不是只在编译时发生。$sdf_annotate是仿真时调用的系统任务它在仿真运行阶段读取SDF并执行反标注而VCS在编译时则要对网表、库文件做解析把可能出现反标注问题的结构提前暴露出来。换句话说你会看到两类不同来源的信息编译阶段出现的关于库单元、端口、路径不匹配的warning运行阶段通过$sdf_annotate打印出来的SDF反标注警告。这两类信息的处理方式不完全相同对应的VCS选项也不同。很多人一上来就只知道加nosdfverbose把警告全部关掉结果等于把自己的眼睛蒙上了。正确做法是先通过选项让警告信息“分级呈现”再决定哪些要屏蔽、哪些要放大。2. 那些你早晚会用到的VCS编译选项一个一个说清楚2.1sdfverbose与nosdfverbose控制SDF信息的输出量这是最基础的一对选项。默认情况下VCS会限制SDF反标注过程中每条警告只打印有限的细节尤其是在顶层SDF反标注出现大量内部错误时默认输出会被截断。加上sdfverbose之后VCS会输出完整的SDF解析和反标注信息包括SDF文件里每一行条目被如何处理、有没有成功匹配到网表实例、反标进去的延迟值是多少。我见过不少人在排查反标注问题时第一反应是“怎么SDF文件好像没生效”然后反复检查文件路径和$sdf_annotate的调用位置最后发现只是默认输出太精简有效信息没显示出来。加上sdfverbose重新跑一次真相很快就浮出水面。反过来当你的设计已经收敛、后仿真回归天天在跑日志里全是无关痛痒的SDF信息这时候用nosdfverbose或者不添加sdfverbose来减少输出量是合理的。但要明确这不是“关掉检查”只是减少打印。真正要关掉某类检查需要下面这些更细的选项。2.2sdfreport把反标注结果写到报告文件里这个选项算是我个人最喜欢的“冷静型”工具。它不会在终端刷屏而是把SDF反标注的统计信息、错误信息汇总到一个报告文件里。配合report指定输出目录使用例如simv sdfreport report./sdf_report运行结束之后去./sdf_report目录里找.rpt后缀的文件里面会有非常清晰的反标注统计总共读取了多少SDF条目、成功反标了多少条、失败了多少条、失败原因是什么、涉及哪些实例路径。这个选项特别适合大规模SoC的后仿真。你想想一个百万门级的设计SDF反标注条目可能上百万条终端打印根本看不过来眼睛盯到流泪也看不出规律。把报告导出之后用脚本统计一下失败条目的分布马上就清楚是某个IP内部路径的问题还是整个模块的例化名对不上。2.3neg_tchk负时序检查能否被接受的开关标准单元库里很多触发器的hold-time是负值SDF文件里对应的$hold条目也可能是负的。VCS默认情况下允许负时序检查值存在但如果某些库或者某些SDF文件包含负的$setup、$hold并且你遇到过“时序检查结果异常”的问题就要确认编译时有没有被某些配置把负值检查能力关掉了。neg_tchk这个选项就是明确告诉VCS允许负的时序检查值。如果你的SDF里有负的保持时间但编译时没有加这个选项反标注后可能表现出时序检查行为的偏差而且这种偏差很难通过常规报错定位往往表现为偶发的仿真时序异常。我在实际项目中遇到过一种情况某个第三方IP的库文件里写了$hold(posedge CLK, negedge D, -0.2)SDF里对应也是负值。加不加neg_tchk在最开始的仿真中看不出区别但换了一个corner的SDF之后问题突然爆发检查一堆寄存器的hold-time全部报错。最后排查下来就是编译选项中少了neg_tchk。2.4overlap控制时序检查重叠告警时序检查项如setup、hold之间可能存在重叠区域这在某些高速接口单元里比较常见。默认情况下VCS会给出警告但不会让仿真停下来。如果项目对时序余量特别敏感你想揪出所有潜在的重叠问题可以在编译或运行时添加overlap让这类警告更明确地呈现在日志里。这个选项我一般只在专门做时序健康检查时打开。日常回归是不开的因为高速接口的时序重叠警告往往非常密集开了之后日志量会翻好几倍对排查真正功能问题反而是一种干扰。2.5pathpulse设置路径脉冲限制SDF文件里可能有$PATHPULSE条目用于定义某个路径上允许的最小脉冲宽度。仿真时如果输入脉冲宽度小于这个值VCS会把它视为脉冲并可能产生X态传播。pathpulse选项用来控制这类检查的开启和关闭行为。默认情况下VCS对$PATHPULSE的支持是开启的但在某些设计里SDF的$PATHPULSE数据和库的脉冲检查模型有细微出入导致仿真器产生不符合预期的X态。这种时候如果确认库模型本身没问题、是脉冲过滤阈值设置过严才可以考虑关闭路径脉冲检查。但关闭之前一定要确认不是真实毛刺问题否则后仿真就白跑了。2.6multisource_int_delays多源内部延迟怎么处理现在的先进工艺节点下单元内部多输入到输出可能存在多条延迟路径SDF5.0标准里也引入了多源延迟的描述方式。VCS默认会尝试合并这些路径的延迟但如果SDF文件里有明确的$setup、$hold等边沿相关数据并且设计中存在复杂的时钟门控结构建议显式加上multisource_int_delays让VCS按照标准的多源内部延迟方式处理。这个选项我没有在小规模测试芯片上遇到过太大区别但在某个带高频接口的SoC项目里加不加这个选项后仿真的SDF warning数目差了将近一倍。具体表现是不加的时候大量cell内部延迟反标警告“multi-source path not supported”加上之后警告明显减少。如果你用的是EDA工具生成的新版SDF文件建议编译时直接把这个选项加上成本很低。2.7sdfprotect与加密SDF文件的处理有些IP供应商会提供加密过的SDF文件VCS读取时会打印类似“encrypted SDF”的信息。加上sdfprotect选项可以让VCS正确处理这类文件。这个选项平时用不上但一旦遇到不加的话SDF反标注会直接静默失败仿真结果完全没延迟信息而你还以为跑的是后仿真。这个坑非常隐蔽特别容易在IP集成时踩中。3. 把选项用起来一套典型后仿真的编译与运行流程3.1 编译阶段的VCS命令构造先给一套我常用的基于Makefile风格的编译命令作为模板根据项目库名、文件列表自行替换vcs -sverilog \ v2k \ -full64 \ -debug_accessall \ -timescale1ns/1ps \ neg_tchk \ overlap \ multisource_int_delays \ sdfreport \ report./sdf_report \ -f filelist.f \ -v standard_cell.v \ -y path_to_lib libext.v \ -top tb_top \ -o simv这里每一行都不是随手写的neg_tchk确保标准单元库里常见的负时序检查值能被正确处理overlap编译阶段就把时序检查重叠的提醒打开跑一轮健康检查multisource_int_delays应对多源内部延迟sdfreport report./sdf_report把SDF反标注报告导出到独立目录等待运行结束后统一检查-v和-y分别指定标准单元库的单个库文件以及库搜索路径这是SDF反标注能否命中实例的关键基础库没给对后面的SDF反标全是白搭。3.2 运行阶段的仿真命令构造门级仿真中$sdf_annotate通常写在testbench里。你当然可以只用系统默认的调用方式但强烈建议把SDF的路径、模块实例和时序检查范围都写清楚比如initial begin $sdf_annotate(tb_top.dut.sdf, tb_top.dut, , sdf_log.log); end很多人在testbench里只写了前两个参数SDF文件和实例路径后面的日志文件参数空着。这样VCS默认把SDF反标注信息打印到标准输出里日志文件反而没有详细记录。第三个参数配置时可以把配置信息写到日志文件里这样SDF反标注过程的信息就不会和仿真log混在一起。运行命令我在回归时一般这样写./simv sdfverbose neg_tchk overlap \ ntb_random_seed1 \ fsdbautoflush \ -l sim_$tc.log重点解释sdfverbose的位置它在运行阶段依然生效可以把$sdf_annotate的具体操作过程完整呈现。日常回归我不开它但在第一次跑新SDF文件、或者换库、换corner时我一定是开着它跑一轮的确认关键路径的反标注都正常匹配。否则一上来就闷头跑最后报时序违例你连是SDF反标失败还是真实违例都分不清。3.3 与Verdi的联合使用让SDF信息可视化后仿真中我习惯用Verdi来看波形和反标后的延迟信息。VCS在编译时加上-debug_accessall或者-debug_pp然后在testbench里调用$fsdbDumpfile和$fsdbDumpvars仿真结束生成fsdb文件Verdi可以直接打开并且能显示单元内部的延迟值。更有用的一个操作是在Verdi里把SDF反标注的message窗口单独拉出来。Verdi的message window会解析VCS打印出来的SDF warning按类型分组点击某一条warning可以直接跳到对应的门级实例上。这个功能在排查SDF反标失败时效率极高。比如警告“IOPATH not found”你可以直接跳到那个cell上看它的pin定义对比SDF里写的路径马上定位。不过想实现这一点有一个前提运行仿真时不能加nosdfverbose必须保留一定程度的SDF message输出。如果你的编译脚本里默认关掉了SDF细节打印Verdi那个消息窗口就只能看到一大串无分类信息没法快速跳转。3.4 一个“压警告”的实用技巧当你已经确认一个模块的SDF反标注稳定且正确但每次回归的日志还是被它刷屏时可以通过环境变量或者在testbench里控制打印过滤级别。我不推荐一上来就全局关闭所有SDF warning更推荐按实例屏蔽。一个比较优雅的解决办法是在testbench里针对不关心的模块用$sdf_annotate的第三个参数sdf_configfile传入一个配置文件配置失败条目的打印级别。例如initial begin $sdf_annotate(core.sdf, tb_top.dut.core, sdf_config.tab, core_sdf.log); endsdf_config.tab里写COMPILED SCALE MTM WIDTH这种方式适合你已经确认某些SDF条目与当前仿真配置不相关比如某些多周期路径的时序检查核心功能和安全相关模块的警告不要在这层过滤。很多人把“压警告”做成了一刀切结果真正的风险也被压掉了。我个人原则是可以接受“降噪”但必须保留“报警”能力。4. SDF警告类型与排查从“看见”到“看懂”4.1 高频SDF警告速查表为了让你拿到日志后能快速判断每类警告的紧急程度我整理了后仿真中最常遇到的几类SDF警告以及它们对应的排查思路警告关键字可能原因紧急程度排查方向IOPATH not foundSDF里的单元输入输出路径和库单元不匹配高检查库版本、单元名、引脚名是否一致SDF instance not foundSDF文件里的例化路径在网表中不存在极高网表和SDF是否对应同一版设计Negative delaySDF里有负延迟值中确认是否需加neg_tchk结合库模型判断Timing check not foundSDF的检查类型如$setup在库单元里没有定义中确认库是否为带时序检查的仿真库Pathpulse too narrow配置的脉冲宽度限制过小低确认是否为真实脉冲过滤需求Multi-source path多源内部延迟无法合并中加multisource_int_delays确认SDF版本SDF file older/newer versionSDF版本与VCS支持版本有偏差低确认SDF版本如5.0/4.0并允许转换INTERCONNECT not found线网延迟条目找不到对应连线中检查网表是否含RC提取后的互连信息4.2 最高危的一类实例路径对不上在所有SDF warning里SDF instance not found是必须清零的。这种警告意味着你预期的时序信息压根没有反标到指定模块上仿真跑的时候那个模块可能是零延迟或默认延迟在跑。产生原因通常有几个一是SDF文件是综合后或PR后生成的生成时顶层模块名、例化名与后仿真所用的网表不一致二是网表经过某些ECO修改、重命名后和SDF不同步三是在testbench里$sdf_annotate的例化路径写错了。排查方式先用grep把一个典型实例名从SDF文件里捞出来再到网表里搜grep -n core_top/ff_reg_0 tb_top.sdf grep -n core_top/ff_reg_0 netlist.v两边一对比是名字不一致还是路径不一致一眼就能看出来。再看$sdf_annotate写的模块实例路径确认是不是从testbench到目标模块的层级写错了。4.3 容易被忽略的负时序检查问题负时序检查negative timing check听起来反直觉但在现有很多工艺库里很常见。触发器的hold time是负值意味着数据在时钟有效沿之后到来一点点也依然能满足保持时间要求因为实际器件内部还有一段延迟。我在第2.3节里已经提过neg_tchk这里补充一个排查细节如果你看到类似“negative timing check limit exceeded”的警告不要简单地去加neg_tchk就完事还要去库里确认这个负值是否合理。拿一个具体例子说某库里的$hold写的是-0.5ns但SDF里标注的是-0.8ns。这可能是不同corner下的合理差异也可能意味着SDF和库的版本不匹配。这时候建议查一下该库的databook或者工艺文档确认该corner下的最小负保持时间范围。如果SDF超出范围太大往往是反标有问题。4.4$setup与$hold检查的“覆盖范围”还有一个经常被误解的点很多工程师以为只要SDF文件成功反标了所有寄存器的setup/hold检查都会自动打开。实际情况是反标延迟和执行时序检查是两回事。标准单元库里必须有对应的$setup、$hold检查模型SDF文件里也必须有对应的$SETUPHOLD或$setup、$hold条目两者都满足时检查才会被真正执行。如果你跑完仿真日志里没有任何setup/hold违例报告不要高兴太早先确认时序检查到底开了没有。最直接的方法是在testbench里主动制造一个偏移看仿真器报不报违反。或者反着来把某个信号故意延时如果仿真器完全无反应大概率是检查根本没生效。这个排查思路在跑“看似成功”的后仿真时尤其重要。4.5 与库仿真模型有关的IOPATH警告IOPATH not found是第二高频的SDF警告。它的字面意思是SDF文件里描述了一个从输入pin到输出pin的延迟路径但库单元模型里没有定义这条路径。我遇到过一个很具体的场景某个buffer单元在SDF里写的是从A到Y的IOPATH但库里该单元模型的时序块里只定义了(posedge A (Y:...))这种边沿相关路径没有定义普通电平路径。VCS就无法成功反标这条延迟。排查这类问题最好是打开库文件搜索对应的单元看它的specify块里有哪些路径定义然后把SDF里的IOPATH条目和库定义逐条比对。如果库模型的路径类型和SDF不匹配通常需要找IP供应商确认或者换一个版本的仿真库。不要自己随便改SDF文件或库模型这种事情一旦出了偏差后面整个时序仿真都不可信。5. 我在跑后仿真中踩过的一些坑5.1 为了“安静”把SDF verbose关了反而找不到问题有一次回归跑挂了日志里最后几条是某种存储单元输出X态扩散。正常思路是先看SDF warning有没有这个单元的路径。但当时的编译脚本为了减少日志量全局把SDF细节打印关掉了结果X态源头根本无从查起。后来我重新编译了一版加了sdfverbose再跑一次同样的用例日志里才发现那块存储阵列有几百条IOPATH not found原因是一个子模块被ECO替换成新单元SDF和库模型版本没跟上。如果保留默认的SDF verbose输出第一轮就能定位问题。从那之后我在回归脚本里的做法就是SDF warning默认保留只把“已经确认无害”的模块用配置文件单独过滤。5.2 换corner时千万记得重新检查SDF相关编译选项工艺角从SS换到FF、电压从0.72V换到0.88VSDF文件会整体换一套。很多人只改了testbench里$sdf_annotate的路径其他编译选项完全不动。这在大多数时候没问题但有一类特殊情况不同corner下的延迟值范围变化很大某些corner下负时序检查值的绝对值会超过默认阈值导致仿真行为和预期不符。建议在每次切换corner后先跑一个最小用例把SDF report打开对比成功反标的条目数。只有反标成功率和延迟范围都正常才继续跑全量回归。不要以为“之前都这么跑的这次换文件也没事”。5.3 门级仿真里memory初始化与SDF的关系这是一个挺多人问我的问题后仿真里memory没有初始化结果一片X态和SDF有关系吗我的回答是SDF本身不会让memory失去初始化但后仿真里memory的初始化方式和SDF的反标顺序、时钟关系确实有微妙联系。如果你在testbench里用了$readmemh或$readmemb函数来初始化memory一定要确认初始化发生在$sdf_annotate之后、并且在第一个时钟沿之前。某些仿真库里memory的行为模型包含内部延迟路径如果初始化的过程受到SDF反标延迟影响可能出现部分单元初始化失败。实战中建议分两步检查先注释掉$sdf_annotate跑一遍确认memory initialization本身没问题再打开SDF跑一遍如果此时memory出现X态就要看SDF反标的是不是包含了memory内部路径以及memory单元的库模型是否适合后仿真。5.4 别把$sdf_annotate写在initial里太靠前的位置$sdf_annotate的执行顺序在testbench里也有讲究。它应该写在initial块里但要在时钟生成和复位释放之前完成。如果在复位已经释放之后再执行SDF反标注可能在反标生效前电路已经以零延迟或部分延迟的状态跑了一段产生非真实的X态传播。推荐的写法是initial begin $sdf_annotate(tb_top.sdf, tb_top.dut); #1; $fsdbDumpfile(tb_top.fsdb); $fsdbDumpvars(0, tb_top); reset 1; #100; reset 0; end这里的#1不是随意加的是给SDF反标准一个小的时间裕量确保反标操作在当前仿真时间片上彻底完成。有些工程师认为这种做法会引入人为延迟导致时序不对其实不会——后仿真的时钟和复位操作本身也是被SDF延迟约束的这一个时间单位的延迟只影响事件触发的先后顺序不改变电路本身的时序关系。5.5 SDF报告文件里的“count”才是最重要的指标sdfreport生成的报告文件内容比较长很多人一打开就不知道看哪里。我建议你只看三组数据SDF解析条目总数成功反标条目总数失败反标条目总数及其分类明细。这三组数据在报告文件里有明确的count字段。拿它们和前一次正常仿真的report做对比如果总数一致、失败数为0说明反标过程健康。如果失败数明显上升先把失败条目按分类统计一下再决定下一步排查方向。我曾经处理过一个caseSDF warning在终端只显示了几十条以为问题不严重。后来用report一看失败条目总数达到几万条只是VCS默认的打印频率把大部分信息吞掉了。从那次起我每次跑后仿真回归都会保留sdfreport不管终端上有没有刷屏报告文件永远最可靠。5.6 一些后端同事不知道、但对仿真很有用的库选项最后分享一个跨岗位协作的经验。前端或验证工程师拿到库时经常只关心.v仿真库有没有很少注意库里的specify块是否完整。其实后仿真能否正确执行时序检查、SDF能否顺利反标很大程度取决于这个仿真库的specify块写得好不好。如果你发现SDF反标总是出现奇怪的失败可以先和后端同事确认一下当前给的仿真库是不是和网表、SDF来自同一版PR输出有些库为了仿真速度会提供-no_specify版本那种库根本没法跑后仿真因为时序检查全被剪掉了。用错库的场面我见过不止一次SDF warning一片一片的但真正的检查一个都没执行仿真“绿得发假”。6. 把SDF警告管理做成流程的一部分跑后仿真不是“跑一次、看有没有fail”那么简单。SDF警告的治理应该是一个迭代流程新设计第一次跑后仿真时把sdfverbose和sdfreport都打开把所有警告分类、定级、确认是否可接受然后针对确认无害的警告用配置文件或选项精准过滤最后形成一套“白名单”让日常回归的日志保持干净同时又保留对新问题的检测能力。我在实际项目里习惯建一个sdf_warning_review的文档每次SDF文件或网表更新后先跑一轮把新的sdfreport结果和上一版对比。新增的FAIL条目一条条过确认是工具差异还是设计改动引入的。这个过程看似繁琐但能避免大量后仿真阶段才暴露的时序问题。再说一个经验之谈如果SDF反标之后开门级仿真你发现波形里到处都是X态且来源是寄存器的时序检查违例比起反复调编译选项先回头确认SDF和网表的版本匹配关系。版本不匹配造成的SDF警告是最没规律、也最耗费时间的。这类问题一旦发生优先级要排在所有编译选项调优之前。后仿真里的SDF警告说到底是整个数字芯片验证流程里最“琐碎”但最关键的一环。它不会像功能bug那样直接导致仿真失败却会在你意想不到的时刻用一场悄无声息的时序失效给你上一课。把VCS这些编译选项记在心里不是为了“消除警告”而是为了在警告来临时你能有足够的判断力去分辨哪些只是噪音哪些是警报。
返回列表