前面我们探讨了接到验证任务后的行动以及前期如何进行高效的学习,当有了对验证对象的充分理解和学习之后,我们就可以进行验证feature(即验证的测试点)的提取了。
凡事预则立,不预则废,众所周知,验证feature文档决定验证的内容、侧重点、质量,是验证工程师最重要的文档和指导工具。
本文的侧重点不在于大而全的探讨诸如”不同类型的验证对象哪些点可以作为验证feature”等内容(以后在别的文章中有机会再讨论),而是继续遵循“高效”的主题,一起探讨如何又快又好的梳理验证测试点这个文档?怎样在验证过程中充分使用这个文档?
杰瑞IC验证给出一种答案,围绕一个口诀来作为今天探讨的线索和综述:
“先粗再细、先全再剃、不断迭代、定期反思”
1
先粗再细
对于验证feature来说什么叫粗?什么叫细?
我们举个简单的例子,如一条验证feature可以这样写:
“需要覆盖中断功能的测试。”
也可以把这一条验证feature细化成多条验证feature,这样写:
“覆盖不同中断信号使能打开、关闭测试”
“覆盖中断正常清除测试”
“覆盖延迟清除中断测试”
“覆盖不同中断来源的中断测试”
“覆盖中断有效后相关中断状态寄存器正确性检查”
“覆盖中断不同来源同时有效的优先级测试”
“覆盖多中断次数测试场景”
……
当然,还可以写的更细致:
例如上面“覆盖不同中断信号使能打开、关闭测试”可以继续分解:
“覆盖不同中断信号随机打开关闭以及不同信号间的交叉场景”
“覆盖中断信号使能全关闭,通过轮询寄存器方式处理中断场景”
……
例如“覆盖延迟清除中断测试”可以继续分解:
“覆盖延迟清中断,延迟时间小范围随机”
“覆盖延迟清中断,延迟时间等到下一个中断来之后再清除”
……
我们不再继续细化赘述,相信大家从举例中已经有点感觉了,什么叫“粗”,什么叫“细”,这里说到的粗细,其实就是指的是验证feature的颗粒度。
杰瑞IC验证认为,一个好的验证feature文档,一定是全面且颗粒度很细的文档。只有颗粒度很细,借助这个验证feature文档才能更好的帮助你把需要覆盖的测试点思考清楚,更好的衡量你的验证工作量制定验证计划、更好的帮你构造定向或随机case和编写功能覆盖率代码、更好的保证你的验证完备性。
可想而知,如果你只写一句这么“博大精深”的验证feature:“需要覆盖中断功能的测试。”,你看到这条验证feature也许很难会想到还需要:“覆盖延迟清中断,延迟时间等到下一个中断来之后再清除” 这种测试场景,这样就有可能会埋下风险。
我们回到“高效战斗”的主题,怎么又好又快的把这个文档搞定呢?
从高效的角度杰瑞IC验证建议一定要“先粗再细”。
一方面:
“粗”可以让我们站在一个宏观的角度,不漏掉大的功能点,例如先涵盖各种需求点、各种设计文档核心功能点、应用场景、性能点、功耗测试点、压力测试点、注错点等等
另一方面:
我们是不可能一蹴而就的。如果一开始就钻进某一个点,把某个功能的所有细节验证feature写清楚再写别的,效率显然会低于先写的粗一点,再多轮迭代进行细化。正如前面的举例,每一次的细化都在上一轮细化的思考基础之上进行的,这样也会想的更清楚全面。
2
先全再剃
通过刚才讲的先粗略提取再不断细化的方式,相信大家可以高效提取出来一个比较全面的验证feature文档。
前面我们提到:“一个好的验证feature文档,一定是全面且颗粒度很细的文档。”但是仅仅的全面和颗粒度小,就可以叫一个好的验证feature文档吗??
答案是否定的,全面和颗粒度小,只是提取验证feature的第一步。如果说第一步细化是做加法,第二步更为重要和有难度,那就是做减法。就像本节的小标题“先全再剃”,这里的“剃”,讲的就是“剃刀原则”的“剃”,关注的是验证的执行层面,“剃”就是学会取舍,就是抓验证重点和主要矛盾,就是高效的体现。
(1)“剃”,删除掉不必要的验证feature。
有时候,我们需要删除和精简一些没有必要的验证feature。
最简单的例如,对于已经多次流片实践验证稳定的ip,没有必要覆盖非常细致的验证feature,这部分完全可以舍去不验证。
再举一个例子:如针对某个参数我们通过确定边界值、典型值、划分等价类等方式进行验证feature细化:
“A参数取值[0:1000],需要覆盖边界值0,1000,典型值200、500、600、900……(例如100个),随机覆盖a模式[0:200),b模式[200:700),c模式[700:1000]”
“B参数取值[0:8880],需要覆盖边界值0,8880,典型值200、500、600、900……(例如300个),随机覆盖a模式[0:1000),b模式[1000:300),c模式[3000:8880]”
……
这样的参数有20个,然后有一条:
“需要覆盖这20个参数取值的所有交叉场景”
这个“交叉场景”是很全面了(当然你如果想“修身养性”可以用一整天时间进一步具体细化出来怎么交叉的)。但是这条有意义吗?
对于EDA仿真验证来说,这条可以说是没有意义的,因为这个需要覆盖的验证空间太大了,大到不能执行,即使你通过脚本交叉参数一键生成批量case,这么大的case量大概率不能在有限的时间跑完,就算能跑完,这样的参数交叉测试是否真的有意义,是否在浪费测试时间?我们有这样的时间,放在更重要的测试点上努力是否更有价值?
所以,对于这样的验证feature我们一定要做以权衡。是否可以通过深入分析实际应用场景和设计思路,精简这些验证feature,是不是哪些点可以删除?是不是哪些点不需要交叉覆盖?当然也可以思考是不是我们可以尝试启用形式验证工具?
(2)“剃”,给验证feature选择一个更好的归宿。
举一个例子,有这样一条验证feature:“需要覆盖连续不间断运行10000次场景的压力测试”。
这条验证feature考虑的没有问题,颗粒度很细,需求也很明确。但是对于EDA验证来说,又是一个不可能完成的任务,这么一个case可能跑几个月都结束不了。对于这样的验证feature,不需要从文档中删除,因为FPGA测试是可以办到的,这种情况可以增加备注,指明在FPGA测试的时候进行覆盖,并且负责跟踪这个点是否在FPGA验证计划中列出以及测试时候是否确实落实。
同理,例如有的验证feature可能不适合在单元级验证时候测试,适合在更高层次的验证阶段中测试,都可以像上面的例子给验证feature一个更好的测试“归宿”,用最适合的方式覆盖,从而提高项目总体的验证效率。当然了,给验证feature更好的归宿前提是需要验证者了解和把握验证的不同验证阶段以及不同验证层次的侧重点和优劣势,有一个验证的全局观念。
(3) “剃”,给验证feature刮骨,设置不同的优先级。
有这么两条验证feature:
“需要覆盖中断功能的测试”
“覆盖用于debug的状态寄存器”
很明显,第一个验证feature是核心功能,第二条重要程度远远不如第一条。如果我们的验证时间有限,那我们至少要通过完备的激励和检查机制保证第一条核心功能,而不是先编写大量的checker去自动化检查各种debug状态寄存器。
也就是说,不同的验证feature含金量和优先级也是不一样的,我们在提取验证feature的时候,要想清楚和标注不同验证feature的优先级。
3
不断迭代
验证feature列表在验证开始前就是写好固定死了不能变的吗?
不是的,验证feature文档是动态变化迭代的。
在正式验证开展之前,我们会出一个当时认为最完善的版本,但是在验证过程中我们还是要定期迭代我们的验证feature文档,例如:
当需求和设计的变更,我们需要相应的修改和增删验证feature;
当功能应用场景、典型参数增加或改变时,及时增加验证feature;
性能功耗的场景验证feature也可能常常需要修改文档;
随着验证过程中对设计理解更加深入,也需要及时的记录和补充细化验证feature。
4
定期反思
验证feature需要定期反思,有两层含义,一方面是对已有验证feature的不断反思,其实类似于上面说的迭代,定期反思之前提取出的验证feature是否合理或有缺少,这里不过多解释;另一方面,是要利用好我们的验证feature文档,定期反思验证进度和质量。
a. 依据我们的验证feature列表和优先级等信息来制定我们的验证计划,并且不断的修改更正我们的验证计划。
b. 定期的把测试用例与验证feature列表做一个对应和反标,心里清楚哪些验证feature已经有case覆盖住了,哪些还没有,在验证项目最后要保证所有验证feature都有定向或随机case可以对应。
c. 功能覆盖率覆盖点的规划和收集工作,也需要定期利用验证feature文档进行规划和反思,确定哪些点是一定需要写功能覆盖率收集代码的,也是验证完备性和质量的保证。