ARTICLE DETAIL

资讯详情

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

VCS覆盖率实战:URG报告未覆盖TC排查与Toggle收集优化策略

VCS覆盖率实战:URG报告未覆盖TC排查与Toggle收集优化策略 1. 覆盖率报告里那些看不见的盲区是怎么来的做数字验证的同行大概都有过这种体验跑完一轮回归URG报告一打开行覆盖率98%、条件覆盖率95%看着挺漂亮但心里总不踏实——因为你知道那剩下的2%里藏着最要命的东西。尤其是Toggle覆盖率经常出现某个信号翻转次数为零或者某个跨时钟域的信号只翻了一半这种问题在仿真阶段不暴露到了后仿或者硅后就变成偶发性的诡异bug查起来能耗掉你两周时间。这篇内容就是围绕VCS覆盖率实战展开的重点聊两件事一是怎么高效排查那些没有被测试用例TC覆盖到的点二是怎么优化Toggle收集策略让覆盖率数据既有意义又不拖慢仿真速度。适合已经跑过完整回归、正在做覆盖率收敛的验证工程师也适合刚接触VCS覆盖率、想搞清楚URG报告怎么读的入门者。我不会只贴命令而是把每个操作背后的逻辑讲清楚让你知道为什么要这么干以及我踩过哪些坑。先说一个反直觉的结论覆盖率数字高不等于验证充分覆盖率数字低也不一定代表有漏洞。关键在于你收集的覆盖率模型是否合理以及你有没有真正理解那些未覆盖项背后的原因。很多人一看到未覆盖就急着加TC结果加了一堆无效用例仿真时间翻倍覆盖率纹丝不动。问题出在哪儿出在没有先做未覆盖根因分析。2. 从URG报告定位未覆盖TC的完整排查链路2.1 URG报告的正确打开方式VCS跑完仿真后会在simv.vdb目录下生成覆盖率数据库。很多人直接用urg -dir simv.vdb生成HTML报告就完事了但其实URG有很多参数能帮你快速定位问题。我常用的组合是这样的urg -dir simv.vdb -format both -report urgReport -show tests -show ratios这里几个参数的作用需要说清楚-format both同时生成HTML和文本格式文本格式方便用grep搜索HTML适合整体浏览。-show tests在报告里显示每个测试用例对覆盖率的贡献这个非常关键能帮你快速判断是哪个TC覆盖了哪些点。-show ratios显示覆盖率比值而不是简单的百分比有时候比值更能反映问题。生成报告后不要急着看总的覆盖率数字。先打开tests.html按覆盖率贡献排序看看哪些TC贡献最大哪些TC几乎没贡献。我遇到过一种情况某个TC跑了三个小时结果对覆盖率贡献为零原因是它的激励根本没打到DUT的有效路径上。这种TC就是典型的无效用例留着只会浪费回归时间。2.2 用URG的exclude功能缩小排查范围当你面对一个大型SoC项目覆盖率数据库里可能有几十万个覆盖点逐个看根本不现实。这时候要用URG的exclude功能先把已知的、不关心的覆盖点排除掉。urg -dir simv.vdb -exclude exclude_file.el -report urgReport_filteredexclude文件的格式很简单每行一个排除规则# 排除所有时钟门控单元的toggle toggle:top.u_core.u_clk_gating.* # 排除测试逻辑的覆盖点 line:top.u_dft.* # 排除某个已知不用的配置 cond:top.u_cfg.mode[3]这里有个经验exclude文件要版本化管理。我见过团队里有人随手改了exclude文件把一些本该覆盖的点排除了结果覆盖率虚高流片后才发现问题。建议把exclude文件纳入Git管理每次修改都要有review记录。2.3 定位未覆盖TC的三步法当你发现某个覆盖点没有被覆盖时不要急着加TC。按下面三步走第一步确认覆盖点是否合理。有些覆盖点是工具自动生成的可能根本不需要覆盖。比如一个复位信号的toggle如果设计上复位只在初始化时拉一次那toggle覆盖率低是正常的。这时候应该用exclude排除而不是强行加TC去翻转它。第二步确认激励是否到达。用Verdi打开波形找到对应的信号看看仿真期间它有没有被激活过。如果波形里信号根本没动说明激励没打到。这时候要检查你的sequence或者testbench的约束是不是太严了。第三步确认覆盖点是否可达。有些覆盖点在当前配置下就是不可达的比如某个只在特定模式下拉高的信号而你的TC根本没配置那个模式。这时候要么加配置要么用exclude排除。我通常会用这样一个表格来跟踪未覆盖项的处理状态覆盖点类型未覆盖原因处理方式负责人状态top.u_dma.ch_prio[2]toggle激励未打到高优先级通道新增TC张三进行中top.u_cpu.irq_mask[7]toggle该中断源未启用exclude李四已完成top.u_mem.addr[31:28]toggle地址空间未使用exclude王五已完成这个表格看起来简单但能帮你把为什么没覆盖和怎么处理分开避免一上来就盲目加TC。2.4 用覆盖率数据库合并来定位回归盲区VCS支持把多次仿真的覆盖率数据库合并这个功能在排查未覆盖TC时特别有用urg -dir simv1.vdb simv2.vdb simv3.vdb -dbname merged.vdb合并之后你可以看到哪些覆盖点是所有TC都没覆盖的哪些是部分TC覆盖的。我一般会做两次合并一次是全回归的合并一次是只选应该覆盖该模块的TC合并。两次结果的差集就是真正的盲区。这里有个坑合并数据库时要注意仿真配置是否一致。如果两次仿真的编译选项不同比如一次开了assertion一次没开合并后的覆盖率数据可能会失真。建议在Makefile里固定覆盖率编译选项避免人为失误。3. Toggle覆盖率收集的优化策略与参数调优3.1 Toggle覆盖率为什么这么重Toggle覆盖率是VCS覆盖率里最耗资源的一项。原因很简单它要记录每个信号在仿真期间的翻转情况包括上升沿、下降沿、以及是否翻转到0和1。对于一个有几十万信号的设计这个数据量是巨大的。我做过一个对比测试同一个DUT关闭Toggle收集时仿真速度是1.2kHz打开后降到0.8kHz慢了33%。如果再加上条件覆盖率和FSM覆盖率速度可能只有原来的一半。所以Toggle收集必须优化不能无脑全开。3.2 用ntb_random_seed和rad控制Toggle收集范围VCS提供了几个编译和运行时选项来控制Toggle收集# 编译时指定只收集特定层次的toggle vcs -cm_tgl portsonly -cm_tgl_portsonly top.u_coreportsonly的意思是只收集模块端口的toggle不收集内部信号的。这个选项在模块级验证时特别有用因为内部信号的toggle往往可以通过端口推断出来。另一个常用的是rad选项它可以让VCS在运行时动态决定是否收集某个信号的togglesimv rad cm_tglrad的原理是基于活动性分析如果某个信号在仿真期间很少活动VCS会自动降低它的收集优先级。这个选项对仿真速度的提升很明显但要注意它可能会漏掉一些低频但关键的翻转。所以我在做最终覆盖率签核时会关掉rad重新跑一遍确保数据完整。3.3 Toggle rate的合理设置Toggle rate是指信号在单位时间内的翻转次数。VCS允许你设置一个阈值只有超过这个阈值的信号才会被详细记录simv cm_tgl tgl_rate100这个设置的意思是只有翻转次数超过100的信号才记录详细toggle信息。对于低频信号只记录是否翻转不记录翻转次数。这个参数怎么设我的经验是先跑一轮不设阈值的仿真看看toggle rate的分布。如果大部分信号的翻转次数都在1000以上那阈值设100就没问题。如果有些关键信号翻转次数只有个位数那阈值就要调低或者把这些信号加入白名单。3.4 用覆盖率分组来管理Toggle收集大型项目里我建议按功能模块把Toggle覆盖率分组管理。VCS支持在编译时用-cm_hier指定覆盖率层次vcs -cm_hier cm_hier.cfgcm_hier.cfg文件的内容大概是这样tree top.u_core 0 tree top.u_dma 1 tree top.u_periph 1 tree top.u_dft 0这里的0和1表示收集级别0是不收集1是收集。这样你可以把DFT逻辑、测试逻辑的Toggle关掉只收集功能逻辑的既省时间又让报告更干净。我通常会维护两份cm_hier.cfg一份是全收集用于最终签核一份是精简收集用于日常回归。日常回归用精简版速度能快40%左右。4. 那些年我在覆盖率收敛上踩过的坑4.1 坑一覆盖率数据库损坏导致数据丢失这个坑我踩过两次都是因为仿真异常终止比如磁盘满了或者被kill了导致simv.vdb目录损坏。URG打开时报错database corrupted之前跑的几个小时全白费。解决方案在仿真脚本里加一个保护机制每次仿真结束后先检查simv.vdb是否完整再决定是否删除旧的数据库。我现在的做法是# 仿真结束后检查数据库 if [ -d simv.vdb ]; then urg -dir simv.vdb -format text -report /dev/null /dev/null 21 if [ $? -eq 0 ]; then echo Coverage database is valid # 备份到带时间戳的目录 cp -r simv.vdb simv.vdb.$(date %Y%m%d_%H%M%S) else echo Coverage database is corrupted, skipping backup fi fi这个检查虽然多花几秒钟但能避免数据丢失的风险。4.2 坑二exclude文件写错导致覆盖率虚高前面提过exclude文件要版本化这里再补充一个细节exclude文件的通配符要小心使用。我见过有人写了toggle:top.u_core.*本意是排除u_core下某个子模块结果把整个u_core的toggle都排除了覆盖率直接从95%跳到99%但实际上是漏掉了大量未覆盖点。解决方案exclude文件写完后用URG的-show excluded选项检查一下到底排除了哪些点urg -dir simv.vdb -show excluded -report exclude_check这个报告会列出所有被排除的覆盖点你可以逐个确认是否合理。我一般会把这个报告发给模块负责人review确认无误后再纳入正式流程。4.3 坑三Toggle收集导致仿真超时有一次跑一个大型SoC的回归开了全量Toggle收集结果单个TC的仿真时间从2小时涨到6小时整个回归跑了两天还没跑完。后来发现是某个时钟分频器的内部计数器每个周期都在翻转Toggle数据量巨大。解决方案对于这种高频翻转的信号用tgl_rate设置阈值或者直接用cm_hier.cfg把它排除。另外VCS还有一个-cm_tgl_max选项可以限制单个信号的toggle记录条数simv cm_tgl tgl_max10000这个选项的意思是单个信号最多记录10000次翻转超过后只记录统计信息。对于高频信号这个限制能大幅减少数据量。4.4 坑四合并数据库时配置不一致前面提过配置不一致的问题这里展开说一下具体表现。有一次我把模块级验证的数据库和系统级验证的数据库合并结果发现某些覆盖点在模块级是覆盖的在系统级是未覆盖的合并后变成了部分覆盖导致报告看起来很奇怪。根本原因模块级验证时某些配置信号被固定了而系统级验证时这些信号是动态变化的。合并后VCS无法正确判断这些覆盖点的状态。解决方案合并数据库前先确认两次仿真的编译选项、覆盖率模型、exclude文件是否一致。如果不一致要么统一配置后重跑要么分开报告不要强行合并。5. 覆盖率签核前的最后一道检查5.1 用URG的assertion和FSM报告交叉验证覆盖率签核不能只看数字还要看质量。我通常会用URG生成几份交叉报告# 生成assertion覆盖率报告 urg -dir simv.vdb -report assertion_report -show assertion # 生成FSM覆盖率报告 urg -dir simv.vdb -report fsm_report -show fsmAssertion覆盖率能告诉你哪些断言被激活过哪些从未触发。如果一个断言从未触发要么是激励没打到要么是断言写错了。FSM覆盖率能告诉你状态机的所有状态和跳转是否都覆盖了未覆盖的跳转往往是bug的高发区。5.2 用Verdi的覆盖率浏览器做最终确认URG报告是静态的Verdi的覆盖率浏览器可以让你在波形上直接看覆盖情况。我一般会这样做verdi -cov -covdir simv.vdb打开后在覆盖率浏览器里找到未覆盖的点右键选择Trace to WaveformVerdi会自动跳转到对应的信号和时刻。这个功能在排查为什么没覆盖时特别高效比对着报告猜要快得多。5.3 覆盖率签核清单最后分享一个我用了多年的签核清单每次覆盖率收敛到最后一轮时逐项检查检查项检查方法通过标准行覆盖率URG报告95%条件覆盖率URG报告90%Toggle覆盖率URG报告85%FSM覆盖率URG报告100%状态和跳转Assertion覆盖率URG报告100%激活exclude文件review人工确认所有排除项有记录数据库完整性URG打开无报错无corrupted提示配置一致性对比编译选项与签核配置一致这个清单看起来简单但能帮你避免90%的覆盖率签核事故。我见过太多团队在最后一刻发现exclude文件写错了或者数据库损坏了导致签核延期。5.4 一个容易被忽略的细节覆盖率数据的版本管理覆盖率数据库和代码一样需要版本管理。我建议每次签核的覆盖率数据库都打上标签和对应的RTL版本、TC版本关联起来。这样当流片后发现问题时可以回溯到当时的覆盖率数据看看是哪个环节漏掉了。具体做法是在Makefile里加一个目标coverage_tag: echo Tagging coverage database with version $(VERSION) cp -r simv.vdb coverage_$(VERSION)_$(shell date %Y%m%d) echo Coverage database tagged as coverage_$(VERSION)_$(shell date %Y%m%d)这个操作只需要几秒钟但能在关键时刻救你一命。6. 写在最后的一些个人体会覆盖率收敛这件事说到底是一个平衡的艺术。你要在覆盖率数字、仿真时间、验证质量之间找到平衡点。我见过有人为了追求100%的Toggle覆盖率加了无数TC结果仿真时间翻了三倍但真正发现的bug还不如之前多。也见过有人为了省时间把Toggle收集关掉结果流片后才发现一个跨时钟域的握手信号从来没翻转过。我的经验是覆盖率是手段不是目的。URG报告上的数字只是参考真正重要的是你有没有理解每个未覆盖项背后的原因。如果一个未覆盖项你能说清楚为什么不覆盖和为什么不需要覆盖那它就是合理的。如果你说不清楚那就老老实实加TC或者改激励。另外Toggle覆盖率的优化没有银弹。rad、tgl_rate、cm_hier.cfg这些工具都有各自的适用场景你需要根据项目的特点去组合使用。我通常会在项目初期就建立一套覆盖率收集的规范包括编译选项、exclude规则、分组策略然后在整个项目周期里持续优化。这样到了签核阶段就不会手忙脚乱。最后再分享一个小技巧定期用URG的-show tests功能检查每个TC的覆盖率贡献。如果某个TC的贡献长期为零要么是TC写错了要么是它覆盖的功能已经被其他TC覆盖了。及时清理这些无效TC能让你的回归效率提升不少。我在最近一个项目里通过这个方式砍掉了30%的冗余TC回归时间从8小时降到5小时覆盖率数字一点没掉。
返回列表