电子说
架构师从原始需求提炼出来功能规格(FS)与架构规格(AS),两套流程使用不同的思路和方式对其进行实现,实现过程中互为对照同步收敛,产生分歧时以架构为根本决策依据,最后殊途同归。
验证流中,首要环节为测试点(亦称验证特性 Verification Feature,我习惯称测试点)提取,验证的后续所有动作基本都是围绕测试点来展开的。测试点实际就是把一个有机整体的功能分解成一系列单个的功能点,起到化整为零,化繁为简的作用,从而方便构建测试用例对其进行验证。分解的粒度没有一定之规,但有几个大原则要把握:完备性,即不能遗漏任何功能点,特别是异常处理,边界处理,容错处理这些往往容易被忽视;低耦合,不同测试点之间的相关性越低越好,这也直接决定了分解粒度,并影响testcase的开发难度;无歧义,测试点的描述要直接而明确,不同测试点之间不存在矛盾之处。
测试点的主要来源为FS和AS,这也就要求验证工程师在项目架构设计阶段并不能置身事外,而是和设计工程师一样,要参与到架构文档的Review活动中来,在不改变产品功能的前提下,甚至可以向架构师提出可验证性方面的设计建议或需求,参与度越高,理解越深刻,越能保证测试点的提取质量。测试点也有少部分来源于设计工程师的微架构或设计规格(DS),主要针对一部份corner case,来源于DS的测试点不能有悖于FS/AS的要求。 测试点是验证活动的核心,直接决定验证结果的可靠性与完备性,非常重要,但因为它是一个相对主观东西,很大程度上依赖于工程师的经验、理解能力、以及责任心,可以说衡量一名验证工程师的技术水准,不在于他的Testbench写得多漂亮,UVM玩得多熟,而在于他的测试点分解质量。为了保证验证源头的正确性,验证工程师应该对FS/AS反复研读,项目组内进行交叉串讲,并通过答辩后再行测试点分解,分解结果依然需要通过架构师、设计工程师、以及组内其他验证工程师(特别是相邻模块)的Review后,方可进入后续流程环节。这个过程看似繁琐,但磨刀不误砍柴功,切不可图省事而草草了之。 测试点明确以后,便可以针对性的设计测试激励与相应的功能覆盖点,并明确覆盖手段。功能覆盖率让自然语言描述的测试点变得更加具象和量化,由主观变成客观,是验证出口标准中最重要的依据之一。功能覆盖点的选取尤其要注意边界值与异常值,并设置合理的cross,确保完备。同样,相互之间反复Review是必不可少的操作。 验证平台的设计现在已经非常标准化,UVM一统天下后,基本框架都差不多,主要取决于对UVM的理解与System Verilog的编程能力,在这里没有太多可说的,当然它也有很多细节,可另外开文单独进行讲解。我觉得需要稍加注意的几个点,一是transaction中,对随机约束的设计要符合测试点的要求,每一个constraint的粒度把握好,方便在testcase中进行扩展与差异化控制;二是功能覆盖率编码不要遗漏,也不要加入毫无意义的cover bins,严格符合测试点阶段的结论;三是适当考虑组件的可重用性,提升整体效率。重用的问题,后面会讲到,这里不展开。 和设计工程师对自己的代码进行单元测试一样,验证环境搭建完成后,也应该进行自测试,以排除低级简单的错误。比如可以采用driver的输出接monitor输入的方式,检查测试激励是否可以生成,整个平台的数据通路是否畅通,自检测机制是否正常等,这是一个简单而必要的步骤,能使RTL与VE的第一次集成,即Sanity Test变得事半功倍。Sanity Test(冒烟测试),顾名思义,就是一跑就冒烟挂了。这是设计代码和验证环境都刚刚完成后的测试,目的就是确保寄存器读写OK和打通基本数据流。这个过程设计人员和验证人员高度配合,发现bug会立即修改。这个过程会发现很多代码问题,这个阶段发现的bug一般不提问题单。 冒烟测试完成后,DUT已经基本可以正常工作,这时候就正式开始进入验证执行阶段。验证是一个不断迭代的过程,需要不断编写或修改测试用例来覆盖功能点和rtl代码。仿真中发现问题,更正问题,记录问题,回归测试,往复循环的同时,分析功能覆盖率与代码覆盖的空洞,根据分析结果增加用例运行次数,或者调整随机约束,或者增加direct testcase,使覆盖率趋于收敛。Regression 在Sanity test后将一直持续到Tape Out。 流程走到Sanity Test,正式开启EDA动态仿真之旅。Sanity Test是一条最基本的测试用例,使用最正常的测试激励,最小的随机范围或不进行随机,以快速确认基本的数据流能通以及寄存器读写正常(如果有的话), 是后面复杂测试进行下去的前提。以后不论是RTL还是VE的每一次代码增改,在提交版本服务器之前,通过sanity test是最基本的要求。 流程再往后延伸,就是一个不断迭代的过程。根据最前面的测试点分解,验证工程师不断添加测试用例,对RTL代码进行仿真,发现问题,更正问题,记录问题,回归测试,往复循环的同时,分析功能覆盖率与代码覆盖的空洞,根据分析结果增加用例运行次数,或者调整随机约束,或者增加direct testcase,使覆盖率趋于收敛。在实际的项目管理过程中,往往会把这个阶段根据功能实现比率再进行细分,比如按85%网表、95%网表、100%网表分为三段,达到每一段的出口标准后,将对设计和验证代码进行固化锁定,作为后续的基线版本,这样既有利于项目进度的精细化控制,也方便问题的管理与回溯。100%网表以后,设计将全面进入后端设计流程,RTL代码的变更将变得很少且严格,但这并不意味着验证工作可以停步,Regression 在Sanity test后将一直持续到Tape Out。在我以往的工作经验中,一直都坚持Daily Regression的形式,即每天下班前,都会将所有测试用例提交服务器进行回归测试,在**CRV(constraint random verification)**机制下,用例跑得越多,最终的验证结果越可靠,但如果全部采用Direct testcase进行验证,daily regression将变得毫无意义。 EDA仿真到最后,完成标准主要有三个,一是所有testcase全部通过,二是代码覆盖率达标,最后是功能覆盖率达到100%。代码覆盖率通常情况下不要求100%,但所有空洞需要经过分析确认并记录在验证报告中,其它两个标准是硬性指标丝毫不能打折扣。即使以上标准全部达到,通常还需要稳定回归两个星期以上,如果回归期间出现了新的问题,一切归零,问题修复后重新开始计算回归周期。实际上,成熟规范的公司对出验证出口标准的要求比这个严格得多,会有一长串checklist需要逐一确认,每一条check项后面,是一系列的质量保证活动,比如文档检视、代码检视、文档代码一致性确认、Bug收敛趋势分析、Bug Review、Corner Case确认、End_of_Check确认、编译仿真Warning分析、异步路径分析、网表仿真结果、后仿真结果、寄存器遍历、接口信号翻转遍历…………,这样的checklist通常都是用惨痛的代价换来的,每一条都要认真对待。做芯片就是这样,永远要保持“战战兢兢,如履薄冰”的心态,验证尤为如此,毕竟如果流片回来存在BUG,板子往往是先打验证。
全部0条评论
快来发表一下你的评论吧 !