ARTICLE DETAIL

资讯详情

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

VCS覆盖率收敛实战:URG与TC管理精准排查未覆盖点及Toggle优化

VCS覆盖率收敛实战:URG与TC管理精准排查未覆盖点及Toggle优化 1. 覆盖率排查这件事为什么值得单独拎出来讲数字前端验证做到中后期最怕的不是case跑不过而是跑了一大堆case覆盖率报告打开一看——代码覆盖率卡在87%死活上不去Toggle覆盖率更惨连70%都不到。这时候你面对的是几百个test case和一份密密麻麻的覆盖率数据库要从里面精准定位到“到底哪个TC没覆盖到哪一行、哪个信号没翻转”靠人眼扫报告基本等于大海捞针。VCS作为业界主流的仿真工具它自带的覆盖率收集和分析体系其实非常完整但很多同行平时只用到最表面的那层——跑完仿真看一眼urg报告看到百分比不达标就继续加case加完再跑跑完再看循环往复。这种“盲加case”的方式效率极低因为你根本不知道新加的case到底有没有打到那个未覆盖的点上。这篇文章要聊的就是怎么用VCS的覆盖率体系配合URGUnified Report Generator和TCTest Case管理机制高效排查未覆盖的TC同时把Toggle收集策略优化到位。适合已经有一定VCS使用经验、正在做模块级或系统级覆盖率收敛的验证工程师也适合想从“能跑通仿真”进阶到“能精准收敛覆盖率”的朋友。核心关键词会围绕VCS、覆盖率、TC、Toggle、URG这几个点展开穿插一些实际项目里踩过的坑和总结出来的排查套路。2. 覆盖率体系与TC管理机制拆解2.1 VCS覆盖率收集的底层逻辑VCS的覆盖率收集分几个维度代码覆盖率Line、Condition、FSM、Branch、Toggle、功能覆盖率Covergroup和断言覆盖率。这些数据在仿真过程中由VCS自动采集最终写入一个统一的覆盖率数据库simv.vdb。这个vdb目录的结构其实很有讲究里面按test case分目录存储每个TC的覆盖率数据独立存放这也是后面能做TC级排查的基础。很多人不知道的是VCS在编译阶段就需要通过编译选项来决定收集哪些类型的覆盖率。常用的选项组合是这样的vcs -cm linecondfsmbranchtgl \ -cm_dir ./cov.vdb \ -cm_name test_case_name \ -f filelist.f \ -o simv这里的-cm指定收集类型-cm_dir指定覆盖率数据库路径-cm_name给当前TC打标签。注意-cm_name这个参数非常关键——如果你所有TC都用同一个名字那覆盖率数据库里就只有一个条目后面想做TC级分析就无从下手了。我见过有团队因为脚本里-cm_name写死了跑了三百多个case结果urg报告里只显示一个TC排查的时候完全抓瞎。仿真运行阶段还需要加上-cm选项来激活覆盖率采集./simv -cm linecondfsmbranchtgl \ -cm_dir ./cov.vdb \ -cm_name test_case_name编译和运行两个阶段的-cm类型必须一致否则运行时会报warning而且实际采集的数据可能不完整。这一点在搭建回归脚本的时候要特别注意建议把覆盖率类型定义成一个变量编译和运行共用。2.2 TC在覆盖率数据库中的组织方式每个TC在vdb目录下对应一个以-cm_name命名的子目录里面包含snps目录和test目录。snps目录下存放的是覆盖率原始数据test目录下是测试信息。当你用urg生成报告时urg会自动扫描vdb下所有TC的数据然后做merge。这里有一个容易忽略的点TC的命名规范直接影响后续排查效率。建议命名格式包含模块名、测试场景和序号比如uart_tx_fifo_overflow_001、uart_rx_parity_err_002。这样在urg报告里一眼就能看出每个TC覆盖了什么场景排查未覆盖点时能快速判断是哪个场景缺失。如果TC命名是test1、test2、test3这种那你就只能一个个点开看效率天差地别。我在上一个项目里接手过一个已经跑了两个月的回归环境TC名字全是case_001到case_487排查一个未覆盖的FSM状态花了整整两天就是因为完全不知道每个case在测什么。2.3 URG报告的核心用法URG是VCS配套的覆盖率报告生成工具基本用法urg -dir ./cov.vdb -report ./urg_report -format both-format both会同时生成HTML和文本格式的报告。HTML报告适合交互式查看文本报告适合脚本解析。URG还支持很多有用的选项-show tests在报告中列出每个覆盖点被哪些TC覆盖-show missing专门列出未覆盖的覆盖点-metric linecondtgl指定报告包含的覆盖率类型-grade生成覆盖率评分最实用的组合是urg -dir ./cov.vdb -report ./urg_report \ -show tests -show missing \ -metric linecondfsmbranchtgl \ -format both这样生成的报告里每个未覆盖的代码行或Toggle点都会标注“Missing”而且能看到哪些TC覆盖了相邻的代码。这个信息对于判断“是case没写对还是激励没打到”非常关键。3. 未覆盖TC的高效排查方法论3.1 从URG报告反向定位缺失场景拿到urg报告后不要一上来就看总的覆盖率百分比。正确的做法是先看-show missing列出的未覆盖点然后按模块分组。通常一个模块的未覆盖点会集中在几个特定的功能区域这些区域往往对应着特定的测试场景。举个例子假设你发现UART模块的tx_fifo_full中断没有被覆盖到。在urg报告里找到这个覆盖点看它的详细信息——是哪个条件没满足是哪个分支没走到。然后回到验证计划里查这个中断对应的测试场景是什么有没有对应的TC。如果没有那就是case缺失如果有那就是case的激励没打到位。这个过程听起来简单但实际操作中最大的坑是很多未覆盖点其实是冗余代码或者不可达代码。比如一些防御性编程的default分支、一些理论上不会同时成立的条件组合。这时候你需要和设计工程师确认这些代码是否真的需要覆盖。如果确认是冗余的可以在覆盖率收集时通过-cm_cond的排除文件把这些点排除掉而不是浪费时间写case去覆盖一个永远不会发生的场景。3.2 用TC级覆盖率差异分析缩小排查范围当你有很多TC时一个高效的技巧是做TC级覆盖率差异分析。具体做法是先用urg生成全量merge后的报告记录未覆盖点列表然后每次排除一个TC重新生成报告看哪些未覆盖点变成了covered。这样就能建立起“TC-覆盖点”的对应关系。不过手动做这个太慢了。更实用的方式是利用urg的-show tests选项它会直接告诉你每个覆盖点被哪些TC覆盖。对于未覆盖的点你可以查看“邻近”已覆盖点是被哪些TC覆盖的然后分析这些TC的激励为什么没有延伸到未覆盖点。比如一个条件覆盖率的分支cond_a cond_b被覆盖了但cond_a !cond_b没被覆盖。你看覆盖了前者的TC发现它只构造了cond_b1的场景。那你就知道需要补一个cond_b0且cond_a1的case。这种精准定位比盲目加case效率高十倍不止。3.3 常见未覆盖原因速查表未覆盖类型常见原因排查方向Line未覆盖冗余代码、防御分支、复位逻辑与设计确认是否可排除Condition未覆盖条件组合缺失、激励不充分检查TC是否覆盖所有条件组合FSM未覆盖状态跳转路径缺失、异常跳转未测检查状态机覆盖图补异常路径Branch未覆盖分支条件未构造、else分支遗漏检查if-else的else分支激励Toggle未覆盖信号未翻转、翻转率低、复位值固定检查信号初始化值和激励序列这张表是我在实际项目中总结的每次覆盖率收敛卡住的时候对着表过一遍基本能定位到80%以上的问题。3.4 实操心得不要忽视复位和初始化阶段的覆盖率很多同行排查覆盖率时只关注正常功能流程忽略了复位和初始化阶段。实际上复位释放的顺序、初始化值的加载、memory的初始化过程这些阶段往往有大量的Toggle和条件覆盖点。如果TC在复位阶段就跳过了某些初始化序列对应的覆盖率就永远打不到。我遇到过一个典型案例一个memory模块的Toggle覆盖率始终差几个bit。排查后发现是memory初始化时某些地址段在特定配置下不会被写入导致对应的数据位永远不会翻转。解决方案是在初始化序列里增加一个全地址段的写入-读取-清零操作专门用于Toggle覆盖。这个case不验证任何功能纯粹为了Toggle收敛但在项目后期非常必要。4. Toggle覆盖率收集优化与实战4.1 Toggle覆盖率的本质与收集机制Toggle覆盖率衡量的是一个信号从0到1和从1到0的翻转情况。VCS在收集Toggle覆盖率时会记录每个信号在每个仿真时间步的翻转事件。这里有一个关键概念Toggle覆盖率是按位bit计算的一个32位总线信号每一位都会独立统计翻转情况。Toggle覆盖率的收集对仿真性能有一定影响尤其是当设计中有大量宽总线时。VCS提供了几种Toggle收集模式-cm_tgl portsonly只收集端口信号的Toggle-cm_tgl mda收集端口和模块内部信号的Toggle-cm_tgl full收集所有信号的Toggle最耗性能在实际项目中建议根据收敛阶段选择不同的模式。项目初期用portsonly快速跑回归项目后期收敛时切换到mda或full做精细排查。4.2 Toggle覆盖率上不去的五大原因原因一信号复位值固定。如果一个信号复位后始终为0且功能上永远不会变成1那它的Toggle覆盖率就是50%只有1到0的翻转没有0到1的翻转。这种情况需要确认信号是否真的不需要翻转如果确认不需要可以在Toggle排除文件中排除。原因二总线高位恒为0。比如一个32位地址总线实际只用了低16位高16位始终为0。这种情况下高16位的Toggle覆盖率永远上不去。解决方案是在验证环境中增加地址高位随机化或者通过配置寄存器让高位参与翻转。原因三时钟门控导致信号不翻转。当某个模块的时钟被门控关闭时模块内部信号不会翻转。如果TC没有覆盖到时钟门控打开的场景对应的Toggle覆盖率就会缺失。原因四多路选择器分支未覆盖。一个MUX的输出信号如果某个输入分支从未被选中输出信号的翻转模式就会缺失。需要补充激励让所有MUX分支都被选中。原因五仿真时间不够。有些信号的翻转需要较长的仿真时间才能触发比如计数器溢出、超时机制等。如果TC的仿真时间太短这些翻转就采集不到。4.3 Toggle排除文件的编写与管理对于确认不需要覆盖的Toggle点可以通过排除文件来过滤。VCS支持在编译或运行阶段通过-cm_tgl的排除文件选项来指定vcs -cm linecondfsmbranchtgl \ -cm_tgl portsonly \ -cm_tgl_exclude ./tgl_exclude.el \ ...排除文件的格式通常是# tgl_exclude.el module_name.signal_name module_name.bus_name[31:16]排除文件的管理需要非常谨慎。我的建议是每一条排除记录都要有对应的注释说明排除原因和确认人。否则项目后期交接时没人知道为什么这些点被排除了可能会被误认为是遗漏。// tgl_exclude.el // 排除原因地址总线高16位在當前配置下固定为0设计确认无需翻转 top.u_dut.addr[31:16] // 确认人张三日期2024-01-15 // 排除原因测试模式信号功能模式下不翻转 top.u_dut.test_mode // 确认人李四日期2024-01-204.4 Toggle覆盖率优化的实操步骤第一步先用portsonly模式跑一轮全量回归拿到端口级的Toggle覆盖率基线。这一步的目的是快速定位哪些模块的端口Toggle覆盖率明显偏低。第二步对覆盖率偏低的模块切换到mda模式重新跑相关TC拿到模块内部信号的Toggle详情。第三步用urg的-show missing生成未覆盖Toggle点列表按信号分组。第四步对每个未覆盖的Toggle点分析原因并归类是激励缺失、还是信号本身不需要翻转、还是仿真时间不够。第五步针对激励缺失的点补充TC针对不需要翻转的点编写排除文件针对仿真时间不够的点延长仿真时间或增加触发条件。第六步重新跑回归验证Toggle覆盖率是否达标。这个流程看起来简单但每一步都有细节。比如第三步生成未覆盖列表时建议用脚本自动解析urg的文本报告提取出未覆盖的Toggle点然后和设计文件做交叉引用自动标注每个Toggle点所在的模块和信号名。这样比手动翻报告快得多。4.5 一个Toggle覆盖率收敛的真实案例之前做过一个DDR控制器模块Toggle覆盖率卡在82%上不去。用urg的-show missing排查后发现未覆盖的Toggle点集中在两个区域一是地址译码逻辑的高位地址线二是数据掩码信号在特定pattern下的翻转。地址译码高位的问题原因是TC的地址范围只覆盖了低4GB空间高位地址线从未被激活。解决方案是在TC中增加高位地址的读写操作即使实际存储空间没有那么大也可以通过地址映射机制让高位地址线参与翻转。数据掩码信号的问题更隐蔽。数据掩码在写操作时控制哪些字节被写入但大部分TC都是全字节写入掩码信号始终为全0。解决方案是增加非对齐写入的TC让掩码信号产生各种组合的翻转。这两个问题解决后Toggle覆盖率从82%提升到了96%。剩下的4%是确认不需要翻转的复位值和测试逻辑通过排除文件处理。5. 常见问题与排查技巧实录5.1 URG报告merge失败或数据缺失这是最常见的问题之一。症状是urg报告里TC数量不对或者某些TC的覆盖率数据明显偏低。原因通常有几个vdb目录被覆盖多个TC同时跑的时候如果-cm_dir指向同一个目录且没有做并发保护后跑的TC会覆盖先跑的数据。解决方案是每个TC用独立的vdb目录最后统一merge。-cm_name重复前面提到过名字重复会导致数据覆盖。仿真异常退出如果仿真过程中crash了覆盖率数据可能没有完整写入。建议在仿真结束后检查vdb目录下是否有对应的TC子目录。排查方法用urg -dir ./cov.vdb -show tests查看TC列表确认TC数量是否和预期一致。如果少了逐个检查每个TC的vdb子目录是否存在。5.2 Toggle覆盖率报告显示100%但实际未覆盖这种情况通常是因为Toggle排除文件写得太宽泛把一些需要覆盖的信号也排除了。或者是因为-cm_tgl模式设置不当比如用了portsonly但报告里显示的是全信号覆盖率。排查方法检查排除文件的内容确认没有误排除。同时确认编译和运行阶段的-cm_tgl模式一致。5.3 同一TC在不同回归中覆盖率不一致这个问题的根源通常是仿真中的随机种子不同导致激励序列不同覆盖到的路径也不同。解决方案是在回归脚本中固定随机种子或者在覆盖率收敛阶段使用定向TC而非随机TC。另一个可能的原因是仿真时间不同。有些TC在回归中被提前终止了导致部分覆盖率数据没采集到。建议在回归脚本中统一仿真时间或者在TC中增加覆盖率采集的结束条件。5.4 如何快速定位某个覆盖点对应的TC用urg的-show tests选项生成报告后在HTML报告中点击任意覆盖点会显示覆盖该点的TC列表。如果某个覆盖点没有被任何TC覆盖报告会标注“Missing”。对于文本报告可以用grep快速搜索grep -A 5 Missing urg_report/urgReport.txt | head -50这个命令会列出前50个未覆盖点及其上下文信息。5.5 避坑指南覆盖率收敛的五个不要不要等到项目后期才开始关注覆盖率。覆盖率收敛是一个持续的过程建议每周跑一次覆盖率回归及时发现未覆盖点。不要盲目加case。每加一个case之前先确认它要覆盖哪个具体的未覆盖点。没有目标的case只会增加回归时间不会提升覆盖率。不要忽视排除文件的管理。排除文件要有版本控制每条排除记录要有注释和确认人。不要用同一个vdb目录跑所有TC。并发仿真时尤其要注意每个TC独立vdb最后统一merge。不要只看总覆盖率百分比。要深入到模块级、信号级找到具体的未覆盖点才能精准收敛。5.6 常用命令速查# 编译阶段收集覆盖率 vcs -cm linecondfsmbranchtgl -cm_dir ./cov.vdb -cm_name tc_name -f filelist.f -o simv # 运行阶段激活覆盖率 ./simv -cm linecondfsmbranchtgl -cm_dir ./cov.vdb -cm_name tc_name # 生成URG报告 urg -dir ./cov.vdb -report ./urg_report -show tests -show missing -format both # 查看TC列表 urg -dir ./cov.vdb -show tests -format text | grep Test # 搜索未覆盖点 grep -B 2 -A 10 Missing ./urg_report/urgReport.txt这些命令是我在日常工作中反复使用的建议保存成脚本或者alias能省不少时间。5.7 关于Toggle rate的补充说明Toggle rate是指信号在单位时间内的翻转次数。有些项目除了要求Toggle覆盖率是否翻转之外还要求Toggle rate达到一定阈值。VCS的urg报告里可以查看每个信号的Toggle rate统计。如果Toggle rate不达标通常是因为激励的翻转频率不够。解决方案是增加高频翻转的激励序列比如在短时间内对同一信号进行多次读写操作。不过要注意Toggle rate过高也可能意味着设计有问题比如信号毛刺需要结合波形确认。6. 从覆盖率数据到验证签核的最后一公里覆盖率收敛到95%以上之后剩下的5%往往是最难啃的骨头。这时候需要做的是逐点确认每个未覆盖点要么补case覆盖要么有明确的排除理由。这个过程需要和设计工程师紧密配合因为很多未覆盖点涉及设计内部的冗余逻辑或不可达路径。我的习惯是做一个覆盖率签核表格列出所有未覆盖点、原因分析、处理方式补case/排除、确认人。这个表格在项目评审时非常有用能清晰展示覆盖率收敛的完整过程。另外覆盖率数据库的版本管理也很重要。每次回归后保留一份vdb快照这样当覆盖率出现异常波动时可以回溯对比。我一般会在回归脚本里加上时间戳把每次回归的vdb和urg报告归档到独立目录。最后分享一个实用技巧如果项目周期紧张可以优先收敛功能覆盖率和代码覆盖率中的Line/ConditionToggle覆盖率放在最后。因为Toggle覆盖率的收敛往往需要额外的定向case耗时较长。但前提是Toggle覆盖率不能太低否则签核时会有风险。具体阈值根据项目要求来定一般建议Toggle覆盖率不低于90%。
返回列表