在展开设计之前,设计人员和验证人员都会阅读功能描述文档,以理解设计的各项功能为前提,来考虑如何验证它。如果功能描述本身不清晰,则需要同系统人员沟通来修改功能描述文档;如果设计和验证双方人员对于某一项功能理解有不同的地方,也需要最后同系统人员的解释保持统一;
一旦完成了验证计划书,还需要对其进行修改吗?答案是需要。因为在实际项目执行过程中,功能描述文档和设计会不断更新,直到芯片到流片前都有可能在一直进行,那么验证人员就需要做好相应的验证计划更新。所以,验证计划的生命在设计被构建之前就诞生了,伴随着设计的周期,直到流片;
伴随着验证计划的创建,验证流程可以分为若干个步骤,它们包括:
- 创建验证计划
- 选择验证方法
- 人力资源调配
- 构建验证平台和环境组件
- 开发测试用例
创建一份验证计划是首要的任务,通过收集下列材料可以更好地组织出有价值的计划:
- 结构功能描述
- 设计的各种操作使用模式
- 在正常输入和错误输入情形下设计的行为
- 设计的接口
- 在一些边界情况下设计的行为
- 设计在现实中使用的场景描述
从更宽泛的意义上来看,一份验证计划几乎可以囊括所以跟验证相关的东西,这其中不单单包括要验证的设计功能,还包括验证方法、人力安排、进度评估等等。由于验证计划的生命期很长,在实际环境中,有很多因素会不断影响计划的更新,这些可能的因素包括:
- 会有不同人员更新验证计划。一份充分的验证计划,需要系统、设计、验证、软件人员给出意见,共同参与制定。
- 需要更新上百上千的测试用例,并且与计划中的待测功能映射。
- 考虑选择不同的验证方法,如果有多种方法并用还需要使得它们之间保持兼容和跨越式的复用。针对不同的设计,需要考虑选择动态仿真、形式验证或者硬件加速方法,如果采用两种以上的方法,还需要考虑如何实现技术平台上的跨越复用。
- 如果有新的设计要求,需要更新计划,同时设法对人力和进度的影响降低到最小。在设计的过程中,设计人员仍然会收到新的功能需求,那么一旦确定下来添加新的功能,就需要考虑额外的人力和对于进度的影响。
- 如果有多个组参与验证,需要考虑如何协调。对于大型的SoC项目,一般会有多个功能组参与,甚至他们会在不同的城市办公,这时候去协调组跟组之间的工作,并综合出整体进度结果就很重要了
计划的内容
在制定验证计划的具体过程中,我们会将技术部分和项目部分都考虑进来。从技术角度而言,我们需要考虑的有验证的功能点、验证的层次、测试用例、验证方法和覆盖率要求,从项目部分来看,我们也需要考虑使用的工具、人力安排、进度安排和风险评估。接下来,我们逐个分析技术部分和项目部分。
技术部分
验证的功能
需要验证的功能点主来自于功能描述文档,设计和验证人员在阅读文档的过程中,会将设计的功能、参数、性能从自然语言拆分转化为一个个可以单独验证的功能点,并且需要用定性定量的语言限定描述这些功能。
我们可以将功能点按照优先级分为:
- 基本功能:通常包括时钟、电源、复位、寄存器访问和基本特性,这些可以在模块级完成验证
- 互动功能:一些需要同其它模块互动的特性,需要在更高层次的子系统级或者芯片级完成验证
- 次要功能:通常这些功能没有要求必须在流片之前完成验证,例如性能验证、效能验证。它们没有通过验证,并不会造成芯片的功能错误
验证的层次
结合验证的功能点,需要清楚该功能点是否可以在较低的层次完成验证。从验证效率和激励自由度来看,我们应该尽量在较低的层次验证更多的功能点。在较高的层次,例如芯片级,应该侧重于系统集成测试;
验证方法
需要考虑采取何种验证方法,动态仿真、形式验证还是硬件加速?采取什么样的透明度,黑盒、白盒还是灰盒?采用直接测试还是随机约束激励?在之前的验证方法篇中,我们对比了不同方法适用的场景;
测试用例
有了带验证的目标功能,选择合适的层次和方法,在完成了验证平台搭建以后,我们就需要考虑如何利用现有的验证平台给出适当的激励,检查测试结果;
覆盖率要求
覆盖率是衡量激励生成种类和设计功能点验证的量化指标,无论通过何种验证方法,我们都需要采用覆盖率来确保给出了足够多的想要的激励类型,以及设计边界和内部穷历了可能的状态。除了给出合法的激励之外,也需要考虑给出一些错误的激励,来测试设计的稳定性和纠错能力;
项目部分
工具选择
对于项目而言,需要通过验证计划中选择的方法,来考虑选择相应的工具,它们包括:
- 仿真工具
- 形式验证工具
- 验证IP
- 断言IP
- 调试器
- 硬件加速器
- 高层次验证语言(High-level Verification Language,HVL)
选择了不同的验证方法和工具,接下来就需要考虑安排有合适技能的验证人员完成工作。
人力安排
在确定下来验证方法以后,验证经理就可以考虑投入的人力了。由于不同验证方法存在显著差别,除过考虑个人的实际经验以外,也需要考虑他们是否熟悉该模块,知识和技术背景越贴合,越倾向于选择这样的验证人员。一般在同一个项目完整周期内,我们会考虑让固定的人员跟踪同一个设计模块,从搭建环境开始,经历模块级、子系统级和芯片系统级验证过程,这样对于项目的风险较低,人员的成长也更快。
进度安排
在安排人力的过程中,我们同时也将进度考虑了进来。一般而言,进度是从上向下传达的,验证经理事先会有一个大致的时间表,通过简单的计算:
- 工作量 = 人力 x 时间
来安排合适的人力投入到验证中去。而往往陷入的境地是,人力不够充分,或者时间不够宽裕,面对这样的困难,时间是没有弹性的,更多地需要在人力角度上考虑如何恰当地安排人力,做好动态的人力分配,实现高效的资源配置。那么对于验证经理而言,进度是否是不可修改的,必须严格遵循呢?这样的问题可能难以给出一个是或者否的答案,但是如果可以在计划中将设计的交付时间、验证的验收时间、不同模块的集成时间等等重要信息拆分开来,做到更细致的量化和评估,那么项目执行中的风险就可以在早期发现,同时朝着按时交付的目标共同迈进。
风险评估
在项目执行中,无论是设计人员、验证人员还是项目经理,都会面临诸多不确定的因素:
- 芯片结构不稳定因素。如果在项目执行后期,突然面临结构的变化,这肯定会给对应的设计和与它关联的设计带来很大影响,而验证任务量和时间也需要发生改变。
- 工具的不稳定因素。在新的项目中,我们倾向于使用更新的工具版本,因为它们会带来新的性能提升和特性,而在新版本工具使用中也会有适应期,并非一帆风顺。如果我们需要替换工具,那么面临的工具替换成本、环境流程更新、技术培训都要更大一些。
- 人力的不稳定因素。我们都希望在项目中人员结构可以稳定,这样就不会出现模块的验证人员被临时替换,加大验证风险的问题。同时,如果一个人投入到两个以上的项目,那么他在不同项目中的精力分配也需要考虑进来。
- 模块交付时间的不稳定因素。由于验证的展开与设计的交付时间密不可分,所以HDL设计的交付时间对于验证进度的影响非常大,所以在计划初期,验证经理应该从设计团队那里获取清晰的交付时间,然在在此基础上做进度和人力安排
计划变更的周期在不断地发生,如下图:
在对设计进行验证以后,我们需要衡量验证的完备性,这时候需要对覆盖率进行分析。当发现覆盖率无法满足要求时,我们需要针对覆盖率漏洞,更改验证计划并且相应添加测试用例,通过这样的反馈环路,我们才可以循序渐进地逼近功能验证的收敛目标;
在验证过程中,我们需要不断地更新验证的进度,从各项参数综合评估验证的完备性。在不同的验证层次过程中,我们通过收集以下信息来评估验证计划的实施进程:
- 递归测试通过率(regressioin pass rate)
- 代码覆盖率(code coverage)
- 断言覆盖率(assertion coverage)
- 功能覆盖率(function coverage)
- 缺陷曲线(bug rcurve)