什么是做覆盖率?要回答这个问题需要知道 IC 验证的目的。最终目的是保证 IC 所有的功能都符合我们的期望。通过和 reference model 比较我们能够知道 IC 的功能是否符合我们的期望,但是如何体现“所有” ?只能从覆盖率上进行体现。
只有当所有代码都被执行过时,中间的功能都符合我们的期望,我们才能够说达到了目的。我们需要知道 IC 的所有功能都是正确的,而不是一部分功能或者是大部分功能都是正确的,这就做覆盖率的意义之一。
覆盖率能够体现我们目前的 case 跑过了多少代码?还有哪些代码没有跑到,在做后面的 case 时,就可以有意识的往没有覆盖到的方向去倾斜,这就是做覆盖率的意义之二。
总之,代码覆盖率检查测试平台和测试用例到底执行了多少目标代码。另外,覆盖率也体现了 IC 验证工程师的工作量。
单元验证阶段,关心的是模块功能和模块质量,一般业内常用的出口条件是:行覆盖率达到 100%,分支覆盖率达到 100%,条件覆盖率达到100%,状态机覆盖率达到 100%,对没有覆盖率的情况给出合理的说明。
集成验证阶段,关心系统的功能以及模块与模块之间的接口,此时出口条件为功能覆盖率。一般业内常用的出口条件是:功能覆盖率达到 95%,对没有覆盖的情况给出合理的说明。
代码覆盖率
代码覆盖率是从软件编程的角度来分析设计代码是否被充分的验证。一般的仿真器能够在仿真的过程中自动统计覆盖率数据。代码覆盖率仅仅能够表明设计中那些代码已经测试,而不能表明测试是否正确, 以及测试是否完善。**测试工程师通过分析覆盖率情况了解目前哪些代码被执行到了,哪些没有被执行到(这些报告在仿真软件中可以输出,很直观), 而后调整测试例,保证代码尽可被全面的测试。代码覆盖率可以通过以下几个角度去统计。
a. 语句覆盖(StatementCoverage)
语句覆盖率(statement coverage):又称行覆盖(LineCoverage), 这个概念是指在仿真的过程中被执行语句所占的百分比。一个语句没有被执行到则肯定没有被检验过,因此我们规定在一个验证的过程中,语句覆盖率必需要达到 100%。语句覆盖率是对 RTL 代码中的语句是否执行过进行统计。其是常用工具中支持的最基本的覆盖形式。几乎所有的测试都能实现 100%的语句覆盖率, 因此被认为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。
语句覆盖 100%不代表着覆盖到所有的分支情况,不代表没有异常情况发生。因为每一条语句都有很多种执行情况,我们设计的 case 只跑过了最普通的一种情况。我们看一个最简单的例子。
int div(int a, int b) begin
return (a/b);
end
设置任何一个测试例,都可以达到 100%的覆盖率。但是当 b=0 时,就会出
现bug。因此用语句覆盖率衡量验证是否完成是不靠谱的。
b. 分支覆盖(BranchCoverage)
每一个条件语句“if/ else”和“case”语句的执行情况。又称判定覆盖,其 是统计各个分支是否被执行到。
c. 条件覆盖(Condition Coverage)
分析在“if”的决定,三元语句被认为是一个扩展的分支覆盖。条件覆盖是统计 if 语句中每个子表达式正确和错误的结果是否被执行到。而不考虑各个分支是否执行到。分支覆盖和条件覆盖是对分支语句的不同方面进行统计,下面举个例子详细说明。
if (a < 10 || b < 10) // 判定
return 0; // 分支一
else
return 1; // 分支二
当进行分支覆盖时, 我们设计 case 只需要覆盖到分支一和分支二两种情况就可以,即只要 a 和 b 的值满足最终执行到两个 return 就可以。而进行条件覆盖时,我们设计 case 要考虑到(a<0)和(b<10)这两个语句的真假值,只有这两个语句的真假值都覆盖到了,才说明条件覆盖完备了。
同时需要注意,条件覆盖不是将判定中的每个表达式的结果进行排列组合,而是只要每个表达式的结果都测试到就可以。
d. 表达式覆盖(Expression Coverage)
分析赋值语句右边表达式的活动情况,当表达式被执行时进行统计。对涉及逻辑运算符的表达式,将会建立真值表,对应真值表中的条件匹配行进行计数。
e. FSM 覆盖
又称有限状态机覆盖,对在一个有限状态机中的状态、转化和路径计数。下面这些因素将会被收集:
1. 状态覆盖向量:有限状态机在仿真期间有多少状态已经达到。
2. 转换覆盖向量:状态机仿真中多少转换已经被执行。
3. 多态转换覆盖:在状态机仿真中追踪许多可能被执行的转换序列。这也被称为 sequence coverage。
功能覆盖率
将待测模块的功能点提取出来,分功能进行测试,当所有的功能点都测完时,就验证了测试的完备性、充分性。
功能覆盖率更能体现 IC 验证的目的,即确保待测模块的实现功能, 比代码覆盖率更接近验证目标。
为了确保验证的充分性, 建议在验证过程中采用功能覆盖率和代码覆盖率结合的方式。当出现功能覆盖率高、代码覆盖率低的情况时,说明验证计划不充分,需要增加功能覆盖点。当代码覆盖率高而功能覆盖率低时,设计没有实现指定的功能。
我对于功能覆盖率的一点心得:即根据模块待测的的功能点来生成对应的测试用例,然后跑代码覆盖率。首先要保证所有的功能点全部跑完,这样代码覆盖率也就八九不离十了。但是在梳理功能点时需要注意以下几个问题:
1.功能点也分为大功能点和小功能点,同时大功能点中有可能会嵌套有小功能点。代码覆盖率达不到预期效果的原因之一有可能是大功能点的部分小功能点未能覆盖到。
2.功能点分为正常功能点和异常功能点,大部分的开发人员比较重视正常功能点,而往往忽略异常功能点的梳理。
3.功能点分为基本功能点和扩展功能点,基本功能点用于测试模块基本的功能,而扩展功能点用于测试模块较为复杂的功能, 只有基本功能点测试正确之后,才能开始测试扩展功能点。
上述三点要求代码开发人员尽可能的完善测试功能点,并将功能点归类。
作者:验证哥布林
原文链接:https://mp.weixin.qq.com/s/0-bYN6dgvEWAqjx54xkt5w
微信公众号:
推荐阅读
更多IC设计技术干货请关注IC设计技术专栏