ARTICLE DETAIL

资讯详情

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

VCS覆盖率分析全流程:从编译选项到Verdi/DVE实操与Merge技巧

VCS覆盖率分析全流程:从编译选项到Verdi/DVE实操与Merge技巧 做数字IC验证的朋友应该都有过这种经历仿真明明跑完了覆盖率报告也出来了打开Verdi或者DVE却不知道从哪儿下手。左边一列数据右边一堆选项点了半天还是没搞清楚“哪一行代码没被覆盖到”到底怎么看。尤其是多用例回归之后怎么把几个test case的覆盖率合在一起很多人还是靠手动拼数字。这篇文章我就把VCS仿真覆盖率分析这条链路完整讲一遍从编译选项到Verdi、DVE的操作路径再到最容易被忽视的merge技巧全部按我平时在项目里实际使用的流程来写照着做基本不会跑偏。适合谁看如果你是刚接触数字IC验证的学生或初级工程师这篇能帮你把“覆盖率”从抽象概念变成可操作的工具链如果你已经跑了一些仿真但一直用单个vdb看数据、不会合并多用例结果那merge这部分建议重点关注哪怕你是老手也可以当一份工具速查偶尔翻一翻省得再去翻文档。1. 覆盖率分析的整体思路先把目标搞清楚再去点工具1.1 代码覆盖率和功能覆盖率别混为一谈先说概念。VCS里常说的覆盖率分成两大类。代码覆盖率Code Coverage是工具自动统计的不需要你写任何额外代码。它关心的是RTL代码在执行仿真时被“踩”了多少Line Cover是哪些行执行到了Condition Cover是条件表达式里的各个分支情况Toggle Cover是信号有没有发生0到1、1到0的变化FSM Cover是状态机的状态和跳转有没有走到还有Assertion Cover统计断言被触发的情况。这些都是VCS通过插桩自动收集的说白了它不管你的设计“该不该”这样走只关心“走没走过”。功能覆盖率Functional Coverage则不一样它是验证工程师用SV的covergroup、coverpoint、cross自己定义出来的描述的是“设计意图有没有被验证到”。比如你要验证FIFO的满和空工具不知道“满”是什么你得在验证环境里写一个coverpoint把fifo_full信号拉高的条件定义出来仿真时VCS才会去统计。很多新人一上来就盯着Line Cover看跑到90%就觉得自己工作干完了。这种想法很危险。代码覆盖率再高只代表代码执行得够多不代表功能点全部被证实过。规范的流程是两者配合功能覆盖率为“验证计划”兜底代码覆盖率帮你在回归里找遗漏。这篇文章讲的VCS和Verdi/DVE工具链就是帮你把这两种数据统一管理起来放在同一个vdb里看。1.2 VCS覆盖率工作流的四个阶段在实操之前先把整个流程在脑子里过一遍。我的习惯是拆成四步第一步是编译在vcs命令里加-cm选项指定这次要收集哪些覆盖率类型。这个阶段工具会在RTL里插桩你觉得哪些模块需要统计覆盖率哪些模块要排除也在这一步通过-cm_hier控制。第二步是仿真跑./simv的时候同样要带-cm选项同时给这次仿真起一个名字比如-cm_name tc1并指定覆盖率数据库目录写到哪里。这一步结束后你会得到一个simv.vdb目录里面就是这次仿真的覆盖率快照。第三步是查看和分析。可以打开Verdi或DVE加载这个vdb一层层往下看代码高亮、条件覆盖明细、FSM跳转、断言统计。也可以直接用urg命令把报告转成文本或网页方便整理到验证计划里。第四步是合并多人多用例的结果。单个test case跑出来的覆盖率通常只有百分之四五十因为不同的用例跑的是不同场景。把所有用例的vdb合并在一起取并集才是最接近真实回归的覆盖率。这一步就是merge也是我见过最多人卡壳的地方。很多教程只讲前三步然后丢给你一句“用urg -dir合并就行”。但实际merge踩的坑不少后面我会详细展开。2. 关键选项与命令-cm是覆盖率分析的灵魂2.1 编译和仿真阶段的核心选项先给出一套我平时最常用的编译命令你可以直接抄vcs -full64 -sverilog \ -cm linecondtglfsmassert \ -cm_hier exclusions.cm \ -f filelist.f \ -o simv这里-cm后面的类型对应五种代码覆盖率line表示行覆盖cond表示条件覆盖tgl表示信号翻转覆盖fsm表示状态机覆盖assert表示断言覆盖。如果你不需要某个类型去掉对应的关键字就好但注意别漏掉关键的。-cm_hier这个选项容易被忽略但它非常实用。实际项目里会有不少模块你并不关心覆盖率比如一些DFT逻辑、模拟宏模型、或者没有验证意义的纯线网逻辑。把这些模块写进exclusions.cm文件里编译时排除掉既能减少插桩开销又能让最终报告聚焦在你真正关心的逻辑上。这个文件格式大概是这样tree { module u_chip.u_uart_top.u_baud_gen } module u_chip.u_sram_128x32第一行按层次路径排除单个实例第二行排除某个模块的所有实例。路径一定要写完整否则工具会报warning然后忽略你写的规则。编译完了跑仿真命令是./simv -cm linecondtglfsmassert \ -cm_name tc_uart_rx \ -cm_dir uart_rx.vdb \ -cm_log uart_rx_cm.log \ -l run_tc_uart_rx.log这里-cm_name给这个用例起个名字建议起得有意义别用test1、test2这种因为后面合并时你要靠这个名字区分覆盖率的来源。-cm_dir指定这个用例的覆盖率数据库目录名。如果不指定默认就是simv.vdb。我强烈建议你每个用例单独指定目录名否则多个用例往同一个vdb里写虽然VCS支持累加但一旦某个用例崩溃或者你不想把它算进最终统计里处理起来很麻烦。2.2 覆盖率数据库simv.vdb的结构和生命周期编译和仿真结束以后你会看到一个以.vdb结尾的目录里面就是覆盖率数据库。有些人不理解为什么叫“数据库”它到底存了什么简单说vdb里保存的是插桩点的执行状态每个行覆盖点有没有被命中、条件表达式里每个子条件的真值组合、每个信号的翻转次数、FSM里每个状态的访问次数、断言触发的次数。这些数据以特定二进制格式组织起来由VCS的覆盖率引擎统一管理和查询。Verdi和DVE其实都是这个vdb的“查看器”它们读取同一个数据源展示方式不同。urg则是这个vdb的“分析器”它能把vdb里的原始数据整理成汇总报告。一个常见误区是以为vdb复制到别的机器或者换个目录就还能用。实际情况是vdb内部记录了不少绝对路径信息换机器或者改路径之后经常打不开或者打开了某个文件找不到。所以我的习惯是如果要把vdb传给同事或者归档先把vdb通过urg重新整理一份再传递。覆盖率数据库的生命周期也要注意。每次跑仿真如果用同一个-cm_dirVCS默认会在原有数据上继续累加而不是清空重来。这个机制在回归时很有用可以分批跑测试用例往同一个库里追加覆盖率。但也容易造成困惑明明这次只跑了一个用例覆盖率怎么比预想的高很多很可能就是累加了上一轮的数据。需要干净数据时一定要先把旧的vdb目录删掉。3. Verdi与DVE实操从打开vdb到看懂报告3.1 用Verdi打开覆盖率数据Verdi是目前大部分数字IC项目的主力调试工具。它的界面相对现代源码高亮和波形联动体验都不错。打开覆盖率数据的基本命令是verdi -cov -dir uart_rx.vdb 如果同时需要加载波形做分析可以加一个-fsdb参数verdi -cov -dir uart_rx.vdb -ssf uart_rx.fsdb 打开之后界面左侧通常会出现“Coverage”相关的窗口按设计层次列出各个模块。你选中一个模块覆盖率数据会按Line、Condition、Toggle、FSM、Assert等类型分好。双击进入源码视图后能看到行号区域有颜色标记绿色表示这一行已经覆盖红色表示从未覆盖棕黄色表示部分覆盖。刚开始用Verdi的人最容易懵的是“Condition”这一列。它统计的不是简单的一行代码有没有执行而是条件表达式内部的子条件组合。比如这一行代码if (a b) ...在Verdi里点开这条语句你会看到a和b各自的真值组合都有没有被跑到。有时候Line Cover显示这一行是绿色的但Condition Cover显示只有50%原因就是a1且b1的组合从来没出现过。这正是代码覆盖率比“代码有没有执行”更精细的地方。FSM覆盖在Verdi里的展示也很有用。选中一个状态机模块Verdi会把状态转移图列出来每个状态和每条跳转都有一个命中标记。状态跳转没覆盖到说明那个跳转条件对应的场景从未发生这是写用例时最值得关注的信息。工具栏里还有不少过滤和分组功能。比如只看未覆盖点、按照覆盖率排序、把多个vdb同时加进来对比。文件名、行号、覆盖率百分比这些信息都可以直接导出成表格方便你贴在验证报告的幻灯片里。我自己的习惯是每次回归结束都会导出一份未覆盖点清单按模块发给对应的设计工程师逐条确认哪些是测试用例遗漏哪些是冗余代码本来就不会走到效率比在会上翻界面高太多。3.2 用DVE查看覆盖率老工具并不差DVE是VCS早期的集成GUI环境现在新项目用得少了但老项目、公司统一环境里依然大量存在。命令同样很直接dve -cov -dir uart_rx.vdb 打开之后DVE会把当前库里所有覆盖率类型汇总展示。左侧是层次树右侧是每种类型的覆盖率百分比表格。你可以点开任意模块一层层下钻最后看到具体某一行、某个信号的覆盖状态。相比VerdiDVE的界面确实老旧源码高亮不够漂亮刷新速度也没那么快。但它的优势是轻量启动快而且有些老版本的VCS安装包默认只带DVE在那种环境下你唯一能用的图形工具就是它。另一个实用点是DVE的“group”功能可以把多个覆盖率指标组合到一个视图里对比这个在查某个功能点是否真正覆盖全时挺好用。如果你要在DVE里同时看波形和覆盖率命令是dve -vpd uart_rx.vpd DVE支持VPD格式波形这个和Verdi的FSDB是两套系统。很多团队在VCS里默认dump VPD然后在DVE里一起开也算是一条成熟的老验证流程。Verdi和DVE的选择我的建议很简单如果项目里两种工具都装了优先Verdi看源码高亮比DVE舒服太多如果公司环境固定用DVE也没必要强求换工具覆盖率数据是同一份vdb两种工具展示的统计结果完全一样不会因为查看器不同而出现数值偏差。3.3 解析urg报告命令行看覆盖率才是日常用GUI工具查看覆盖率适合做详细定位分析但要快速评估“今天回归覆盖率怎么样”我都是直接跑urg让它生成一份报告。基本用法urg -dir uart_rx.vdb -format text这条命令会读取uart_rx.vdb在当前目录下生成一个urgReport文件夹里面是文本形式的覆盖率汇总。想输出网页版加-format html在我看过的很多项目里html版本用得最多因为可以直接在浏览器里打开按模块排序看薄弱点还可以把不同的测试用例对比视图拉出来。urg报告的核心指标大概包括Total Coverage总覆盖率通常按类型分开统计Line / Condition / Toggle / FSM 各自的数值每个模块的覆盖率详情按层次树展示未覆盖点的列表按文件路径和行号列出如果你想把报告里某个模块的数据再细分还可以用-gt选项按覆盖类型分组或者用-hier把层次树展开得更深。VCS的urg其实还支持一个很好用的-group选项能把多个用例按自定义分组统计在回归报告里非常直观。结合我自己的使用习惯urg报告生成之后我会先用脚本把未覆盖点按文件汇总看看集中在哪些功能块再去Verdi里重点打开这些文件定位原因。命令行批量处理加上GUI精准定位这套组合比纯点界面高效得多。4. Merge技巧多用例覆盖率合并以及统计口径的坑4.1 什么时候必须merge什么时候小心merge先回答一个很实际的问题回归跑了几百上千个用例难道要把所有vdb都合并在一起吗不一定。merge的核心目的是取得所有已验证场景的覆盖全集。如果你每个用例是单独目录存的vdb那最终必须经历一次merge才能回答“我们这次回归总共覆盖了多少”这个问题。merge的方式也有讲究很多团队的做法是分层合并功能验证阶段把同一功能模块的用例合并成一份再跨模块合并。这样如果某个模块的覆盖率不达标可以直接定位到该模块下的哪些用例组合不足不需要从总库里反向拆。但这里有个很容易踩的坑merge虽然默认是取并集但不同覆盖率类型的合并逻辑并不完全一样。行覆盖、条件覆盖、信号翻转这些都是“或”的关系只要任何一个用例覆盖到了合并后就算覆盖FSM覆盖也类似。功能覆盖率则不一样特别是带cross的covergroup合并时往往会出现某些组合丢失或者统计口径变化的情况尤其当不同用例使用不同的covergroup实例时。所以我把功能覆盖率合并单独说一下如果你在环境里用到了covergroup的crossmerge前最好先确认所有要合并的用例用的是同一套covergroup定义否则每个用例的bin集合都不同合并出来的数据很容易失真。遇到这种情况我一般会保留功能覆盖率的原始vdb用Verdi或uur单独查看而不是盲目merge进总库。4.2 命令行merge的完整流程上代码假设你跑完三个用例生成了三个vdb目录uart_rx.vdbuart_tx.vdbuart_cfg.vdb合并的命令urg -dir uart_rx.vdb uart_tx.vdb uart_cfg.vdb -dbname uart_all.vdb-dbname指定合并后输出到哪个新目录。这一步会在当前目录生成uart_all.vdb同时生成一份默认的urgReport。合并完成后你可以用任何工具查看这个库verdi -cov -dir uart_all.vdb 也可以用urg再生成合并库的报告urg -dir uart_all.vdb -format text如果用例很多命令行里写一长串-dir很痛苦。建议用通配符或者把目录列表写进一个文件urg -dir ./*.vdb -dbname all.vdb注意通配符展开后如果包含不符合预期的目录urg会直接报错所以建议先ls确认。关于merge还有两个非常实用的小技巧。第一每个用例仿真时最好都带-cm_name。这个参数不只起到“命名”的作用它会在vdb里记录这个数据来自哪一个用例merge之后你可以反向查“总覆盖率里各用例贡献了多少”这在回归分析和覆盖率补充分配时非常有用。实际上VCS的方案也支持在merge时指定一个用例的vdb并保留原有名称用好这个特性等于给自己留了一条追溯路径。第二merge时可能遇到某个vdb格式不对或版本不兼容的情况。一个稳妥的保险手段是merge之前先对每个vdb单独跑一次urg确认都能正常生成报告再做合并。这样万一merge报错你能很快定位到是哪份数据出了问题。4.3 merge过程中易踩的坑先列一个我真实踩过的不同编译选项产生的vdb合并urg大概率会警告甚至拒绝。举个例子你第一次编译时用了-cm linecond后来又改成-cm linecondtgl跑出来的vdb虽然都是vdb但内部记录的数据维度不一致。merge的时候urg会提示发现不完整的覆盖率数据或者直接忽略某个类型的覆盖。最稳妥的做法是项目从一开始就统一编译选项命令行、Makefile里的-cm参数保持完全一致。还有一个坑是绝对路径问题。如果你的vdb是通过仿真机A生成的之后把vdb传到本地工作站用Verdi打开有时候会出现打不开或者源码定位失败的情况。前面提过vdb内部存了文件路径信息尤其是在source code路径信息上换机器后原路径不存在了工具就找不到原始RTL。解决方法是迁移vdb时同时把RTL放到相同相对路径下或者用urg -dir xxx -dbname new.vdb重新打包一份让内部路径信息更新为当前环境再打开。最后一个坑也是很多人都问过的为什么我merge完之后某些测试用例的覆盖率反而“吵架”了比如tc1里某个fsm状态是覆盖的tc2里没覆盖merge后理论上应该显示覆盖。但在Verdi里一看还是红的。这种情况多半和覆盖率的“事务”隔离有关。某些用例仿真时崩溃或者提前终止vdb里可能只存了部分数据merge时这部分数据被当作“未覆盖”处理。解决办法是检查每个用例仿真结束时有没有正常生成vdb、有没有写cm_log。我的习惯是每次仿真完都看一眼最后的coverage summary确认数据完整再做merge别一股脑跑完就合。4.4 什么时候用GUI merge什么时候用命令行Verdi的GUI里也提供了merge功能路径大致在Tools - Coverage - Merge。操作方式是把多个vdb文件拖进窗口然后执行合并。GUI的优点是直观适合临时合并两三个vdb看一眼或者你想在merge过程中手动勾选哪些用例要加进来。但如果是日常回归、几十上百个vdb的合并GUI就不合适了。一方面路径拖拽容易出错另一方面GUI merge的过程缺少可脚本化、可复现性。回归脚本里我都是写死urg命令来合并每次回归完自动执行这样连报告生成、邮件通知都可以串成一条自动化流水线。一句话总结临时看用GUI回归归档用命令行。两条路线都掌握覆盖率分析才算是真的顺手。5. 常见问题与排障实录5.1 编译报了-cm相关错误怎么办很多新手的第一个问题是vcs编译时加-cm结果报了一堆不认识的信息比如某些模块没有插桩、某个语法在插桩后不兼容。最常见的原因是不同VCS版本对SystemVerilog语法的支持程度不同。像covergroup里面用了较新的关键字或者interface里写了比较复杂的clocking block插桩后某些旧版本VCS解析不了。遇到这种情况可以先不加-cm把编译跑通确认RTL本身没问题然后逐步加回-cm定位是哪个文件引入了冲突。这个办法虽然笨但很有效。另外一个常被忽略的点是如果用了第三方IP或者加密RTL插桩可能会被禁止。对于加密模块VCS一般不会插入覆盖率探针编译时会打印warning这不是错误但你要知道最终报告里这个模块的覆盖率数据不会出现别到时候对着缺失的IP模块数据反复排查。5.2 GUI打不开vdb或者打开后一片空白我在给同事培训时遇到过最多的问题就是Verdi或DVE打不开vdb。第一步先确认路径。当前工作目录和vdb所在目录是不是一致如果vdb的路径是相对路径比如./u1/simv.vdb那在别的目录启动工具时得用-dir指定完整路径不能指望工具自动找到。第二步确认工具版本。VCS编译和仿真产生了vdb然后用一个不兼容版本的Verdi去打开大概率打不开或者报格式错误。团队里如果大家用的不是同一套工具版本vdb文件最好不要在不同版本间来回拷贝。一致性最好的保障是让所有仿真、查看、merge都在同一版本工具的容器或模块环境里完成。第三步检查vdb目录完整性。VCS在仿真结束时会做收尾操作如果仿真中途被杀掉比如服务器负载太高导致任务OOMvdb可能没有写完。这种情况下打开工具看到的覆盖率数据是不完整的.处理方式是重新跑这个用例或者检查cm_log确认仿真流程是否正常结束。我强烈建议在仿真脚本里加一段检查判断vdb目录是否生成、cm_log里有没有error这样能提前把坏数据拦下来而不是等到最后merge才发现某个vdb是残的。5.3 覆盖率始终是0先别怀疑工具这是个特别经典的场景跑了仿真打开Verdi一看所有覆盖率指标都是0。99%的情况不是工具坏了而是你编译时没加-cm或者仿真时没加-cm。必须两个阶段同时加缺一个都不行。编译阶段不加就没有插桩逻辑仿真阶段不加即使编译时插桩了也不会真正记录和落盘。VCS和Verdi的联合使用中还有一个常见问题如果你在跑仿真时没有加-debug_access比如Verdi所需的选项导致没法拉FSDB波形很多人会误以为“覆盖率也没生效了”其实两者没有直接关系。覆盖率数据写在vdb里波形数据写在fsdb或vpd里是两个独立的输出。建议分别确认cm_log里有没有summary、有没有生成fsdb波形文件这两件事独立判断互不干扰。5.4 后仿时序仿真中的memory初始化问题很多人跑后仿时会给memory做初始化这个和覆盖率还真有关系。如果你的设计里带大块SRAM后仿真开始时memory内容是未知态X。开启toggle覆盖率统计后X态或复位初值会导致信号在0、1、X之间大量翻转这种“无意义覆盖”会对toggle指标造成虚高严重污染报告。我在项目里遇到过某模块toggle覆盖率莫名冲到99%的情况查了几天才发现是memory初始化没做好一复位整个RAM区域在仿真器里疯狂翻转。解决办法是后仿前的初始化步骤必须严格设计。用系统函数或force文件把memory预置成已知值同时仿真约束文件里把异步复位时序处理干净。这个操作不复杂但少了它覆盖率数据完全是假的而且会让你在debug时浪费大量时间。5.5 排障速查表现象可能原因处理思路编译报不支持-cmVCS版本太老或license不全确认license包含覆盖率功能升级工具版本仿真没有vdb目录仿真阶段没加-cm检查./simv命令行vdb存在但Verdi打不开路径不对或工具版本不匹配用-dir指定完整路径兼容版本工具打开覆盖率数据为0编译或仿真缺-cm两个阶段都要加toggle覆盖率高得离谱memory未初始化/复位X态翻转检查后仿初始化流程merge时总有一个vdb报错该用例仿真中断或数据不完整单独urg确认重新跑该用例merge后某些点消失不同编译选项或路径迁移问题统一编译选项用urg重新打包vdb最后分享一个我的个人习惯每次做覆盖率分析时心里一定要有一个“覆盖率贡献图”的念头——每个用例为什么存在它补的是哪块覆盖盲区。一份好的merge报告不只是告诉你“总覆盖率80%”更重要的是告诉你“剩下的20%哪些模块、哪些类型、哪些分支缺覆盖应该再设计什么场景去补”。覆盖率分析本质不是一个点开工具看数字的动作而是一条从回归规划、数据管理到报告解读的完整链路。把VCS、Verdi、DVE这套工具用熟再把merge这个环节做规范你会发现覆盖率报告从“一堆看不懂的数字”变成“指导下一步验证计划的路书”。希望这篇对你有所帮助。
返回列表