验证的方法篇 一、动态仿真 从这一季开始我们进入了《验证的方法篇》,之所以单独分出一季来介绍验证的方法和工具,一方面是目前验证方法的分支和其工具种类繁多,另外的是希望读者可以在系统了解了验证的工具库之后,在验证设计的时候首先有一套工具箱,而后再根据设计的特点将其结合不同的验证方法和工作,最终取得满意的效果。 从Wilson 2014年调查数据来看,验证占据了主要的人力资源,同时也是设计能否达标低缺陷率的主要保障。从2007年到2014年的增长趋势来看,由于设计的复杂度逐年攀升,与之带来的验证压力和实际人力资源配置都相应提高。除了人力的投入,设计自动化(DA,design automation)工具关于验证的方法、特性、性能提高都在协助验证人员来面对新的验证挑战。 到了目前的阶段,已经没有一种单一的工具、语言或者方法可以提供用来实现验证完备性。实际的验证工作中,我们需要通过多种语言、方法、脚本、工具最终达到验证的的目的。这些不同的语言、方法、脚本和工具之间没有绝对的优劣,比如仿真验证方式会协同形式验证方式一同来完善功能覆盖率,也有可能通过不同语言的脚本之间的整合来最终完成一项验证流程。总而言之,作为一名有经验的工程师,他需要在掌握现有的各种方法和工具的前提下,通过合理的选择,最后“保质高效低耗”地完成验证任务。 所以,我们将根据验证的方法分为若干类为大家梳理目前主流的验证方法和工具。这些主要的验证方法可以分为:
在此之上,我们额外引入一篇开发环境来将日常的编码环境与大家介绍,所谓工欲善其事,必先利其器,有一个应手的开发方式,也是迈向高效率的一步。 这一篇我们为大家带来日常最常见的验证方式——动态仿真(dynamic simulation),该方式其实就是通过测试序列和激励生成器给入待验设计适当激励,结合时间的消耗,进而判断输出是否符合预期的。简而言之,我们需要仿真器来配合这一项工作,验证人员也需要通过查看比较结果、仿真波形比对最终来判定测试用例是否通过。如果按照激励生成方式和检查方式的不同,我们又可以将动态仿真中的验证方式分为:
由于参考模型一般都会伴随着直接测试或者随机测试,所以我们接下来带着大家着重了解这三部分:直接测试、随机测试和断言检查。 直接测试 直接测试指的是激励的值在仿真之前已经决定下来,测试用例给出的激励序列会在下一次重新提交任务以后保持不变。我们日常会通过C/C++/汇编代码来实施测试用例,该场景最常见的是SoC子系统级或芯片系统级的测试,因为待验设计一般会包含处理器在期中,而且根据硅后测试复用的角度,我们也倾向于运用C代码来编写测试用例。 从下图中可以看出,测试用例经过编译、二次映射成为硬件存储器可以读入的镜像文件(一般为二进制文件,主要包含地址和数据两部分)。待验设计经过上电复位(power up and reset)以后会从存储器中读取二进制文件,进而处理器会将二进制数据译码(decoding)为指令和数据进行运算或者寄存器访问。而最终的数据比较分为两种情况:
有时候我们也会考虑直接将第三方提供的可执行文件或者预先映射的二进制文件作为激励源交给存储器,这就跳过了C代码编译的步骤,也需要额外的运行环境兼容措施。 我们将上述的直接测试的流程对照到实际项目中,如下面这个例子,测试用例可以通过C代码交给处理器,进行硬件行为的仿真检查。如果在模块验证环境中缺少处理器,我们如何在这一级实现C代码的垂直复用(从模块级到芯片系统级)呢?可以考虑下面的步骤:
上面的步骤中需要引入转换器实现复用,我们也可以考虑将转换器和总线翻译器结合成为SystemVerilog C-DPI的形式来将翻译层通过标准的C-DPI接口实现更多的复用性。关于SystemVerilog C-DPI的实践方式我们会在后面的篇章《SystemVerilog实战点全讲》里跟大家详细讨论。 直接测试的运用场景一般会在模块测试的早期或者在系统级芯片测试场景中,它适合于测试待验设计的基本功能,且能最直接地翻译出验证人员想要的场景,而它的缺陷也较明显那就是,每一个直接测试用例在通过之后的重复仿真是冗余的,因为这不会提高更多的覆盖率,也无法产生新的测试序列。不过也正因为它的激励序列确定性(determinacy),直接测试有时候可以构成基本测试表来在验证前期保证设计的基本功能。 随机测试 与确定性序列相反的则是随机序列(random sequence),随机序列通过预先定义的约束每次随机产生合理的数值,进而通过激励产生器给出测试序列。下图可以说明,与直接测试相比,随机测试用例可以直接通过激励生成器转化为测试序列。 产生随机数的方法有很多种,有很多语言可以实现,但是考虑到灵活地给随机绑定一些约束的时候,我们需要特定的语言提供这样的属性,目前常用的语言有SystemVerilog和e语言。从下面Wilson 2014年调查数据来看,SystemVerilog的 使用率大致已经上升到了75%以上。 约束实际上是随机激励能否符合接口协议,以及朝着验证焦点而去的关键。随机约束生成器一般可以通过静态约束或者动态反馈约束来给出每一轮的激励。从下图可以看出,在实际的验证环境中,往往有很多对随机约束起到控制和反馈的因素,它们分别是:
基于覆盖率驱动的随机验证 目前常使用的一种随机验证方式是基于覆盖率驱动的,而这种方式也同我们上面提到的影响随机生成的因素“反馈的动态随机约束”一样。从下图可以看出,与常用的随机约束验证方式不同的一点是,覆盖率收集器在每次测试中都会通过监视器来收集覆盖率(主要指功能覆盖率),将其与已有的覆盖率数据库进行合并,同时根据现有的覆盖率数据库来为下一次随机约束给出反馈。这些正向的反馈就是用来进一步缩窄随机约束域,使其能够定向产生一些序列来覆盖那些未知的功能测试点。 基于TLM的随机验证 对于测试用例而言,它可以指定每一次激励的数据内容,也可以在较高层次上指定每一次激励数据包(data packet)的内容。我们在之前《设计的流程》中就介绍过用TLM建模来在产品定义早期对设计建立模型,而TLM本身是就模型层次而言,它在更高一级用来描述设计或者验证环境。对于基于TLM的随机验证方式,它指的是在随机环境中使用到的最小颗粒是TLM级别的数据包。该激励数据包中不只是包含一个时钟周期内该给出的激励,而是在更长的时间范围(一般为一次完整的数据操作,例如完整的数据读写或者完整的数据包传输)将使用到的数据都加以定义。 通过TLM级别的验证方式带来的好处是验证人员可以更为便捷地描述一些测试场景,更加贴近于真实的用例。这也是因为真实的用例,例如硅后系统测试和固件开发时基于系统级别的高层次,它们专注的并非某个模块的某一项功能,而是关注于某个子系统或者整个系统的联合工作模式。 从下面这张图可以看到,TLM测试用例由于抽象级较高,需要有TLM2RTL激励生成器来做进一步的转换。我们将TLM激励生成器进一步放大以后可以看到它内部的一些转换模块,包括读写操作、复位操作、中断操作还有其它操作。这些方法一般都是根据TLM操作命令经过翻译来使用的,我们将这样的激励生成器称之为总线功能模型(BFM,bus functional model),它的作用就是将高抽象级的TLM命令转换为低抽象级的硬件端口时序。进一步看,在高抽象级到低抽象级的转换中,除过数据抽象度是在降低以外,激励所用的时间也在转换中被实现加注到待测设计接口上面了,因此要完成一项TLM命令的转换,经常需要数十上百个时钟周期。 断言检查 影响验证产出的一个重要因素是如何将功能描述部分准确地描述,因为准确地描述可以帮助验证人员更方便地去翻译功能描述文档。而对于设计人员而言,他们也需要去捕捉各种可能设计行为来证明设计符合预期。断言(assertion)就提供了这样的特性,它善于针对某一个特定的逻辑或者时序进行预设,一旦设计的实际行不符合断言的描述,则会给出检查报告。 断言本身不限定于某一种语言或者工具,而是就它的特性来讲,它可以准确地描述出设计的预期行为。所以有多种实现断言的方法和工具,在近来的20年间,这些被业界支持的基于断言的验证方法和工具如下图所示,在这里我们按照断言方法不同的运用过程可以将它们分为如下几类:
由于断言的使用可以分为在验证平台中和插入到设计中,这也使得断言可以同时为验证人员和设计人员所使用。使用断言的优势在于以下几个方面:
这里谈到了断言的复用性,实际上断言的应用场景非常多,且它自身便捷的即插即用的特性使得有多种可选的商业断言IP。下面这个例子用来说明断言运用的场景以及它可以垂直复用的特性。 从运用场景来看,典型的断言场景可以包括:
从复用角度来看,断言可以实现从模块级到子系统级再到芯片系统级的垂直复用。从上图可以看出,从单元1在模块级验证时插入的断言“数据进出”和“状态机”两部分在子系统级和芯片系统级两个环境都可以保持监测检查的状态,这一点要归功于断言可以作为非综合模块被置入到设计中,或者通过绑定的形式作为模块并行于设计进行例化(同时不影响设计结构)。而在子系统中,新的断言部分“子系统集成”又可以实施用来检查从单元1与从单元2之间的集成关系,这一关系检查在芯片系统中也可以继续保留下来。 至此,我们将动态仿真验证的方法介绍完了,在今后更多的篇章中还将对这些主流方法进一步讨论。 二、静态检查 与动态仿真相对的是静态检查,它本身不需要仿真、波形激励,通过工具的辅助,验证人员即可以发现设计中存在的问题。静态检查方法较为分散,且关注的验证领域也不为一致,我们将目前主要的方法概括为:
语法检查 如大多数编译器(compiler)自带的功能一样,各种硅前验证的工具一旦需要建立模型(无论是针对动态仿真还是静态检查的模型),都需要其编译器对目标语言提供语法检查。对于硅前阶段,各种编译器带来首要的好处是帮助检查明显的语法错误,例如拼写、声明、引用、例化、连接、定义等等常见的语法错误。 不同仿真工具对于同一语言标准的解释和理解也可能存在偏差或者不同的严格程度,所以在使用不同厂商、不同工具提供的编译器时需要注意的地方包括:
对于初步认识仿真工具的人而言,可能不同编译器对于同一项语法错误给出的错误提示也不相同。这里我们能够给出的建议是:
语义检查 语义检查和语法检查相比,是在设计可行性上做深入检查的(当然前提也是首先通过了语法检查)。语义检查是通过专用的工具来协助完成的,例如0-In(Mentor)以及Spyglass。常见的语义检查包括的范围有:
进一步细化这些检查项,它们会检查设计的这些部分:
这些静态检查最大的便捷在于,一些功能实现以外的设计问题可以在更早期就被发现,而且这些静态检查也有助于完善设计编码风格,使其更有助于覆盖率的收敛和后端综合以后的逻辑实现保持(例如寄存器未初始化或者固定赋值)。语义检查最明显的两个优势在于:
跨时钟域检查 大多数复杂的设计都拥有不止一个时钟,而且多个时钟之间也是异步的关系。对于设计中的不同功能模块如果被不同的时钟驱动,那么就会形成不同的时钟域(clock domain)。对于单一时钟域的设计而言,它的设计方式和验证环境都较为简单。而对于多时钟域而言,不同时钟域之间的逻辑通讯就需要考虑同步问题了。在这里,用来验证这些设计要求的过程就被称为跨时钟域检查。 之所以需要同步是由于不同时钟域的时钟是异步的关系,这使得从时钟域A的信号进入时钟域B被采样时,每个周期都会有相对时钟B不同的延迟,这种随机性可能会导致建立或者保持时间无法满足(setup timing or violation timing violation),进而导致不可预期的功能失败。 这种跨时钟域问题无法通过常规的验证方法分析,例如动态仿真,也不能被静态时序分析(static timing analysis)判断出来。而这里通过静态的跨时钟域检查就可以分析这一问题。通过该方法可以在早期的RTL阶段来识别出跨时钟域的通信电路上面是否有合适的同步处理。 所以跨时钟域检查(CDC)是为了保证所有的CDC信号都能够得到正确的同步,而进一步来看,CDC检查是为了解决更大的问题:
目前支持CDC检查的商业工具有Spyglass、0-In(Mentor)。 形式验证 形式验证分为两种方式:
我们在这里介绍的是属性检查,即通过验证语言(PSL、SVA)来描述设计行为,用断言(assertion)的方式结合设计源进行检查,来证明设计行为同属性描述保持一致。属性检查的流程通常如下: 在动态仿真验证中,我们是通过生成各种测试序列来去访问待验设计中的状态(state)的,而理论上所有可能仿真的设计状态被称作可及状态空间(reachable state space)。对于动态仿真而言,要遍历可及验证空间的所有状态是一项非常大的挑战,这种通过访问状态、检查结果的方式需要覆盖率反馈来衡量可及状态空间还有多少未被访问。 然而动态仿真验证的方式实际上无法来穷举所有可能的序列去访问设计的可及状态空间,而形式验证可以通过数学方式来穷举出所有的状态空间,彻底验证设计。从下图可以看到,在仿真过程中,通过随机和覆盖率反馈的形式,我们可以产生不同的测试序列来访问状态空间,直到我们发现新的缺陷。这是一种实用的测试办法,但是另外一方面,动态仿真验证没有办法去确定设计中不存在缺陷,因为图中其它隐藏缺陷依然有待于去挖掘更多的状态空间才能被发现。 而形式验证可以通过数学的方法来遍历状态空间,进而证明设计行为符合属性描述(property description)。在遍历过程中,一旦遇到反例,形式验证工具便会停止下来,报出反例情景,由用户来核对错误是否属实,再考虑修改设计或者进一步约束属性使其更精确地描述设计行为。下图中可以看到,在大量的状态空间中,形式验证工具只需要针对某一项属性描述举出反例,即可报告给验证人员,而并不需要穷举所有的反例。等待设计缺陷一旦确认、经过修正之后,验证人员可以继续通过工具来对设计和所有的属性进行检查。 像上面所讲的将属性描述(由断言构成)与设计结合进行一致性检查的方法已经提出超过20年了,且在这期间也有着不同的商业工具提供支持,例如:OneSpin,0-In(Mentor),Jasper等。下面的图概括出这些工具的进化历程: 在今后关于“基于断言的验证(assertion-based verification)”我们会详细介绍SVA、OVL的使用方式。 三、开发环境 如果我们将影响验证编码效率的因素分为“硬件因素”和“软件因素”,那么硬件因素的配置在短期是可以补齐的,而软件因素则会设计到验证人员的技术能力、调试能力和其它软实力。所以从实用的角度上来看,如果准备在验证道路上长期深耕的话,更早地提高硬件环境配置是一笔越早投入收益越大的事情。 如果这是一篇知乎上的文章我的笔风可能是这样的——
实际上我们作为稍显严肃的一个订阅号,要跟大家分享的验证师日常会是下面这样——
如果是软文,我们会主要讨论前两个问题,不过这显然不符合我们的气质。有多少位涉世未深的青年在一开始在对SV编码时,手足无措,跟大圣一样手头缺少一件像样的兵器。我们这篇文愿抛砖引玉,将验证人员日常SV编码的开发环境做一个介绍。实际上,我们之前也介绍过验证人员需要掌握其它的软件语言例如C/C++或者脚本语言,这些语言也需要不同的开发环境,只是这一部分并不在我们这篇的讨论范围内。 Vim开发环境 大多数Unix用户的编辑器无外乎使用Vim或者Emacs,而自打有了这两样编辑神器以来,两路的铁粉们从未就孰优孰劣达成一致,这也反映了两种编辑器都有着广大的用户群体。由于我们团队是重度Vim使用者,所以我们就着Vim开发SV的环境配置做一些介绍。下面介绍的环境配置中,大量的插件来自于Vim官方网站,有一小部分是用户自定义的设置。 由于Vim添加插件、用户自定义方法很方便,所以,我们Vim的开发环境包括的特性有:
浏览方式 好的浏览方式的简单衡量办法就是看你在键盘和鼠标之间的切换频率有多少,切换地越频繁也就越影响效率(其实也影响你的手部腱肌健康)。所以,我们建议初学者首先配置好浏览文件的环境,这其中要考虑的因素有:
版本控制 对文件版本有严格控制的项目,需要文件在编辑之前签出(checkout),而在文件编辑完成之后签入(checkin),通过这种方式实现团队内部文件资源的协作。由于版本控制需要额外的软件,例如SVN、Git、Clearcase,我们在签出签入时需要在Shell命令行键入相应的命令,这又引入了额外的手续。在这里我们也建议通过Vim官网下载相应的文件版本控制的插件,来实现版本控制命令同Vim的绑定。 例如,我们团队在使用Clearcase版本控制工具,通过Clearcase的插件实现了新工具栏和命令的绑定,实现了文件操作环境保持在Vim中,也无需切换环境。 代码编辑 到了代码编辑部分,是我们投入最多的阶段。在这一过程中,我们需要考虑的跟SV编辑相关的部分有:
语法高亮 语法高亮是减少编码错误的有效方式,由于Vim默认安装包中没有SV/OVM/UVM的语法高亮,所以用户需要自己在Vim网站上下载这些插件。 实际上,有效武装Vim的插件还有很多,有些小而美的插件在上面的介绍中没有提到,但是它们却可以帮你的大忙。我相信,高效的验证人员一定有着自己习惯的Vim/Emacs环境配置。不同的环境配置实际上都是朝着高效解决问题而去的,如果你愿意分享你的环境配置,欢迎与我们联系和投稿。 商业SV开发环境DVT DVT(Design and Verification Tools)是面向e、SystemVerilog、Verilog、VHD的集成开发环境,它同VisualStudio、NetBeans一样拥有完善的开发特性。DVT是在Eclipse的开放框架基础上开发的,所以如果你已经熟悉如何在Eclipse环境中建立项目、编译、运行和调试的话,那么DVT对你来讲也一定不会陌生。DVT就是来克服设计验证编码中缺少强有力的开发工具现状的,它包含的主要特性有:
此外,DVT的调试器是开发环境的高级功能,它可以使得在DVT上直接调试代码,无需在仿真器上面做转换调试,这种方式降低了调试的复杂程度。用户可以通过调试器,直接在DVT中进行:
在基础的语言编辑和调试基础之上,DVT的验证平台语义检查器(testbench linter)可以通过静态代码分析发现不合适的语句、代码风格、无用语句、与OVM/UVM相悖的使用方式和性能问题。它可以通过改进验证代码的可靠性和维护性来更好地协助验证人员完成验证任务。通常的编译器会检查代码是否符合语言规范,而报告出语法错误,但是编译错误不会给出代码可靠性和维护性的报告,也不会给出建议如何使得代码与方法学保持一致性。 此外,DVT自带的文档生成器可以用来从代码中的注释自动生成准确的HTML文档。这种方式使得设计人员和验证人员只需花费更少的精力来维护一份组织良好的设计和验证文档。或者设计验证人员也可以在原有的代码基础上通过注释方式生成一份更直观的文档,文档的内容可以包括文字描述、继承树、设计结构、UML类图和验证框架等。 有了一件称手的兵器,我们在接下来打野升级的路上会更顺利一些。 四、虚拟模型 对于系统虚拟建模的广泛定义是它包含高抽象级的系统硬件模型,而与此同时软件开发可以在此硬件模型基础上展开。通过这种方式,虚拟模型不但可以让软件开发在更早期就展开,而且还可以收获软件开发的反馈,从而交给硬件设计。 这种反馈在以往的瀑布模式开发周期中是无法实现的,因为软件往往需要等到硬件设计制造完成以后才能展开。通过虚拟模型,硬件可以更早地收获软件反馈而对现有的设计更早地进行修改。这种硬件和软件之间更紧密的协作方式,譬如在早期软件利用虚拟模型测试性能时就可以提出是否需要硬件加速器,或者在更早期来判断硬件和软件的协同任务是否可以满足总的功耗目标。 在目前多核的移动平台上,一个不断增长的需求就是通过划分不同的任务到多核上面来取得更好的性能,而这种软件层面的估测就可以在更早的虚拟建模阶段完成。目前我们通过多项虚拟建模的技术例如协同设计、协同仿真和协同验证,来企图在更早期就可以发现设计中的缺陷,使得修改这些缺陷可以在相对容易实施的阶段完成。通过这种将设计问题更早期暴露出来的方式来使得芯片可以完成一次流片成功的目标,和贴合市场越来越紧迫的窗口需求。 虚拟建模包括一系列的验证技术,他们有仿真(simulation)、模拟(emulation)、FPGA,而目前的现状是验证人员往往会通过混合这些方法来在最短时间内确定更好的效果。在这里,我们将虚拟模型先限定于仿真(simulation),而将模拟和FPGA归类为硬件加速技术,我们会在后面的文中主要介绍硬件加速技术。 那么,虚拟建模的优点有哪些呢?
截止现在,虚拟建模仍然是一项不断完善和发展的技术,而它也正在被广泛的运用的芯片设计验证领域中。那么目前主要的虚拟建模平台有哪些呢? 目前工业界一致推广TLM(Transaction Lelvel Models)用来建立抽象层次的模型,而TLM也已经发展到了TLM 2.0标准。主要支持TLM2.0标准的语言有SystemC和UVM方法学。目前主要的EDA厂商都可以支持SystemC的仿真,我们可以将支持SystemC模型的仿真平台分为两种:
那么在这些平台上,虚拟模型大致建立的方式是什么样的呢? 实际上,虚拟模型的建立也类似于硬件RTL的建模,只是从抽象层次上来讲它们提高了,或者从代码量上来讲它们变少了(但不见得变简单了,这要看逻辑实现的细节程度)。由于芯片中各个子模块都会对照着不同的软件驱动库、应用库,我们需要在芯片系统级建模过程中最大限度地囊括所有子模块对应的TLM模型,这样才会提供给软件最大程度上的自由度(即可以将日后为硅后开发的软件先在虚拟平台上测试)。 在虚拟建模平台上,可以通过可视化界面和自动智能的方式将已经准备好的模块进行集成。在集成过程中,我们需要主要讲模块类别按照提供方分为:
如下图,在虚拟模块集成过程中可以从现有库中选择IP: 如果虚拟模块需要用户自定义,那么平台工具也可以通过用户大致定义接口、内部属性来生成框架,而后等待用户去填充该完备的功能,例如下图: 同时,通过可视化窗口完成系统集成: 当通过虚拟建模平台完成集成以后,虚拟系统会完成编译建立模型,进而交付给软件组以供开发,另外软件组的反馈也会报告给硬件设计组。 此外,由于虚拟模型可以考虑作为参考模型参与到RTL仿真中,这种SystemC同RTL的协同仿真模式包括有:
至此我们将虚拟建模的优势和方法大致讲完,目前越来越多的公司都已经应用该方法来尽可能地提前软件开发时间,并在早期反馈给硬件设计。同时,此种方法对于团队学习曲线、如何在旧有硬件设计流程中集成并有效组合、如何考虑虚拟建模在远期价值和人力额外投入的性价比、如何实现虚拟模型团队同设计验证团队的整合等等都是对现有工作方式的挑战,这一点需要团队整体都看到它的优势并且愿意为之改变,才会将它的优势更好地发挥出来。 五、硬件加速 我们之前介绍过的动态仿真和静态检查方法各自具有优势,然而它们都不具备的一个优势在于速度。尤其是在SoC的设计体量越来越大的时候,仿真速度成为制约验证进度的重要障碍。同时,由于仿真速度的限制,一些真实的用例也无法在RTL级仿真很快地呈现结果,这种困难在硅后软件测试发现问题反馈给硅前硬件团队时更加明显,因为通常这意味着硬件团队需要将耗时很长(相对硬件仿真的承受能力)的软件进行分析,找到可能的问题点,拆分软件场景,进而在硬件仿真上尝试重现问题。仿真速度的限制使得在硬件仿真方法上面无法很好地早期测试软件,而这一任务一般交给了另外两种方法:
上一节已经讨论过虚拟模型平台,它的一项优势在于可以在硬件设计之前就用来建立硬件模型,并通过集成来生成虚拟模型平台,当然这也意味着新的工作量和技能学习需要引入进来。那么,对于硬件加速而言,它通常的流程是如何呢?一般需要等到硬件设计初步稳定,进而将其映射到可配置的平台上面,因此设计的数字电路部分可以通过更高的时钟频率(受限的,无法达到真实芯片频率)来仿真。这种方式相比于RTL仿真速度已经有了质的提升,稍后我们会比较速度的提升优势。 目前业界主要的硬件加速方式分为两种,即FPGA和专用的模拟器(emulator)。实际上,专用模拟器仍然是基于FPGA的定制产品,只不过比起商用的FGPA(Xilinx、Altera),它在硬件加速方面还有其它显著的特点:
模拟器的这些特点与FPGA可以很好地区分开来,而在实际工作中,FPGA和模拟器使用的场景也有所不同。FPGA原型验证主要是针对于小型设计或者单独的IP,而模拟器则是用来面向更大更复杂的SoC设计。FPGA主要是为软件开发提供平台,而模拟器则是为了硬件和软件协同验证和整个系统的测试。随着最近10年,模拟平台技术日趋完善和容易使用的情况下,与FPGA相比,越来越多的公司开始考虑使用模拟器,这主要是基于如下的因素:
以下是FPGA同模拟技术的比较: 目前业界的硬件加速标准并未达成一致,主流的三家公司实现硬件加速的具体技术也各有特点。我们在上面提到的模拟器(emulator),通过将设计逻辑映射到可编程单元的方式,主要有Veloce(Mentor)和ZeBu(Synopsys)。 Veloce采用的技术正是我们上面提到的,通过定制的可编程单元(非常类似于FPGA),不同的内部连接网络结构,以及透明的可调式电路实现在该模拟器平台上。平台上的每一块模拟器芯片都可用来模拟一小块的设计逻辑,而整个芯片的功能则是通过集成各个模拟器芯片实现片间快速通信来实现的。 而ZeBu不一样的地方在于它直接采用FPGA,而且通过技术也将透明的可调式电路技术和其它特性实现到FPGA中,多个FPGA进一步来组成完整的芯片功能,这种方式对于用户来看,与Veloce的区别并不大。 在此之外,Cadence公司的仿真加速器(simulation accelerator)Palladium也显得与众不同。它作为独立的加速器平台,内部包括有数量巨大的简单处理器,而每一块处理器又可以来仿真一小块设计的逻辑部分,并且将运算结果在它们之间传递。看起来,这些处理器每一个的运算速度都要低于我们的桌面处理器,但是由于我们通过成千上万个小的处理器并行工作,这使得实际的运算结果要大大高于独立处理器的表现, 同时,这些独立的小型处理器也支持透明化的调试方式。 通过这些模拟器,我们可以主机的验证平台到模拟器的激励场景,同时,假如我们需要设计一个USB器件,我们可能会将物理层的USB与模拟器相连,进而同电脑或者其它器件相连。这时候,我们将模拟器与真实世界的应用器件连接的方式(不同于与主机上的验证平台连接)称作是在线模拟(in-circuit emulation)。随之而来的问题是,一般真实世界的频率要高于模拟平台的频率,这时候我们需要为它们之间频率的差异搭建降速同步的桥接,我们称之为速度桥接(speed bridge)。它主要的功能是通过缓存快速端的数据,进而主动降低快速端的速度,来适配两端的数据率。 如果我们要将RTL的验证平台移植到模拟平台上,我们可以通过可配置平台来仿真待验设计,同时将验证平台运行在加速平台以外的主机上,这种方式被称为联合仿真(co-simulation)。这些激励可以由软件的验证环境从主机给入到可配置平台上面,或者由真实世界的接口给入到可配置平台。另外一方面,硬件加速的方法受到的限制是它们没有办法像RTL仿真一样透明地去观察硬件信号和内部逻辑,也无法很好地去调试硬件程序(例如设置断点)。 在实际联合仿真平台中,加速因子最大的受限因素在于平台外主机的验证平台运行速度,以及它与加速平台之间通信的速度。因此,在构建一个联合加速平台环境时,我们需要考虑的是:
六、效能验证 在PC时代,还少有人将处理器功耗提上验证的日程,因为大家对于处理器性能的关注多于功耗的考虑。在十多年前,大家使用2G的功能手机,“超长待机”一词渐渐被作为主打广告语进入了用户的视线,这得益于硬件本身的低功耗(性能本身不要求太突出)和大容量的电池。而到了智能手机时代,伴随着将桌面办公和娱乐移动化的需求,一部手机承载着以前桌面机的性能。这种要求之下,也催生了智能机市场在过去的几年当中蓬勃增长,因为随着软件性能对硬件的日趋增长的要求,以及移动网络数据传输性能的不断提高,都在促进者硬件性能的层层上升。 在移动时代,硬件提升性能的方式主要表现为以下几种方式
总体上看,随着性能的提升,能耗也会逐步提高,这在过去的PC时代还不是一个显著问题,但是到了移动端的现在,就越发要求硬件不但要求性能有提升,也同时需要考虑能耗是否也可以接受。我们这篇文章主要以移动芯片为例,来讨论目前关于性能(performance)和效能(power consumption)的权衡。 从上面这张移动硬件领域的技术缺口图上可以看出,无线通信技术被标注上了1G、2G、3G和4G。香农定律预测出每8个月传输性能会提升一倍,同时摩尔定律也指出了每18个月晶体管的单位密度会提升一倍因此处理器的性能也会提升一倍。同样地也有对电池生产商每10年左右能源密度提升一倍,而存储器的性能大约每12年会提升一倍。 那么从这张图不同器件的特性增长来看,就揭示了对于耗移动硬件的技术缺口,它们是:
而上面讲述的技术缺口同目前硬件提升性能的方式也大致保持逻辑吻合。我们本篇主要就如何解决能效缺口入手,讲述目前主流的能效验证方式。 功率和能量 首先我们先引入基本的概念,能率和电能在日常器件能效讨论中经常会提起,然而它们是不同的两个术语。 功率 = 能量/时间 (瓦特) 能量 = 功率*时间 (焦耳) 有时候,我们设法降低功率也会随之降低能耗,但这也不是绝对的,例如有些任务在高速高功率情况下可以很短完成,而且效果实际上要比在低速低功率下消耗更长时间的效率更高。又比如,如果静态功耗可以忽略的前提下,如果一个任务需要固定的时钟周期数完成,那么无论时钟快还是慢,它消耗的能量是一样多的;然而,当静态功耗无法忽略的时候(例如目前的工艺制程已大致在10纳米),反倒是时钟更快、动态功耗越高的情况下,完成这项任务更高效。所以,效能的验证和评估实际上就是对能量利用效率的优化途径。 静态功耗和动态功耗 所以从上面的例子,我们知道,如果要考虑功耗,需要考虑两部分,静态功耗和动态功耗,总的功耗表现可以描述为如下 总功耗 = 开关功耗 + 短路功耗 + 静态功耗 这里开关功耗和短路功耗构成了动态功耗的部分。 开关功耗 = C·V^2 ·F C = 负载电容 V = 电压 F = 频率 短路功耗 = V · I (短路) I(短路)为在开关切换过程中N极和P级同时有效时发生的电路电流 静态功耗 =V · I (漏电) 而静态功耗(或漏电功耗)则是晶体管在激活或者保持状态下都会出现的漏电造成的功耗。 节能技术 实际上移动硬件节能(省电)技术是一项全面的流程,从工艺制程、电路、封装到模块设计、SoC设计、系统和应用软件开发等等,整个环节都需要有效利用能量。下面这张图是从芯片硬件和软件所采用的节能技术(省去工艺制程): 同我们之前介绍过的硬件设计流程类似,节能的设计流程也是从规划到实施最后到集成的。面对越来越复杂的系统,实用的方式还是从系统设计开始,逐步分解到电路设计,先从硬件层面考虑如何去实现低功耗设计。 能效验证 我们这里主要针对硅前设计阶段入手,进行能效验证,我们将其主要分为两个部分:
PA(Power Aware)能效设计流程 UPF/CPF这两种功耗格式比较类似,且可以将它们的流程主要分为四个部分:
对于硅前验证阶段,验证人员接触到的主要是RTL模拟仿真,我们一般采取的策略是:
功耗预测与优化 一般我们期望尽早地获取到功耗的估测信息,而这一期望又与芯片开发过程相悖,因为往往在流片以后的软件开发阶段测量出来的功耗是更准确的。但是如果需要等到流片之后才能测量功耗,那么低功耗设计的成本就很大了,因为一方面这使得我们试错的成本增加,另外一方面产品能效优化迭代的周期也变长了。所以,我们希望在硅前设计阶段甚至是规划阶段(TLM虚拟模型)来估测出芯片功耗,已经分析出较降低功耗的设计方法。这里,我们将目光落在RTL和门级阶段,通过现有的功耗设计平台,执行早期物理感知功耗预算与调试、功耗降低分析、电源效率回归分析、以及利用仿真器接口对动态应用进行功耗特性分析。 简而言之,目前这些工具都是为了查看、估计、分析和降低功耗,通过在RTL级和布局后门级功耗数据指标和报告,为设计和验证人员提供调试和追踪功耗的方法。目前主要的功耗预测分析工具有PowerArtist(Ansys)、Spyglass Power(Synopsys)、PrimeTime PX(Synopsys)、Redhawk(Ansys)。而我们在实际项目中通过不同工具的比较,提供了如下的建议: 目前在硅前能效验证阶段,我们相对容易做到的是去采纳PA设计流程,进行相应的RTL仿真和后端流程。在PA验证过程中,我们可以通过熟悉的仿真器进行PA仿真,进而在保证原有功能实现的情况下,进一步检查低功耗逻辑和断电控制功能。而对于功耗预测与优化,目前有几点因素值得考虑:
七、性能验证 在迈过了效能验证的坎以后,我们来到了性能(performance)验证部分。顾名思义,在这部分验证当中我们需要测试芯片的性能,而测试性能又离不开大量的运算或者数据传输。我们之前提到过,硅前RTL验证的瓶颈之一在于仿真速度,而且一旦到了芯片级仿真,这一因素就更进一步放大了。 由于在产品定义过程中,对于系统的运算和数据传输都有要求,如果可以在产品实现阶段尽早地得出一些基本数据,从而为硅后测算出一些性能数据,那么这不但可以帮助提前指明硬件实际性能是否满足,在有时间的情况下对于可以调整的硬件设计还可以做出完善性能的修改,同时,这种将性能测试提前的方式也可以使得硅前验证与硅后测试使用的性能测试用例保持一致,进而得出有帮助的性能数据。 性能验证是用来衡量一个系统在特定工作负载下它的响应能力和稳定性,同时通过性能报告也可以用来分析和优化系统的质量标准,例如可靠性和资源使用能力。性能验证是一门实用的计算机科学工程方法,且在软件工程测试中分类较多,譬如有负载测试(load testing)、压力测试(stress testing)、浸泡测试(soak testing)、尖峰冲击测试(spike testing)、配置测试(configuration testing) 、隔断测试(isolation testing)等。 目前在硅前验证阶段,性能验证还是一个新颖的概念,一方面由于业界对这一测试还没有形成一致的定义和验收标准,另外也是由于性能验证更多地是在衡量测试指标,而与验证(判断设计是否与功能描述一致)本身的聚焦不太重合。但是,对一些性能要求(同样对于功耗要求)较严格的硬件设计,我们确实希望在更早期就得出一些数据,而且最好能够赶得上给设计做出反馈并且完善设计,做更早期的回馈,以此来降低开发成本。所以,这就要求我们能够自己先定义出硅前性能验证的目标、环境和方法。 设定目标 目前我们主要将性能验证主要侧重在负载测试和压力测试上面,来完成下面的目标:
在我们开始性能测试之前,应该首先问一问自己“为什么我们要进行性能验证?”,因为只有朝着明确的性能目标方向,才能得出下面的一些测试数据:
实际上我们很难在性能验证计划中具体描述出测试方式和场景,而性能验证计划又应该列在硬件设计之前。在实际项目中,我们不能很好地知道软件使用硬件的场景,已经应用软件如何调度不同硬件模块,所以我们只能首先将目光着眼于单个子系统的性能测试,或者通过测试单一的数据链路找到最薄弱的节点。因为上面这种方式可以将复杂的问题降维到可以理解可以描述测试场景的难度。 测试环境 理想地来看,如果测试环境贴近于用户实际使用的情况,我们得出的数据会更加真实有意义,然而作为硅前硬件实现阶段,我们与用户的距离又何其远。退而求其次,我们希望可以通过和固件开发团队合作,找到一些典型的子系统应用场景,在硬件仿真上实现来观察子系统的性能。 同时为了将测试的成本降低,我们尽可能选择原有的功能验证的环境,通过动态的环境配置或者仿真开关来实现监视系统性能的组件。这些监视性能的组件可以分为:
验证方法 从性能验证流程来看,目前我们参照微软的性能测试方法学流程,它包括以下步骤:
正如前面提到的,实际项目中的性能测试除了不规范和较难实现意外,也缺少明确的验收标准。这就使得不同验证人员编写的测试用例距离真实情况应用的差别不等,而且检查性能的标准也各不相同。目前,我们通过下面一些形式来帮助实现性能验证:
八、趋势展望 目前主要的验证方式包括动态仿真、形式验证和硬件加速,那么如何选择它们,已经是否可以构建一个可复用的验证平台实现这些不同验证方法的跨越是接下来我们需要关心的。随着设计的尺寸和复杂度在不断提高,即便有IP复用的方式来缩短设计时间,更多模块之间的互动可能性也要求更充分地去验证这些状态空间。目前仿真技术的瓶颈在于速度,随着这几年实际项目中的切身感受,仿真技术除了需要EDA厂商提供加速方式以外,项目自身也需要结合实际情况使得仿真可以实现相对轻量化来保证可接受的速度。 形式验证可以穷尽检验一些设计属性。对于一个合适尺寸的IP,它只需要通过一些时钟周期就可以穷尽检验出设计属性是否满足。例如一个32位的乘法器,如果通过动态验证可能需要几年的时间来穷举出所有可能的情况来完全验证,然而对于形式验证而言,往往几分钟到数小时的时间就可以了。同时,形式验证伴随着设计的复杂度提高状态空间指数增长的情况下,运行速度也急剧下降,IP是合适的形式验证尺寸。 尽管在学术和工业领域,对于形式验证的算法研究非常活跃,它还需要解决的问题是,使用者对于形式验证语言的不精通。因为使用者还需要保证设计属性描述是精确反映实际设计的,同时属性描述的总和可以对等一个设计的所有功能,只有这两点满足了,才有足够信心确信形式验证的完备性。目前我们可以通过EDA厂商提供的可复用的断言库来实现高层次的属性描述,弥补我们对断言描述本身的知识缺乏。此外,形式验证让我们“不那么放心”的一点是,它无法像仿真一样为我们提供一个动态的行为,而验证人员又需要“眼见为实”来亲自判断设计的实际行为是否正确。所以,如果采取形式验证,建议的一种方式为以动态仿真为辅助手段,来完成基本的功能激励和检查。 硬件加速的历史要更悠久,这可以回溯到1980中期到1990中后期,在RTL仿真还未推出被广泛使用之前,占据验证市场的还是门级硬件模拟技术,随着Verilog和VHDL的语言推出和自动逻辑综合技术的应用,RTL仿真就逐渐取代了硬件加速技术。这一技术更迭的背后,关键因素还是速度,因为那一时期的设计还不足以复杂到仿真器性能无法满足的情况。20年后的今天,硬件加速技术显然又有着收复失地的趋势,三大主流工具商都提供各自的硬件加速解决方案。 硬件加速技术的速度优势还是相当明显的。动态仿真的性能平均保持在1KHz,硬件模拟技术大致在1MHz左右,而FPGA在10MHz左右。无论是硬件模拟还是FPGA,都要比动态仿真技术的速度显著提高不少,通过更快速的验证技术,我们也才能够抵消日益复杂的设计,和体量不断增大的嵌入式软件代码测试。 那么是不是硬件加速技术就是未来的主流呢?仍然不是绝对的。目前硬件加速技术也有自己的不足,比如:
这么看来,尽管在速度上硬件加速有显著的优势,但是从调试层面,动态仿真和形式验证也有其优点。那么,实际中我们是怎么结合这些技术的呢?一般我们倾向于以下方式:
从验证平台搭建和复用的角度出发,我们也需要考虑,如何实现一个可以横跨这三种技术的可复用平台呢?通过一个统一平台,如果可以自如地在这三种技术之间实现横向跨越,以及完成从模块级到子系统级再到芯片级验证的复用实现纵向复用,这将是接下来实现技术融合和验证层次复用的方向。为讨论这一方向,我们分别以下列问题展开叙述:
技术之间的横向跨越 在解决横向跨越的问题之前,我们先需要理解为什么有这样的需求?从下面这张图可以看到这三种技术之前有着共通的技术桥接,和一些核心的基础技术:
那么基于这些项目实际中的桥接,如何设计出可以合并的数据库和通用的验证平台就成为了关键。但对于这两点,目前三大工具商还缺乏一种完整的解决方案。例如,验证的覆盖率数据库如何在三种技术中实现互通和合并?如何定义出合理的结构完成形式验证平台到动态仿真平台的复用?以及什么样的动态仿真平台才可以顺利移植到硬件加速平台上呢?这些都是还有待思考解决的问题。 层次之间的纵向复用 在不同验证层次之间的复用,我们也会遭遇到实际的痛点。例如,随机约束的仿真方法(SystemVerilog,UVM/OVM或者Specman/e)适合于模块级和子系统级验证,而直接测试方法(C/C++)则适用于子系统级和芯片系统级的验证过程。在这里,我们看到了子系统级验证有着两种可能的验证方法,我们需要考虑是否选择其中一种,还是两折兼具?如何实现模块级随机测试到子系统级随机测试的复用?如何实现子系统级直接测试到芯片系统级的直接测试复用?又譬如通过何种方式实现从随机约束测试到直接测试的复用?因为只有完成了层次之间的纵向复用,我们验证的是时间成本和人力成本才会降低,验证效率才会进一步地提高。 面临这目前这三种主流验证技术,我们需要从验证效率出发,只有通过合理地选择使用这几种技术,并且实现技术之间的横向跨越和层次之间的纵向复用以后,我们才有可能在不断提速的SoC集成设计过程中也保持加速,与设计实现共同飞跃。 至此,我们关于《验证的方法篇》就结束了,到了下一个新篇章,我们将为你带来《验证的计划篇》,欢迎你们的订阅和传播!
|
|
来自: 晓理晓章 > 《路科验证(转帖)》