芯片验证的方法篇(上篇) 验证的方法篇之一:计划的概述 验证的方法篇之二:计划的内容 验证的方法篇之三:计划的实现 验证的方法篇之四:计划的进程评估 验证的计划篇之一:计划的概述在选择验证方法和构建验证环境之前,我们首先需要清楚验证计划是什么。在展开设计之前,设计人员和验证人员都会阅读功能描述文档,以理解设计的各项功能为前提,来考虑如何验证它。如果功能描述本身不清晰,则需要同系统人员沟通来修改功能描述文档;如果设计和验证双方人员对于某一项功能理解有不同的地方,也需要最后同系统人员的解释保持统一。 那么一旦完成了验证计划书,还需要对其进行修改吗?答案是需要。因为在实际项目执行过程中,功能描述文档和设计会不断更新,直到芯片到流片前都有可能在一直进行,那么验证人员就需要做好相应的验证计划更新。所以,验证计划的生命在设计被构建之前就诞生了,伴随着设计的周期,直到流片。 伴随着验证计划的创建,计划流程可以分为若干个步骤,它们包括:
创建一份验证计划是首要的任务,通过收集下列材料可以更好地组织出有价值的计划:
通常上面的这些资料可以从硬件功能描述和系统文档中找到,同时,也可以从硅后测试、固件开发人员那里得到设计的实际使用配置情况。 通过合理的验证计划,可以为芯片开发带来很多好处:
从更宽泛的意义上来看,一份验证计划几乎可以囊括所以跟验证相关的东西,这其中不单单包括要验证的设计功能,还包括验证方法、人力安排、进度评估等等。由于验证计划的生命期很长,在实际环境中,有很多因素会不断影响计划的更新,这些可能的因素包括:
通过在早期制定出一份验证计划,并且伴随着设计更新和验证过程不断修改和跟踪,就可以提高验证的质量,同时降低项目的风险。同时对于人力和时间进度的合理估计,也使得验证进度和流程更加透明。 验证的计划篇之二:计划的内容在制定验证计划的具体过程中,我们会将技术部分和项目部分都考虑进来。从技术角度而言,我们需要考虑的有验证的功能点、验证的层次、测试用例、验证方法和覆盖率要求,从项目部分来看,我们也需要考虑使用的工具、人力安排、进度安排和风险评估。接下来,我们逐个分析技术部分和项目部分。 技术部分 验证的功能 需要验证的功能点主来自于功能描述文档,设计和验证人员在阅读文档的过程中,会将设计的功能、参数、性能从自然语言拆分转化为一个个可以单独验证的功能点,并且需要用定性定量的语言限定描述这些功能。 我们可以将功能点按照优先级分为:
验证的层次 结合验证的功能点,需要清楚该功能点是否可以在较低的层次完成验证。从验证效率和激励自由度来看,我们应该尽量在较低的层次验证更多的功能点。在较高的层次,例如芯片级,应该侧重于系统集成测试。 验证方法 需要考虑采取何种验证方法,动态仿真、形式验证还是硬件加速?采取什么样的透明度,黑盒、白盒还是灰盒?采用直接测试还是随机约束激励?在之前的验证方法篇中,我们对比了不同方法适用的场景。 测试用例 有了带验证的目标功能,选择合适的层次和方法,在完成了验证平台搭建以后,我们就需要考虑如何利用现有的验证平台给出适当的激励,检查测试结果。 覆盖率要求 覆盖率是衡量激励生成种类和设计功能点验证的量化指标,无论通过何种验证方法,我们都需要采用覆盖率来确保给出了足够多的想要的激励类型,以及设计边界和内部穷历了可能的状态。除了给出合法的激励之外,也需要考虑给出一些错误的激励,来测试设计的稳定性和纠错能力。 项目部分 工具选择 对于项目而言,需要通过验证计划中选择的方法,来考虑选择相应的工具,它们包括:
选择了不同的验证方法和工具,接下来就需要考虑安排有合适技能的验证人员完成工作。 人力安排 在确定下来验证方法以后,验证经理就可以考虑投入的人力了。由于不同验证方法存在显著差别,除过考虑个人的实际经验以外,也需要考虑他们是否熟悉该模块,知识和技术背景越贴合,越倾向于选择这样的验证人员。一般在同一个项目完整周期内,我们会考虑让固定的人员跟踪同一个设计模块,从搭建环境开始,经历模块级、子系统级和芯片系统级验证过程,这样对于项目的风险较低,人员的成长也更快。 进度安排 在安排人力的过程中,我们同时也将进度考虑了进来。一般而言,进度是从上向下传达的,验证经理事先会有一个大致的时间表,通过简单的计算:
来安排合适的人力投入到验证中去。而往往陷入的境地是,人力不够充分,或者时间不够宽裕,面对这样的困难,时间是没有弹性的,更多地需要在人力角度上考虑如何恰当地安排人力,做好动态的人力分配,实现高效的资源配置。那么对于验证经理而言,进度是否是不可修改的,必须严格遵循呢?这样的问题可能难以给出一个是或者否的答案,但是如果可以在计划中将设计的交付时间、验证的验收时间、不同模块的集成时间等等重要信息拆分开来,做到更细致的量化和评估,那么项目执行中的风险就可以在早期发现,同时朝着按时交付的目标共同迈进。 风险评估 在项目执行中,无论是设计人员、验证人员还是项目经理,都会面临诸多不确定的因素:
在清楚了一份验证计划中需要包含的各项因素之后,我们接下来就需要考虑如何在项目初期准备这样一份关键的计划,以及在项目执行过程中怎样针对不确定因素的相应更新计划,确保项目的进度受到最小的影响。 验证的计划篇之三:计划的实现一份细致的验证计划会包括详细的项目动向、更新和进度,面对人员总是保持紧张的窘境,只有清晰的计划才能够合理运用人力资源,保证时间和人力的平衡。在上一篇计划的内容中,我们列举出了诸多项目中不稳定的因素,这就使得验证计划需要时常保持更新,给出合理的安排,这样的过程就蕴含着从计划到实践再到反馈,最后再进行计划修改。 计划变更的周期在不断地发生,如下图: 在对设计进行验证以后,我们需要衡量验证的完备性,这时候需要对覆盖率进行分析。当发现覆盖率无法满足要求时,我们需要针对覆盖率漏洞,更改验证计划并且相应添加测试用例,通过这样的反馈环路,我们才可以循序渐进地逼近功能验证的收敛目标。 那么如何制定验证计划呢?通常我们按照如下的步骤:
邀请相关人员 通常我们会邀请跟系统设计和功能模块相关的人员到会,共同展开讨论,参加会议的人一般包括:
这些人员在看待如何验证一个模块的问题上面都有着不同的角度,例如系统人员会关注功能描述是否被实现,测试场景是否可以覆盖到这些功能点,设计人员会考虑具体的设计细节是否会被测试到,软件开发人员会关心如何组合硬件的寄存器配置来完成某一项功能的正确配置和使用场景,我们将这些利益相关者对于验证某一个模块给出的不同角度列举如下: 在实际中,我们不一定可以面面俱到同时邀请到这么全的项目角色,而且,我们也要考虑这么多不同的角色一起开会,沟通起来难免存在一些障碍和分歧。所以实际的建议可以变成分阶段进行:
开会讨论 在开会讨论前,作为会议的组织者,需要搞清楚开会的目的和议题分别是什么?
在开会之前,我们需要一份合适的验证计划的模板用来指导我们在会议上讨论的主要内容,一份验证计划的模板(或者组织结构)可以像下面这样:
在上面这样的计划模板中,我们开会前需要了解的是功能描述和硬件实现方案,在开会中只需要讨论和确定哪些功能点是要验证的,而哪些事不需要验证的,至于验证环境搭建和测试用例构成则是验证工作展开以后需要更新到计划中去的。 面对着不同背景的项目人员,我们在会议中需要注意几个方面,使得会议最终可以达成我们想要的结果。这些值得注意的地方包括有:
通过和不同系统层次的人沟通,充分交流不同层面上的观点,我们对于验证的功能点和它们在系统运用中的角色认识才会更加清晰。 确定测试场景 经过了细致的讨论,我们就可以确定下来哪些功能点需要测试,进而模拟实际场景给出激励进而生成测试场景。在考虑如何生成测试场景的时候,我们需要注意思考下面几个地方:
创建验证环境 在确定了测试场景和验证方法以后,我们构建验证环境产生激励来实现场景。那么我们需要针对设计模块的接口信号设计对应的激励发生组件,通过控制协调不同的激励组件来构建场景。在实现激励发生组件中,我们需要考虑接口信号是否是标准总线或者是系统控制信号例如时钟、复位,如果有可以复用的验证资源,那么毫无疑问会节省我们的时间。在有些时候,如果接口是标准总线,且没有现有资源可以利用的情况下,我们需要自己实现,那么从成本的角度来看,只需要实现设计中所实现的总线功能即可。例如,如果设计实现的是AHB总线协议,但是只支持单次的读写访问,那么我们在实现AHB激励组件的时候,也不必要实现AHB协议的全部,而只需要实现单次读写协议,满足设计接口的协议要求即可。 同时,我们也需要考虑收集数据和检查对比结果,这就需要有监视信号组件和检查组件的实现。监视信号组件的主要任务就是监视设计的接口信号以及内部信号,如果是总线接口,那么需要在解析总线的情况下将观察到的数据打包整理,如果是控制或者其它信号,也需要按照信号的使能定义,在特定的事件下捕捉有效信号。监视信号组件最终会将分析整理好的数据发送给检查组件,最后由检查组件进行数据比较,给出比较信息和报告,最终判定该次测试是否成功。 验证的计划篇之四:计划的进程评估 在验证过程中,我们需要不断地更新验证的进度,从各项参数综合评估验证的完备性。在不同的验证层次过程中,我们通过收集以下信息来评估验证计划的实施进程:
接下来我们分别介绍上述信息的具体收集和分析过程。 递归测试通过率 一份递归测试表是将测试设计所有功能点的用例合并为一个测试集。递归测试表的主要功能就是用来在设计经过缺陷修复或者性能提高后测试原有的所有功能点,确保设计仍然可以正常工作。这种往复的测试方式不仅在于确保新的设计变化不会影响之前的功能,也可以用来避免新的对话对于别的模块造成的功能失效,所以,设计的维护不仅在于按照设计需求提供新的功能,而且也需要保证新功能不会影响原有的功能。 不同的公司和团队之间,往往有着不同的递归测试工具和方法,在这里需要注意的是工具和脚本的版本可能会对递归测试造成影响。例如,如果我们切换了仿真器的版本,那么可能会出现新的问题需要我们调试,所以在项目后期阶段设计区域稳定时,我们不建议切换工具或者脚本的版本。 另外一个重要的地方时,递归测试表中的测试用例需要确保是可以重现激励场景的。这一点对于直接测试方法(例如C/C++)是容易实现的,而对于随机约束测试而言,我们需要在测试中打印出每次测试用例使用到随机种子(random seed),只有通过这个特定的钟子号,我们才可以重新产生之前的激励,并且跟踪调试失败的用例。 我们将递归测试的流程归纳为下图,值得注意的是,如果在某一个层次的递归测试通过,我们接下来可以向上迁移到新的验证层次,展开新的递归测试流程,或者在设计需求发生变化时,重新从模块级开始递交测试表。 不同层次的递归测试表,每个测试用例的仿真时间消耗也不一样,一般而言,模块级是最快的,到了芯片级,一个递归测试表如果是数千级别的测试用例,往往需要若干天时间才能最终运行完毕得出结果。所以,不同层次,不同设计规模大小,不同测试场景复杂度,都会影响测试用例的仿真时间。递交测试表的重要因素就是仿真速度,由于考虑到递交测试表主要是计算资源的消耗和验证结构的性能表现,我们对验证平台的优化和运算资源都会在此时提出更高的要求,因为只有更快速地往复递交和得出结果,才能更快得知新的设计变动是否是可靠的。 代码覆盖率 代码覆盖率是用来衡量RTL代码是否被充分运行的指标,目前的仿真器也都提供方法来收集代码覆盖率,并且进行合并和分析。通过递归测试表,我们可以产生基于测试用例的代码覆盖数据,并且在递归测试完成后,通过合并数据,生成总的数据来分析各个模块的覆盖率情况。常见的代码覆盖率包括:
值得注意的一点是,仿真器在收集覆盖率数据的时候会牺牲一些运行效率,这是因为它需要对代码保持“更多的关注”,所以资源消耗要更多一些。所以,我们建议只有在需要收集覆盖率的时候,需要传入一些仿真命令触发覆盖率收集,而在更多情况下,不需要传入这些命令,也不需要编译带有支持覆盖率收集的仿真目标。 在项目执行中,我们一般会在模块级验证节点结束后开始收集模块级的代码覆盖率,而在芯片级验证节点结束后,收集芯片级的代码覆盖率。在两部分的数据都收集结束后,我们会进行这两个级别的覆盖率数据融合,生成总的数据库。一般项目中会有专人来负责收集和分析覆盖率,各个模块的覆盖率数据会分发给相应的验证人员,等待他们的分析、过滤或者添加新的测试用例,再次递交测试收集新的数据,以此往复,来提高总体的覆盖率。 通常,我们会比较关注语句覆盖率、决策覆盖率和跳转覆盖率,对于总体指标和各个模块在这三项覆盖率上也有相应的指标,只有至少达到了90%以上的覆盖率,才会有足够的信心进行分析下面的两类覆盖率。 断言覆盖率 断言描述本身也支持覆盖率收集,一般可以通过仿真或者硬件加速的方式来收集,也可以通过形式验证的工具来收集。在常见的仿真中,仿真器会记录断言的先决条件是否被触发,以及判断语句成功或者失败。 根据选择的验证方法不同,我们可以将断言覆盖率分为:
功能覆盖率 功能覆盖率是为了衡量设计的各项功能要求是否都实现了,并且按照预想的行为执行。功能覆盖率会关注设计的输入、输出和内部状态,通常它会通过如下组合的方式来描述功能覆盖率要求:
缺陷曲线 在验证过程中,我们会不断地发现新的设计缺陷,通过缺陷记录表或者已有的商业工具记录下来,进而提交给设计人员。设计人员在分析了缺陷,构思并修复了设计缺陷以后,也会修改该缺陷的记录,并且通知验证人员。验证人员会递交原有的递归测试,在有必要的情况下添加新的测试用例,直到所有的测试通过以后,才能宣布新修复的缺陷是成功的。 在缺陷被记录的过程中,我们通过时间坐标和特定时段的缺陷数量绘制出缺陷率曲线。在之前《验证的任务》一文中,我们就指出了缺陷曲线对于验证计划的影响,从下图中我们看到,如果我们可以尽早地将缺陷曲线增长状态收敛,这意味着我们后期发现缺陷数量和可能性也就越小。可有些时候,我们需要当心的是,如果到了验证后期,我们发现了一个基本功能存在重大缺陷,这就是一个危险信号,代表我们很可能在之前验证当中遗漏一些重要的激励部分。 至此,我们将用来评估验证进度的几种标准概括介绍完了。对于验证计划的制定,不仅仅是验证人员会参与其中,其它角色也会被邀请到会议当中。而到后来验证进度的更新和评估过程,则主要是验证人员和验证经理的在执行。实际项目的经在重复告诉我们,一份详尽准确、不断更新维护的验证计划是迈向成功验证的基石。 来源:路科验证(微信订阅号ROCKER-IC) 及 EETOP BLOG |
|
来自: 毕杰lb7q1kq7pr > 《待分类》