芯片验证策略六部曲
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
芯片验证策略六部曲
验证的策略篇之一:设计的流程
通过芯片产品开发的流程图,而在描述中我们将开发流程分为了两条主线:
芯片功能的细分
不同人员的任务分配
即是说不同人员需要在硅前的不同阶段实现和测试芯片的模块功能。
如果我们从另外一个角度看,芯片的开发即是将抽象级别逐次降低的过程,从一开始的抽象自然语言描述到硬件的HDL语言描述再到最后的门级网表。
而在我们已经介绍过RTL设计和门级网表以后,这里需要引入一个目前更高抽象级的描述TLM(事务级模型,transaction level models)。
TLM一般会在早期用于构建硬件的行为,侧重于它的功能描述,不需要在意时序。
同时各个TLM模型也会被集成为一个系统,用来评估系统的整体性能和模块之间的交互。
同时TLM模型在早期的设计和验证中,如果足够准确的话,甚至可以替代验证人员的参考模型,一方面为硬件设计提供了可以参考的设计(来源于系统描述侧),一方面也加速了验证(无需再构建参考模型,而且TLM 模型足够准确反映硬件描述)。
TLM模型的需求和ESL开发
早期的芯片开发模式是遵循先从系统结构设计、到芯片设计制造、再到上层软件开发的。
但随着产品开发的压力,一方面我们需要让系统人员、硬件人员和软件人员都保持着充沛的工作量,同时对于一个芯片项目而言,我们也希望硬件人员和软件人员可以尽可能的同时进行开发。
这听起来怎么可能?毕竟芯片还没有制造出来,没有开发板怎么去构建软件呢?在这里我们系统结构人员会在早期构建一个高抽象级的系统,同时该系统必须具备该有的基本功能和各模块的接口保持信息交互,通过将功能描述变成可运行的系统,让硬件人员和软件人员可以在早期就利用该系统进行硬件参照和软件开发。
这种可以为复杂系统建立模型,让多个流程分支并行开发的方式被称作ESL(电子系统级,electronic system-level)开发。
传统的系统设计流程
传统的系统设流程是瀑布形式(waterfall)开发的,这种顺序开发的方式存在明显的边界:
时间边界:不同的开发子过程之间是保持顺序执行的,几乎没有可以交叠的空间来缩短整体的项目交付时间。
组织边界:不同的开发小组之间的交流是计划是发生在前一个过程结束,后一个过程开始的,这也引入了额外的沟通成本。
ESL系统设计流程
为了模糊或者融合这种边界,ESL开发流程通过建立虚拟原型(virtual prototype),又或者称之为TLM模型来使得整个参与到系统开发的小组做并行开发。
之所以可以有这种魔力,是因为TLM模型不再是一种无法被硬件开发和软件开发利用的抽象描述,而是一种更早期开发的软件模型。
所以在ESL开发的协助下,更多的自开发流程可以更早跟随系统设计一块进行开发,那么从整体上来看这种方式有助于缩短芯片开发的时间。
除此之外,在前期产品定义的阶段有相对可量化的模型,更有助于早期验证产品的功能、性能是否满足客户要求,也能减轻一些低配置性能的风险和降低过多设计的成本。
这是为什么呢?有以下几点:
在早期定义产品的时候,市场部会将客户对于产品特性收集回来,而交由系统框架师来定义芯片结构。
这中间会存在一些问题,例如系统框架师无法深入到局部功能更无从列举出所有的用例来判断功能是否满足,而对于性能测试方面也只能通过一些表格化数据做出静态估计。
这时候,TLM模型可以帮助在系统级别完成模型搭建和虚拟系统集成,甚至帮助测算系统的性能,这对于系统框架师而言会有更多的信心来给出合理的结构配置。
正由于可以在早期做出性能评估(而且快速、发生在芯片结构的定义阶段),框架师可以及时地做出资源调整来满足用户的需求。
否则,尽管芯片可能是低缺陷率的,但如果它的执行速度不够快、功耗又过高,那么也仍然无法满足客户的要求。
过度设计的结构就跟给一只袜子缀上水钻一样不差但也没有必要。
客户给的报价摆在那里,你的设计越过度,不但意味着成本的增长,也意外着更高的复杂度和风险。
ESL和TLM对系统模型的要求使得需要有一门语言可以:
纵深多个抽象级别来进行模型描述;
标准开放的语言;
高效的仿真性能和调试接口;
被主流仿真工具支持;
本身包含TLM事务级传输的接口这样的一本语言即是我们接下来介绍的SystemC。
SystemC介绍
SystemC是可以满足TLM模型开发的一种语言。
严格来讲,它本身不是一种语言,而是建立在C++之上的一种类库(class library)。
SystemC语言可以用来描述系统级别的硬件行为,而这一点恰是其它语言无法满足的。
SystemC从2006年被IEEE收入IEEE 1666标准,它本身也易于学习,对于有C++/Java基础和硬件设计概念的人使用起来都不需要太多的学习成本。
SystemC语言介绍不在本章的重点,所以我们略去它的更多的语言特性介绍。
语言的抽象级比较
而不同的硬件领域使用到的建模语言都有它们各自适合的抽象级,下图就指出了各个语言擅长的抽象级领域。
从左至右,VHDL和Verilog主要用作RTL仿真和数字电路的综合,它们也用来在早期搭建一些验证平台。
对于SystemVerilog/Vera/e是用来做功能验证语言的,这其中也包括了它们的随机约束重要特性。
同时我们也可以发现SystemVerilog本身可以用来描述硬件做RTL 仿真和门级综合。
在此之上,SystemC关注的地方要更偏向于系统层,它在结构层面上可以做更高抽象级的描述,而本身也无法去描述电路的综合网表,但它能
够以自己为平台为上层的软件开发做准备。
而Matlab和其它语言被用在了数字信号处理上面用来描述和验证算法。
传统的系统集成视角
我们前面已经提到,传统的瀑布开发模型无法让硬件人员和软件人员在系统结构定义早期就进入。
对于硬件的设计人员和验证人员而言他们都需要等待系统定义完成之后将功能描述文档分别做出自己的翻译来建立可综合模型和参考模型。
软件人员只有在硬件流片以后才会真正开始进行软件开发,尽管目前的FPGA 有着比硬件更快的仿真优势,但无论从时间段(硬件设计的后期)还是从速度(相比软件模型)而言,仍然不是理想的软件开发平台。
我们可以认为FPGA等硬件加速工具对于硅后系统测试有积极意义,但是对于更上层的软件层开发的帮助则并没有那么明显。
ESL系统集成视角
新型的ESL系统开发方式会在系统定义阶段就建立TLM模型,这一模型的建立会对系统人员、硬件设计人员、验证人员和软件开发人员都有显著帮助:
系统人员在TLM模型集成系统上会更容易评估系统性能
硬件设计人员会同时利用功能描述文档和TLM模型更准确地翻译为可综合的RTL设计
验证人员甚至可以直接将TLM模型作为参考模型集成到验证环境中,省去了额外开发参考模型的时间
软件开发人员也可以在TLM集成后的虚拟系统上面开发软件,而当芯片真正出片以后,只需要做一些基于实际硬件的软件移植,这将大大提前软件开发的起点
TLM建模有这么多的优点,然而在真正考虑施行ESL系统集成流程上面,我们也需要考虑到一些实际的问题:
TLM建模对于系统人员而言有更高的技能要求。
这不但需要他们掌握SystemC开发,同时也需要他们有硬件描述的基础。
在此之上,他们的工作量将会同时包括功能描述文档和TLM模型,并且TLM需要准确翻译功能描述文档,确保一致性。
对于从传统流程迈向ESL流程而言,我们可能需要做一些妥协,引入专门的虚拟建模(virtual prototyping)团队来协助系统人员翻译功能描述文档,而他们的共同产出也将最终作为一致的参考标准。
尽管已经有了可以被综合的SystemC的子集和代码规范,目前这种方式仍然没有得到业界的青睐。
不过,在某一个硬件模块没有就位,或者想加快仿真速度的时候,我们甚至可以临时将原先的硬件设计用TLM模型替换。
这一点的前提是,系统的仿真行为保持不变,而且TLM模型接口上的时序可以满足HDL仿真的要求。
当TLM模型被验证环境复用时,就需要TLM与验证环境之间保持标准接口(TLM interface),这样方便TLM模型的插拔。
当TLM用于软件开发时,这就要求TLM被尽早集成到一起作为整体系统为软件开发所用。
因为软件开发环节中针对某一个功能模块的软件开发仍然是建立在整个芯片系统(至少是子系统之上)的。
所以TLM模型之间也需要有标准接口可以更快速地实现系统集成。
目前我们常见的设计流程仍然是瀑布开发时,或者类ESL开发。
这里类ESL 开发指的是开发流程并没有完全遵循上述流程,而是在一些地方引入了TLM建模。
例如下面这张图,由于系统人员的技能限制,项目开发需要额外引入虚拟建模团队。
此外,由于地域上的限制,虚拟建模团队主要服务的对象是软件开发一侧,而他们与硬件设计、验证团队的沟通较少。
这种类ESL的开发可能有多种组合,但我们需要警惕的是,在方便软件开发早期进入项目时,TLM模型是否会同系统定义保持绝对的一致性,从而为硬件和软件方提供文本和代码参考。
从图上来看,这种类ESL的方式是存在风险的,因为虚拟建模团队从系统定义到TLM模型的过程就存在二次翻译,如果翻译不准确,存在疏漏,那么可以
想象基于TLM模型的软件开发不会那么容易被移植到真正的硬件系统上面,因为硬件本身也是二次翻译。
所以,理想的合作边界应该如下图一样。
虚拟建模首先需要和系统定义保持原义的一致性,而硬件和软件则可以将TLM模型视为功能描述的一致性翻译,然后各自在TLM模型上进行开发。
验证的策略篇之二:验证的层次
从系统定义阶段开始,我们就会将芯片系统划分为子系统,进而又为每个子系统划分为不同的功能模块,直到划分为复杂度合适的模块。
而到了设计阶段,我们又会按照自底向上的方式开始做硬件设计和集成。
从定义阶段到设计阶段再到后端部分,我们整个硅前的流程都是将芯片按照层次划分的,一般我们称之为芯片系统级(chip level/system level)、子系统级(sub-system level)和模块级(module level/unit level),这种层次划分的方式对于芯片的好处有哪些呢?
便于拆解功能模块,实现人员的并行工作协同,这一点是从项目执行效率出发的。
对于系统定义而言,这是从主要的功能、性能要求量化为系统不同模块定义的方法。
从设计和验证角度出发,合适的复杂度模块也有助于估计合适的工作量和人员分配。
设计最终是通过模块化来集成的,而验证的环境在模块化以后,也可以方便在更高级的验证环境中复用。
对于后端,在进行了合理的区域划分后,模块和SoC可以并行进行后续的物理设计流程,在每个设计阶段再合成进行相关电源设计、时序分析等设计项检查。
基于模块化的设计最终再进行SoC级别的设计检查并通过流片要求。
如果我们是在为一款手机设计通讯芯片,那么如图显示,一开始系统定义阶段可能要规划出来这么多的功能模块,而且还需要考虑模块的性能因素。
每一款芯片都会包括多个子系统,而每个系统也会包含多个功能模块,从举的这款手机通讯芯片来看,他包括的功能子系统有:
处理器子系统
协处理器系统
本地存储系统
外部存储控制器系统
数据接口系统
系统模块外设
多媒体子系统
调制解调子系统
对于核心模块调制解调子系统来看,其中的2G/3G/4G又因为自身的复杂性依次提高,可以进一步作为独立的子系统来对待,进而细分下去。
所以,如何划分层次,我们一般会从如下几个角度考虑:
系统的复杂性:如果该系统相对独立,那么它自身有作为子系统的条件。
如果它本身任然过于复杂,可以进一步细分。
芯片集成的便利性:对于顶层芯片继承而言,应该一个合适子系统应该与外界应该有清晰的功能边界,例如系统信号边界、标准总线边界、与其它子系统交互的边界,同时这些信号边界也尽可能保持稳定和精简,这是从顶层集成的工作量和后端布局布线的角度出发的。
验证的阶段:验证人员需要清楚哪些功能点在模块级验证、哪些属于子系统和芯片系统、是否有必要在不同级别重复验证、最终各个层次是否会保证验证完备性。
后端的流程:如果一个子系统占到了芯片整体面积的10%以上,那么后端就没有理由不考虑将其单独做综合,因为这样子系统综合有助于后期整个芯片综合的收敛速度。
在这里,我们将主要从验证的角度来考虑,如何选择合适的验证层次到下面不同的验证环境中:
模块级(block level/unit level)
子系统级(sub-system level)
芯片系统级(chip level)
硅后系统级(post-silicon system level)
模块级
如果是图中的处理器子系统,我们会考虑先将DMA(direct memory access)、cache缓存、和core0/core1分别展开模块验证。
每个模块验证首先要考虑的是哪些功能点是可以在模块一级完全验证的,这基于如下考虑:
内部功能如状态机验证
内部数据存储验证
数据打包功能、编解码功能
指令执行
寄存器配置
同时我们也需要考虑哪些功能无法在模块一级被验证到:
与其它相邻模块的互动信号
与其它子系统的互动信号
与芯片外部的互动信号
与电源开关的验证这些部分我们需要考虑在更高的层次来验证他们。
子系统级
对于一个成熟的子系统而言,它既拥有完备的功能可以执行专门的任务,也有足够稳定的接口用来在更高级做集成。
与模块相比,子系统更稳定也更封闭,这对顶层集成是有好处的。
也正是这种便于集成相对封闭的特征,我们可以从公司外部或者内部得到不同的子系统。
合格的子系统交付不单单包含着它的设计部分,也应该包括如下:
设计包
验证包
递归测试表
覆盖率收集脚本和数据
完整的文档(设计、验证、集成、后端)
完备的交付才会增强顶层集成的信任,同时减少在集成过程中发生的一些接口理解分歧和参数化配置问题。
那么单就验证而言,除了充分验证内部功能以外,对于子系统的外部接口如果存在参数或者编译预处理(compiler directive)时,验证人员需要就这些参数和不同的编译选项(可能因此产生不同的硬件结构功能)给出完备验证。
因为从子系统的封闭性和复用性来看,它们会在多个芯片项目中被使用,这对于设计复用来讲是一件好事,而验证也需要将验证环境参数化来适应硬件的参数化配置。
只有充分验证了参数化的子系统,才可能让它在不同的芯片项目中都能够按照预期实现它的功能。
对于验证管理而言,子系统验证也是一个理想的可以切分的单元,因为这一层下面的模块之间互动很多,而这一层本身又趋于封闭,也即是与外围的接口有限,所以便于在子系统层建立验证小组——包产到组。
芯片系统级
在芯片系统级,我们的验证平台的复用性较高,这主要是因为
外围的验证组件不需要像模块级、子系统级的组件数量多且经常需要更新,它们主要侧重于验证芯片的输入输出
芯片内部的子系统之间的交互、协作检查主要交给了处理器和子系统,从寄存器检查和数据检查入手,写直接测试(directed test)用例
在芯片系统级的验证侧重于不同子系统之间的信号交互问题,以及实现更贴近实际使用的用例。
这里的实际用例并非是在系统软件层面的,而是将系统软件层面的场景进一步拆分为多个模块互动情景,再分类测试的。
硅后系统级
尽管我们硅前验证部分与硅后系统软件开发联系较少,但是如果可以尽早将硅后软件开发的实际用例在硅前测试,也能够可以发现一些实际使用中的问题。
实际上,系统软件用例和硅前的随机测试有着互补的特性,对于功能验证上面缺陷的理解是,如果没有被硅后测试、软件开发、用户使用的过程中发现,那么隐藏的缺陷也会永远静静躺在那里,也许永远也不会被发现(没有零缺陷的芯片,却有用户没有发现缺陷的芯片)。
所以,如果可以将硅后的驱动、固件和系统软件尽早在硅前就引入验证过程的话,这可以跟硅前的验证方法形成互补,使得验证更加完善。
我们上面介绍了验证的四个阶段,也给出了他们各自使用的测试场景。
这里我们再给出几点可以遵循的原则帮助大家选择适合的级别来进行验证:
如果更低的级别可以完成某一项功能验证,那么就不要在更层去验证它。
因为更小的验证环境更有利于控制激励场景的产生,更加全面的覆盖功能点。
如果低层次已经充分验证过某一项功能,那么高层次不需要重复验证。
而对于低层次无法完全覆盖功能点验证的时候,应该在高层次完全覆盖。
如果是低层次的验证阶段,应该适当地考虑高层次的测试用例,而在低层次创造一些条件来进行模拟发生。
如果是高层次的验证阶段,验证环境中的参考模型、数据比对、监视器等模块首先考虑从低层次环境复用,在无法满足的情况下再考虑重新构建。
如果是新的模块或者新的功能,应该投入更多的精力和优先级在不同层次充分验证。
最后,我们通过一张列表来更好的理解,不同的验证层次的验证侧重、性能、使用方法:
懂得选择一个合适的验证层次,并且通过在不同层次分配不同的功能验证
点,是最终迈向验证完备性的一项必备技能。
验证的策略篇之三:验证的透明度
我们可以按照激励的生成方式和检查的功能点分布将验证划分为三种基本方式:
黑盒验证
白盒验证
灰盒验证接下来,我们逐个解释这三种不同透明度的验证特征。
黑盒验证
如果验证人员对于设计的细节缺乏认识,那么黑盒验证是一种合适的方式。
因为验证环境只需要将激励给入设计的外部接口,而检查设计的另一侧输出就够了。
而测试的成功与否只是根据一个输入是否得到一个正确的输出,验证环境本身不会关注设计的内部。
从上面这张图可以看到,激励生成器(stimulator)只负责给设计灌入激励,监视器(monitor)和检查器(checker)也只查看和比较输出信号。
黑盒验证的一个缺点是它缺少设计的透明度和激励的可控度,而由此带来的一些问题包括:
当测试失败以后,无法更深层次地定位问题。
对于验证人员而言,他只能判断是测试是否成功,但无法将报告进一步定位到缺陷所在的位置,与设计人员完成深度协作。
这种方式对于发现一些较深的缺陷比较困难,因为验证人员无法根据设计本身给出更窄的随机约束来定向生成一些激励。
同时,这也对设计内部功能点的功能覆盖率收敛没有太多的帮助。
当一些设计的接口采用标准接口时,图中的激励生成器或者总线功能模型可以使用复用性高的验证IP。
这些验证IP一般由第三方公司提供,有时候公司内部也有这样的IP,它们的特点是像标准接口一样易于在验证环境中插拔,易于控制且接口时序严格按照总线文档定义。
同时对于监测器而言,它也来自于验证IP,这也减少了验证人员的工作量。
所以当模块的接口标准化时,验证环境也可以复用一些验证IP。
由于黑盒验证本身不包含设计的内部逻辑信息,所以当设计由于缺陷做了更新或者添加新的特性之后,原有的测试列表仍然较稳定,验证人员只需要对新添
加的特性考虑新的测试场景。
黑盒验证有利于保持测试环境的稳定,在后续项目中一旦更新了设计,新的验证人员也只需要很少的力气来维护继承的验证环境。
白盒验证
相比黑盒验证,白盒验证可以弥补一些不足。
由于验证人员了解设计的内部工作逻辑、层次、信号等,他就可以对更底层的设计细节进行测试。
由于对于设计中各种组件和逻辑细节都了如指掌,这种验证方式可以验证设计是否更严格地遵循功能描述文档,而且一旦测试发生失败也可以更快速地定位到缺陷。
对于白盒验证的环境,我们的参考模型逻辑非常简略,甚至不需要参考模型,而只需要植入监视器和断言来检查各个内部逻辑。
这种环境配置背后的原则是说,当我们充分检查各个逻辑驱动和结构以后,就不需要测试它的整体功能,因为白盒验证是穷举逻辑路径的方法。
使用白盒验证也面临一些方法学上的缺陷:
由于本身专注于设计内部逻辑检查而忽略整体功能的测试,在设计本身违反规范的情况下,白盒验证难以发现缺陷。
在数据一致性检查的方面,白盒验证难以从整体入手给出实际测试用例。
由于白盒验证的测试用例很多都是从设计的细节入手,所以一旦设计发生更新,那么对于验证环境的维护成本就偏高。
这一点在项目间复用方面带来的影响更多,甚至新接手验证环境的人要付出很大的成本去理解设计细节和验证环境的细节。
这时候白盒验证环境的低复用性缺点就暴露出来了。
灰盒验证
从黑盒验证和白盒验证来看,他们各自都有着优势和劣势。
在实际验证中,我们更倾向于将黑盒和白盒两种方法掺杂在一起,让监视器、断言、参考模型一同来完善验证。
这种糅合的方式带来的好处包括:
监视器和断言可以有着更好的透明度来着重检查设计的一些重要内部逻辑。
参考模型由于已经有了断言检查局部逻辑的帮助,会减少很大一部分精确度,而主要专注在输入和输出的数据比较上。