EDA/IC设计
0 绪论
验证,顾名思义,看看做出来的东西对不对,通知以及说服设计人员,把BUG改掉。
其实看一家芯片公司靠不靠谱可以从他们的芯片验证是不是专业来判断。部分人对芯片的验证映像还停留在让设计人员写几个testbench自己测一下功能的阶段,实际上芯片验证是一个非常专业化、体系化、有自己独特技术栈的工作。芯片的验证和软件的验证最大的一个区别我想应该是责任的区别,软件验证放走一个BUG大不了下个版本修改好,芯片验证如果放走一个BUG一旦流片可能就没有补救的机会了,属实是责任重于泰山,压力山大。
验证的主要内容我们按阶段分ESL, EDA, 硬件辅助验证来讲。
1 ESL建模验证
1.1 ESL简介
ESL是electronic system-level languages的简称。广义上来讲,ESL建模也算是验证工作的一部分。主要是用C模型来验证芯片的行为,以达到快速debug的目的。ESL一般只在超大的芯片公司有独立的团队,大部分公司由设计或者验证人员来完成,或者干脆不做。ESL验证一般用system C设计ESL平台。system C可以理解为一个C++类库和一堆宏,方便模拟硬件的并行操作的。ESL建模从芯片设计的很早期就可以开展。此处我们简单讲讲几个步骤。
1.2 建模步骤
建模大致分为5种model,由上到下逐步细化即可,按需实现即可,其实也不需要全部实现。
Spec Model如上图,最先设计的是spec model, 这个步骤主要就是搞清楚算法链路是不是能实现功能。其实和算法链路区别不大。功能块之间的交流直接用全局变量就搞定了,只能验证一下功能,不能验证芯片行为。
Architecture Model在spec model的基础上继续细化。根据设计人员的架构设计讲ESL也按架构分开。模块之间的数据交换也用variable channels (system c提供的类库,可以很好的模拟interface行为)。这个步骤可以验证大的模块之间的接口不会出错。
Transaction Model主要是将BUS连在了一起。这些模块之间不再是两两互联,而是根据架构设计通过BUS Arbiter连接。需要注意的是这个地方Arbiter还是功能级的实现。这个步骤可以验证地址空间是不是对的,互联是不是通的等等。
Behavior Model主要是对总线进一步细化,模拟真实的总线行为。一般ESL验证到这个步骤就可以停了,后续交个EDA验证去搞定。
Cycle-Accuracy Model最后一个模型,cycle级精确的模型。进一步细化behavior model,将每个信号给出时序就能出cycle accuacy 精确的model。可以逐cycle比对行为。但我觉得这个模型太细致了,开发量也不小,没必要。直接开发到behavior model或者transacation model即可,cycle accuracy model交给EDA验证。
ESL验证的一个好处是可以逐步细化你的验证平台,在比较早的时候就发现问题,不要等代码都写完了以后再发现问题。建议做到architecture model或者transaction model, 可以很好的利用C++快捷的特点加速芯片收敛。
2 EDA验证
接下来我们就到了EDA验证阶段。这个阶段是验证的重中之重。ESL模型总归是建模,EDA验证面向的是真正用于综合的RTL代码。为了让大家对测试有个基本认识,我们先讲方法与平台,然后讲讲验证的几个重要阶段。主要内容如下。
2.1 验证方法
广义的验证方法有很多,比如上一章讲到过的Spyglass也可以叫做一种静态验证。此处我们讲讲EDA验证中狭义的方法。主要包括三方面的内容,验证的手段,验证的透明度和如何评估验证的进度。
从验证的手段来讲,主要有三种
·断言测试, assertion check。这个主要是对模块的输出或者中间变量做一定的预设,比如状态机就该如何跳,输出就应该是符合标准协议的。一旦不符合立刻就能发现错误。这个部分适用于测试的最早期,能快速的发现问题。写C++的时候这个其实由设计人员顺手就写了,随手就一个断言,保证自己的程序和预期一致。写RTL的话断言一般还是由测试人员写在测试的平台了的,不会直接插入到设计代码里(可以插,但是不建议)。
·定向测试,directed test。测试的输入都是提前定好的。验证人员通过设计需求分解的测试点,或者叫测试用例。定向测试主要运用在测试的早期,用来测试基本功能。
·随机测试,random test。输入的序列是随机的,然后测试输出的结果是不是对的。随机测试一般在定向测试结束以后开始的。一般来讲随机用例会监测一下覆盖率,覆盖率达到要求就可以停下来了。此处也有一种每日回归的提法,验证人员每天晚上跑上测试(包含了随机和定向),早上发现BUG以后报告设计人员,设计人员修改BUG,下班之前提交一个版本让验证再跑一晚上。如果不在意电费的话当然是随机跑的越多,发现BUG的概率越大。但是每日回归对设计人员和测试人员压力都比较大。work life balance是别想了。
从透明度上来讲,主要有三种透明度。
·白盒测试。白盒测试相当于设计人员了解设计细节。上面讲的断言测试一般就是白盒的。白盒测试的优点是对问题的定位其实是比较快的,适用于测试的初步阶段。但白盒测试也有自己的一些问题。第一个问题是验证可能和设计错成一样的。验证人员由于知道全部的设计细节,自然会收到设计思路的影响,从而让验证错成一样的问题。第二个问题白盒测试验证环境高度依赖于设计,不同版本之间其实很难复用。
·灰盒测试。介于黑盒测试和白盒测试之间的测试方法。主要用在集成测试里面。不知道子模块的具体行为,但知道互联的细节。其实我觉得更偏向白盒测试,只是白盒子里面的子模块是黑的而已。
·黑盒测试。黑盒测试验证人员应当完全不了解内部实现。只关心输入输出。测试人员给若干输入,看看输出是不是都对。黑盒测试的优点是更加贴近使用场景,容易发现比较重要的BUG。但也有问题,一旦发现了BUG定位是比较麻烦的,而且黑盒测试的输入不一定能覆盖各种情况,有可能有漏测的情况。
实际上,为了最好的验证效果,验证在不同阶段使用的手段和透明度其实是不一样的。
上面讲的都是验证的手段,此处还有一个主要问题要说一下,怎么确认验证要停下来了?毕竟除非你能把所有输入情况都试一遍,否则没办法打包票验证就一定完成了。所以我们需要一些指标来指导我们验证是不是充分了。
·回归测试通过率。测试中我们会把典型场景的输入作为一个用例集,每次修改源代码都会回归一下。通过样例数/总样例数=回归测试率,回归测试率显然是要求100%的,如果有样例都通不过测试,说明代码有功能问题,不可能拿去流片。
·功能覆盖率。功能覆盖率主要指的是各项功能是不是一一验证过了。验证人员逐一验证设计需求。功能覆盖率也要求100%。否则相当于有功能没有经过验证就直接拿去流片了。
·断言覆盖率。断言是不是都被执行过。不一定要达到100%,有些断言可能确实也没什么用。由于断言本来就是验证人员加的,如果确认就是执行不到的断言删掉即可。
·代码覆盖率,代码覆盖率是软件测试中经常用到的手段。芯片测试里也会用。这些覆盖率不要求100%,因为有些情况确实靠构造用例很难构造出来。一般应该会要求95%以上即可,(有段时间在互联网公司写C++的时候覆盖率要求貌似是99%以上,RTL代码要求理论上不需要这么严格)。里面又细分为
-语句覆盖率。每一句RTL是不是被运行过。
-条件覆盖率。每个条件是不是都执行过成立和不成立。特别是或的情况。if (cond a || cond b)这种语句,cond a和cond b是不是都验过了。
-决策覆盖率。指的是if和else块是不是都运行过了。(你可以想想决策覆盖率和条件覆盖率有什么区别)。
-跳转覆盖率。各个信号是不是都从0到1跳变过。
·缺陷曲线。评估验证是否完全的一个重要工具是缺陷曲线。缺陷曲线Defect curve长下面这样。一般来讲,测试活动全面铺开以后每天都会统计测试出的BUG。可以根据曲线的斜率变大还是变小确定测试活动是不是在收敛。最后一定要曲线收敛。当然,即使曲线收敛了也不能保证100%就没问题。曲线收敛了有两种情况,一种是没有BUG了,一种是测试质量不过关,压根就发现不了BUG。比如曲线看着收敛了,但是还是发现了最基础的BUG,这种情况可能就是伪收敛的,需要重新检查缺陷质量。
2.2 验证平台
上面讲了一堆方法上的东西,我们还缺一个东西,如何把方法实现。EDA验证我们用的语言一般是System Verilog,为了提高重用性,大量使用了面向对象的设计方式。还是那句话,没必要重复造轮子。目前业界最常用的一套轮子是UVM (The Universal Verification Methodology)。虽然名字叫方法学,其实就是一套用system verilog写的库以及基于这个库的一套验证框架,方便验证的时候使用。
UVM主要的优势:
·提供可重用的的组件以及可分层的组件
·面向对象,各个组件之间可以并行开发,耦合比较小
·各个组件通过configuration可以很灵活的使用
2.1.1 UVM的整体框架
UVM的整体框架见下面的图,UVM内部的东西非常多,此处只是介绍个大概。其实大部分的验证框架都是这个图。DUT是我们要测的模块,用TX ENV产生输入激励,从RX接收到DUT的计算结果。在Scordboard比对一下结果。判断用例是不是执行正确了。
需要注意的是这个图可能会产生部分误解。TX Agent和RX Agent都复用了agent, 但实际上在最简的测试系统中,RX中的sequence, driver可能没有, TX Agent的Monitor可能也没用。实际上变成下面的一个形式。
其中sequencer是产生抽象序列的类,driver是真正的生成pin信号控制dut, monitor接受信号。scoreboard比对信息。reference model (RM) 通过in_agent给出的激励,通过算法链路生成结果,最后和dut的结果比较。
和其他开源框架比如LLVM一样,UVM运行也是分阶段的。
主要就是上面若干阶段。其中build, connect, start_f_simulation其实需要我们干预的比较少,我们主要是要重载若干run里面的函数。run里面又分为reset, configure, main, shutdown四个阶段。后面有check, report, final阶段,都好理解。
2.2.2 UVM的主要机制
UVM区别于手撸的System Verilog验证环境主要是几个机制起作用。所以对几个机制也要有一定了解。UVM的新机制还是比较多的,此处我们只介绍几个最基本的。
机制1:Factory机制。这个和我们软件工程里面的函数工厂或者对象工厂其实是一个意思,UVM会通过uvm_components_utils的机制把我们写的组件注册到一张表中,我们需要使用的时候直接使用名字字符串为索引创建出相应的对象。(emmm, 此处突然想卖个关子,大家可以想一下UVM为什么采用了Factory机制获取对象,而不是直接采用类的构造函数获取对象^^)
factory采用下面的方式注册。
使用的时候就比较简单了。
机制2:Config机制。
Config机制主要是为了改变testbench的配置项,生成各种不同的激励。UVM区别于SV的另一个重要的机制是config机制。这个config从顶层一直往下传导,各处都能访问到,类似一个config-hub。对于硬件设计和测试来讲这种方式确实还是可以省去很多麻烦。后面chisel的config设计其实也和这种config是同一个思路,只是进行了扩展。
用set或者get配置、获取参数。
static function bit get( uvm_component cntxt, string inst_name, string field_name, inout T value )
机制3:TLM机制。
这个机制主要是为了专门做一个模块,在不同模块之间传数据。比如monitor向scorebord传数据。简单理解为port分装。
PORT又分为port和export。其中PORT是主动端,写入数据用PUT, 读出数据用GET。这种交互主要是为了数据隔离,避免意外的数据改动。
机制4:Sequencer机制
看这个图,driver是真正驱动DUT的模块,而给DUT提供数据的是Sequencer。sequencer相当于一个数据队列,存储着一包包的数据,按包发给driver, 然后driver再解析包,解析成具体的驱动信号。之所以加入sequencer的一个很大的原因是隔离DUT业务。假如DUT的端口变化了,我们只需要改动driver, 不需要改动其他东西。
2.3 验证阶段
上面讲了验证方法和验证平台,此处我们开始讲讲验证的阶段流程。由于现代芯片越来越复杂,验证一般要分层次。常见的测试和软件测试活动其实类似,分为UT, IT,ST。比如我们简单画一个AI SOC。
·UT(Unit Test)测试:测试功能模块是不是正确的,比如CNN CORE, RISC-V CORE就是一个UT。UT层面基本上可以白盒或者灰盒测试。主要测试单元模块的正确性,包括内部状态机是不是正确的,数据处理是不是正确的等等。由于这个层面的测试和设计功能实在是耦合有点紧密,可以由设计人员自己完成UT测试,当让也可以测试人员来搞。
·IT(Integrated Test)测试:测试子系统。比如AP子系统(Application Processor), 里面的core, cache, DMA是不是联合起来能工作正常。理论上来讲IT测试出的问题应该主要在各个UT之间的交互上,但实际上也可能发现UT内部的问题。IT测试一般是灰盒和黑盒的。主要有测试人员来做。
·ST(Sysem Test)测试:这一个层面的测试主要是芯片整体层面。整个芯片的子系统是不是能很好的配合运行起来主要靠ST来保证。ST测试的重点是真实场景下的用例。基本都是定向测试,最好把实际芯片用的各种情况都模拟一遍,以防出错。
UT划分比较清楚,IT和ST划分其实没那么清楚,所以有个概念即可,验证实分层做的。
3 硬件辅助验证
EDA验证由于软件其实对于跑一些大型测试是比较慢的。归根结底EDA用CPU来算,CPU就不适合算这种高并发的计算任务。所以在验证的最后阶段,往往还有用硬件辅助验证查漏补缺。
硬件辅助验证大约就两种,第一种是FPGA搭原型。这个容易理解,将你写的芯片先烧到FPGA上看看能不能跑起来,这种验证可以验出一些芯片接口的问题,但也有缺点,一来,芯片里面一些东西是没办法综合到FPGA上的,所以只能写一个假的模块用来验证,二来,随着芯片规模的变大,FPGA不一定放得下芯片,可能需要并联两块甚至多个FPGA,搭建这样一个平台也不容易。FPGA一般用xilinx家的ultrascale。这个东西听说国内不一定买得到了。
第二种是emulator。这种东西可以理解为一个仿真波形的加速器。Cadence Palladium, Synopsys ZeBu, Mentor Veloce都属于这类emulator。贼贵。Mentor Veloce长这样的, 放在数据中心。用户租用软件就可以。
不得不说,这三家EDA厂商为了验证芯片真的是什么招都想出来了。
4 总结
验证部分的内容到此就介绍完了,也只是个框架,实际上远不止这些内容。验证在芯片里属于一个系统工程,主要解决的是如何用最小的代价让芯片出错概率最小的问题。此处主要讲的是前端验证,后续做完版图还会后仿真一下,后面再提。大部分BUG应当都能在EDA验证给找出来。
编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !