芯片验证的方法篇(上篇)(良心大作,验证必看)

本篇为作者验证系列之验证的方法篇,该验证系列还包括:

芯片验证全视

芯片验证的策略篇

芯片验证的方法篇

本文分八个部分:
上篇:

验证的方法篇之一:动态仿真

验证的方法篇之二:静态检查

验证的方法篇之三:开发环境

验证的方法篇之四:虚拟模型

下篇:

验证的方法篇之五:硬件加速

验证的方法篇之六:效能验证

验证的方法篇之七:性能验证

验证的方法篇之八(终):趋势展望

芯片验证的方法篇(上篇)

验证的方法篇之一:动态仿真

(博客链接:http://www.eetop.cn/blog/html/28/1561828-438525.html)

从这一季开始我们进入了《验证的方法篇》,之所以单独分出一季来介绍验证的方法和工具,一方面是目前验证方法的分支和其工具种类繁多,另外的是希望读者可以在系统了解了验证的工具库之后,在验证设计的时候首先有一套工具箱,而后再根据设计的特点将其结合不同的验证方法和工作,最终取得满意的效果。

从Wilson 2014年调查数据来看,验证占据了主要的人力资源,同时也是设计能否达标低缺陷率的主要保障。从2007年到2014年的增长趋势来看,由于设计的复杂度逐年攀升,与之带来的验证压力和实际人力资源配置都相应提高。除了人力的投入,设计自动化(DA,design automation)工具关于验证的方法、特性、性能提高都在协助验证人员来面对新的验证挑战。

到了目前的阶段,已经没有一种单一的工具、语言或者方法可以提供用来实现验证完备性。实际的验证工作中,我们需要通过多种语言、方法、脚本、工具最终达到验证的的目的。这些不同的语言、方法、脚本和工具之间没有绝对的优劣,比如仿真验证方式会协同形式验证方式一同来完善功能覆盖率,也有可能通过不同语言的脚本之间的整合来最终完成一项验证流程。总而言之,作为一名有经验的工程师,他需要在掌握现有的各种方法和工具的前提下,通过合理的选择,最后“保质高效低耗”地完成验证任务。

所以,我们将根据验证的方法分为若干类为大家梳理目前主流的验证方法和工具。这些主要的验证方法可以分为:

  • 动态仿真(dynamic simulation)

  • 静态检查(formal check)

  • 虚拟模型(virtual prototype)

  • 硬件加速(hardware acceleration)

  • 电源功耗(power consumption)

  • 性能评估(performance evaluation)

在此之上,我们额外引入一篇开发环境来将日常的编码环境与大家介绍,所谓工欲善其事,必先利其器,有一个应手的开发方式,也是迈向高效率的一步。


这一篇我们为大家带来日常最常见的验证方式——动态仿真(dynamic simulation),该方式其实就是通过测试序列和激励生成器给入待验设计适当激励,结合时间的消耗,进而判断输出是否符合预期的。简而言之,我们需要仿真器来配合这一项工作,验证人员也需要通过查看比较结果、仿真波形比对最终来判定测试用例是否通过。如果按照激励生成方式和检查方式的不同,我们又可以将动态仿真中的验证方式分为:

  • 直接测试(directed test)

  • 随机测试(random test)

  • 参考模型检查(reference model check)

  • 断言检查(assertion check)

由于参考模型一般都会伴随着直接测试或者随机测试,所以我们接下来带着大家着重了解这三部分:直接测试、随机测试和断言检查。

直接测试

直接测试指的是激励的值在仿真之前已经决定下来,测试用例给出的激励序列会在下一次重新提交任务以后保持不变。我们日常会通过C/C++/汇编代码来实施测试用例,该场景最常见的是SoC子系统级或芯片系统级的测试,因为待验设计一般会包含处理器在期中,而且根据硅后测试复用的角度,我们也倾向于运用C代码来编写测试用例。

从下图中可以看出,测试用例经过编译、二次映射成为硬件存储器可以读入的镜像文件(一般为二进制文件,主要包含地址和数据两部分)。待验设计经过上电复位(power up and reset)以后会从存储器中读取二进制文件,进而处理器会将二进制数据译码(decoding)为指令和数据进行运算或者寄存器访问。而最终的数据比较分为两种情况:

  1. 通过内置的C代码进行数据正确性检查

  2. 通过外置的参考模型或者其它检查器来进行信号一致性检查

有时候我们也会考虑直接将第三方提供的可执行文件或者预先映射的二进制文件作为激励源交给存储器,这就跳过了C代码编译的步骤,也需要额外的运行环境兼容措施。

我们将上述的直接测试的流程对照到实际项目中,如下面这个例子,测试用例可以通过C代码交给处理器,进行硬件行为的仿真检查。如果在模块验证环境中缺少处理器,我们如何在这一级实现C代码的垂直复用(从模块级到芯片系统级)呢?可以考虑下面的步骤:

  1. 将C代码交给转换器将其转换为文本命令格式

  2. 文本命令格式可以被总线翻译器识别进而转换为总线上的读写操作

上面的步骤中需要引入转换器实现复用,我们也可以考虑将转换器和总线翻译器结合成为SystemVerilog C-DPI的形式来将翻译层通过标准的C-DPI接口实现更多的复用性。关于SystemVerilog C-DPI的实践方式我们会在后面的篇章《SystemVerilog实战点全讲》里跟大家详细讨论。

直接测试的运用场景一般会在模块测试的早期或者在系统级芯片测试场景中,它适合于测试待验设计的基本功能,且能最直接地翻译出验证人员想要的场景,而它的缺陷也较明显那就是,每一个直接测试用例在通过之后的重复仿真是冗余的,因为这不会提高更多的覆盖率,也无法产生新的测试序列。不过也正因为它的激励序列确定性(determinacy),直接测试有时候可以构成基本测试表来在验证前期保证设计的基本功能。

随机测试

与确定性序列相反的则是随机序列(random sequence),随机序列通过预先定义的约束每次随机产生合理的数值,进而通过激励产生器给出测试序列。下图可以说明,与直接测试相比,随机测试用例可以直接通过激励生成器转化为测试序列。

产生随机数的方法有很多种,有很多语言可以实现,但是考虑到灵活地给随机绑定一些约束的时候,我们需要特定的语言提供这样的属性,目前常用的语言有SystemVerilog和e语言。从下面Wilson 2014年调查数据来看,SystemVerilog的 使用率大致已经上升到了75%以上。

约束实际上是随机激励能否符合接口协议,以及朝着验证焦点而去的关键。随机约束生成器一般可以通过静态约束或者动态反馈约束来给出每一轮的激励。从下图可以看出,在实际的验证环境中,往往有很多对随机约束起到控制和反馈的因素,它们分别是:

  • 静态随机约束:即默认的约束,一般是同激励一起定义的,不会随着测试而变化。

  • 反馈的动态随机约束:在测试的过程中通过上一轮的结果来对下一轮随机序列给予反馈,通过额外的定向约束(biasing constraint)给出更小的随机域(random region)。

  • 待验设计的功能验证开关:待验设计的功能点有时候可以通过测试序列来关联,进而从该序列是否要验证某一项功能来决定某一组随机约束是否生效。

  • 激励的结构成员:随机激励的成员构成,一般分为接口成员(跟设计交互),和成员间的逻辑变量(决定成员之间数值关系的变量)。

  • 验证环境的配置参数:验证环境如果是可以配置的,那么这些配置参数也可能会影响序列的产生。

  • 验证环境中不同激励组件之间的同步通信:如果验证环境中包含多个激励组件,那么如果要实现这些随机组件之间的协同,我们就需要考虑它们之间实现同步通信(synchronization communication)来实现激励组合之间的合理性。

基于覆盖率驱动的随机验证

目前常使用的一种随机验证方式是基于覆盖率驱动的,而这种方式也同我们上面提到的影响随机生成的因素“反馈的动态随机约束”一样。从下图可以看出,与常用的随机约束验证方式不同的一点是,覆盖率收集器在每次测试中都会通过监视器来收集覆盖率(主要指功能覆盖率),将其与已有的覆盖率数据库进行合并,同时根据现有的覆盖率数据库来为下一次随机约束给出反馈。这些正向的反馈就是用来进一步缩窄随机约束域,使其能够定向产生一些序列来覆盖那些未知的功能测试点。

基于TLM的随机验证

对于测试用例而言,它可以指定每一次激励的数据内容,也可以在较高层次上指定每一次激励数据包(data packet)的内容。我们在之前《设计的流程》中就介绍过用TLM建模来在产品定义早期对设计建立模型,而TLM本身是就模型层次而言,它在更高一级用来描述设计或者验证环境。对于基于TLM的随机验证方式,它指的是在随机环境中使用到的最小颗粒是TLM级别的数据包。该激励数据包中不只是包含一个时钟周期内该给出的激励,而是在更长的时间范围(一般为一次完整的数据操作,例如完整的数据读写或者完整的数据包传输)将使用到的数据都加以定义。

通过TLM级别的验证方式带来的好处是验证人员可以更为便捷地描述一些测试场景,更加贴近于真实的用例。这也是因为真实的用例,例如硅后系统测试和固件开发时基于系统级别的高层次,它们专注的并非某个模块的某一项功能,而是关注于某个子系统或者整个系统的联合工作模式。

从下面这张图可以看到,TLM测试用例由于抽象级较高,需要有TLM2RTL激励生成器来做进一步的转换。我们将TLM激励生成器进一步放大以后可以看到它内部的一些转换模块,包括读写操作、复位操作、中断操作还有其它操作。这些方法一般都是根据TLM操作命令经过翻译来使用的,我们将这样的激励生成器称之为总线功能模型(BFM,bus functional model),它的作用就是将高抽象级的TLM命令转换为低抽象级的硬件端口时序。进一步看,在高抽象级到低抽象级的转换中,除过数据抽象度是在降低以外,激励所用的时间也在转换中被实现加注到待测设计接口上面了,因此要完成一项TLM命令的转换,经常需要数十上百个时钟周期。

断言检查

影响验证产出的一个重要因素是如何将功能描述部分准确地描述,因为准确地描述可以帮助验证人员更方便地去翻译功能描述文档。而对于设计人员而言,他们也需要去捕捉各种可能设计行为来证明设计符合预期。断言(assertion)就提供了这样的特性,它善于针对某一个特定的逻辑或者时序进行预设,一旦设计的实际行不符合断言的描述,则会给出检查报告

断言本身不限定于某一种语言或者工具,而是就它的特性来讲,它可以准确地描述出设计的预期行为。所以有多种实现断言的方法和工具,在近来的20年间,这些被业界支持的基于断言的验证方法和工具如下图所示,在这里我们按照断言方法不同的运用过程可以将它们分为如下几类:

  • 商业开发的断言IP,可用来插入到HDL中做检查,例如CheckWare(0-In/Mentor)。

  • 专门开发的断言语言,例如PSL(Property Specification Language)。

  • 广义的验证模块,不依赖于特定的语言或者工具,例如OVL(Open Verification Language/Accellera),这些验证库中含有多个常用的验证模块,可以用来在设计中例化。

  • 根据广义的验证语言描述而使用其他语言实现的验证库,例如在按照OVL来实现的QVL(Questa Verification Library/Mentor)和OVA(OpenVera Assertion checker library/Synopsys)。

  • 扩展某一种语言的特性,延伸出断言的功能,例如SVA(SystemVerilog Assertion)。

由于断言的使用可以分为在验证平台中和插入到设计中,这也使得断言可以同时为验证人员和设计人员所使用。使用断言的优势在于以下几个方面:

  1. 由于断言的位置更贴近于不同功能点的源码位置,这使得一旦相应检查的功能点发生错误,可以更快更清晰地定位出错误源

  2. 断言自身可以表达更长的时序,覆盖任意长度的功能时序,这就使得它可以在更高的抽象级别来描述设计行为

  3. 断言也有覆盖率的功能,通过断言覆盖率可以建立量化数据来衡量验证进度。

  4. 由于断言可以被直接置入到设计中(无论是设计人员置入还是验证人员置入),这都使得断言可以在不同的层次上得到复用,这使得它有更久的生命周期和验证延展。

这里谈到了断言的复用性,实际上断言的应用场景非常多,且它自身便捷的即插即用的特性使得有多种可选的商业断言IP。下面这个例子用来说明断言运用的场景以及它可以垂直复用的特性。

从运用场景来看,典型的断言场景可以包括:

  • 集成连接:例如片上网络多个发起端和目标端之间的访问路径检查,或者系统集成中各个模块之间的连接关系。

  • 总线协议:针对工业标准总线,有商业验证IP可以协助准确验证设计是否按照总线协议实施。

  • 仲裁机制:仲裁机制中的各种类型通过检查来保证仲裁执行合理。

  • 数据一致性:对于存储单元,数据的一致性检查可以通过检查端口读写来预期数据的一致性。

  • 数据进出:对于队列设计,断言也可以建立模型来检查。

  • 状态机:检查状态机的跳转是否正常。

  • 输入限定:基于假设的输入限定也可以通过输入端的断言来判断输入首先是否符合预期,这对于错误源排查也有帮助。

  • 自定义断言:用来检查各个设计的细节,通常这些细节属于设计人员和验证人员关注的功能焦点。

从复用角度来看,断言可以实现从模块级到子系统级再到芯片系统级的垂直复用。从上图可以看出,从单元1在模块级验证时插入的断言“数据进出”和“状态机”两部分在子系统级和芯片系统级两个环境都可以保持监测检查的状态,这一点要归功于断言可以作为非综合模块被置入到设计中,或者通过绑定的形式作为模块并行于设计进行例化(同时不影响设计结构)。而在子系统中,新的断言部分“子系统集成”又可以实施用来检查从单元1从单元2之间的集成关系,这一关系检查在芯片系统中也可以继续保留下来。

至此,我们将动态仿真验证的方法介绍完了,在今后更多的篇章中还将对这些主流方法进一步讨论。下一篇将会同大家一起领略《静态检查》的魅力。

验证的方法篇之二:动态仿真

(博客链接:http://www.eetop.cn/blog/html/28/1561828-438526.html)

与动态仿真相对的是静态检查,它本身不需要仿真、波形激励,通过工具的辅助,验证人员即可以发现设计中存在的问题。静态检查方法较为分散,且关注的验证领域也不为一致,我们将目前主要的方法概括为:

  • 语法检查(syntax check)

  • 语义检查(linting check)

  • 跨时钟域检查(CDC,cross-clock domain check)

  • 形式验证(formal verification)

语法检查

如大多数编译器(compiler)自带的功能一样,各种硅前验证的工具一旦需要建立模型(无论是针对动态仿真还是静态检查的模型),都需要其编译器对目标语言提供语法检查。对于硅前阶段,各种编译器带来首要的好处是帮助检查明显的语法错误,例如拼写、声明、引用、例化、连接、定义等等常见的语法错误

不同仿真工具对于同一语言标准的解释和理解也可能存在偏差或者不同的严格程度,所以在使用不同厂商、不同工具提供的编译器时需要注意的地方包括

  • 理解不同的语法格式或者实现途径,可能在编译器A面前可以通过,却不见得在编译器B之前可以通过。这种差别通常来讲,跟仿真器的特性和支持也有关系。如果在同一个硅前周期使用了不同的工具,那么我们要做的应该是让目标代码(无论是设计代码还是验证代码)满足所有工具的要求,确保它们跟工具之间良好的语法认可度。

  • 由于语言本身也有不同年份的标准,所以我们需要在编译过程中注意加注不同的选项,例如如果默认编译器按照VHDL93标准来编译VHDL文件,那么要显式地声明VHDL文件是87格式,需要额外加注编译选项。

  • 除过语法检查,编译器选项中也会包含一些检查设计代码风格是否符合可综合规范,建议在编译阶段加上这些选项,它们会帮助检查设计中较明显的漏洞

  • 对于SystemVerilog,值得注意的是,最新的SystemVerilog2012中的标准并没有全部被编译器支持,而且不同工具的支持程度也是不尽相同的。如果你在使用一个看起来较“偏门”的功能,在实现它之前可以查看一下工具支持文档,或者看编译器的编译结果来查看是否被支持。

对于初步认识仿真工具的人而言,可能不同编译器对于同一项语法错误给出的错误提示也不相同。这里我们能够给出的建议是:

  • 认真阅读错误信息。没错,请你认真阅读错误信息

  • 在认真阅读无果的情况下,根据错误信息的代码可以通过工具命令结合错误代码来查看错误信息的具体解释

  • 如果你对前面两个步骤仍然免疫,请找一位更有经验的领路人帮你一起检查错误,并且给你一些如何阅读错误、查找语法错误点的方法

语义检查

语义检查和语法检查相比,是在设计可行性上做深入检查的(当然前提也是首先通过了语法检查)。语义检查是通过专用的工具来协助完成的,例如0-In(Mentor)以及Spyglass。常见的语义检查包括的范围有:

  • 常见的设计错误

  • 影响覆盖率收敛的问题

  • 可能会产生‘X'以及受其影响的设计部分

进一步细化这些检查项,它们会检查设计的这些部分:

  • 验证收敛性检查

    • 无法达到的逻辑部分

    • 无法跳转到的状态机状态

    • 无法完成的状态机跳转逻辑

  • 硅效用检查

    • 寄存器被固定赋值

    • 寄存器未初始化

    • X值的传播

  • 功能问题检查

    • 状态机检查

    • 总线检查

    • case语句检查

    • 数学逻辑检查

这些静态检查最大的便捷在于,一些功能实现以外的设计问题可以在更早期就被发现,而且这些静态检查也有助于完善设计编码风格,使其更有助于覆盖率的收敛和后端综合以后的逻辑实现保持(例如寄存器未初始化或者固定赋值)。语义检查最明显的两个优势在于:

  • 不需要验证环境:即无论设计人员还是验证人员可以几乎同设计同步来检查设计中明显的设计问题,这对仿真之前扫清明显障碍、保证设计质量很有帮助。

  • 不需要写断言:这跟我们接下来介绍的形式验证方式有关。由于语义检查无关乎设计从功能描述到功能实现的翻译准确度,所以也就无需要断言参与进来。

跨时钟域检查

大多数复杂的设计都拥有不止一个时钟,而且多个时钟之间也是异步的关系。对于设计中的不同功能模块如果被不同的时钟驱动,那么就会形成不同的时钟域(clock domain)。对于单一时钟域的设计而言,它的设计方式和验证环境都较为简单。而对于多时钟域而言,不同时钟域之间的逻辑通讯就需要考虑同步问题了。在这里,用来验证这些设计要求的过程就被称为跨时钟域检查。

之所以需要同步是由于不同时钟域的时钟是异步的关系,这使得从时钟域A的信号进入时钟域B被采样时,每个周期都会有相对时钟B不同的延迟,这种随机性可能会导致建立或者保持时间无法满足(setup timing or violation timing violation),进而导致不可预期的功能失败。

这种跨时钟域问题无法通过常规的验证方法分析,例如动态仿真,也不能被静态时序分析(static timing analysis)判断出来。而这里通过静态的跨时钟域检查就可以分析这一问题。通过该方法可以在早期的RTL阶段来识别出跨时钟域的通信电路上面是否有合适的同步处理。

所以跨时钟域检查(CDC)是为了保证所有的CDC信号都能够得到正确的同步,而进一步来看,CDC检查是为了解决更大的问题:

  • 是否CDC信号同步逻辑防止数据在跨时钟域采样以后不准确?

目前支持CDC检查的商业工具有Spyglass、0-In(Mentor)。

形式验证

形式验证分为两种方式:

  • 等价检查(EC,Equivalence Check):用来保证两个电路的行为是等价的,可以用来检查不同抽象级的电路是否是一致的,例如RTL级和网表之间。

  • 属性检查(PC,Property Check),又称之为模型检查(MC,Model Check):电路的行为通过验证语言来描述其属性(property),随后通过静态方式来证明在所有状态空间下都满足该条件,否则举出反例(counter example)来证明设计行为不符合属性描述(property description)。

我们在这里介绍的是属性检查,即通过验证语言(PSL、SVA)来描述设计行为,用断言(assertion)的方式结合设计源进行检查,来证明设计行为同属性描述保持一致。属性检查的流程通常如下:

在动态仿真验证中,我们是通过生成各种测试序列来去访问待验设计中的状态(state)的,而理论上所有可能仿真的设计状态被称作可及状态空间(reachable state space)。对于动态仿真而言,要遍历可及验证空间的所有状态是一项非常大的挑战,这种通过访问状态、检查结果的方式需要覆盖率反馈来衡量可及状态空间还有多少未被访问。

然而动态仿真验证的方式实际上无法来穷举所有可能的序列去访问设计的可及状态空间,而形式验证可以通过数学方式来穷举出所有的状态空间,彻底验证设计。从下图可以看到,在仿真过程中,通过随机和覆盖率反馈的形式,我们可以产生不同的测试序列来访问状态空间,直到我们发现新的缺陷。这是一种实用的测试办法,但是另外一方面,动态仿真验证没有办法去确定设计中不存在缺陷,因为图中其它隐藏缺陷依然有待于去挖掘更多的状态空间才能被发现。

形式验证可以通过数学的方法来遍历状态空间,进而证明设计行为符合属性描述(property description)。在遍历过程中,一旦遇到反例,形式验证工具便会停止下来,报出反例情景,由用户来核对错误是否属实,再考虑修改设计或者进一步约束属性使其更精确地描述设计行为。下图中可以看到,在大量的状态空间中,形式验证工具只需要针对某一项属性描述举出反例,即可报告给验证人员,而并不需要穷举所有的反例。等待设计缺陷一旦确认、经过修正之后,验证人员可以继续通过工具来对设计和所有的属性进行检查。

像上面所讲的将属性描述(由断言构成)与设计结合进行一致性检查的方法已经提出超过20年了,且在这期间也有着不同的商业工具提供支持,例如:OneSpin,0-In(Mentor),Jasper等。下面的图概括出这些工具的进化历程:

在今后关于“基于断言的验证(assertion-based verification)”我们会详细介绍SVA、OVL的使用方式。

下一篇我们将对验证中日常使用的开发环境做一个介绍《开发环境》,感谢你对路科验证的关注。

验证的方法篇之三:开发环境

(博客链接:http://www.eetop.cn/blog/html/28/1561828-438527.html)

如果我们将影响验证编码效率的因素分为“硬件因素”和“软件因素”,那么硬件因素的配置在短期是可以补齐的,而软件因素则会设计到验证人员的技术能力、调试能力和其它软实力。所以从实用的角度上来看,如果准备在验证道路上长期深耕的话,更早地提高硬件环境配置是一笔越早投入收益越大的事情。

如果这是一篇知乎上的文章我的笔风可能是这样的——

  1. 首先你的保证你的手、肩、颈、腰在十年以后还是你的。

  2. 其次你需要养成深度编码的习惯——论如何不受打扰的方法。

  3. 最后回到编码本身,如何可以“键步如飞”,让你的键盘跟上你的脑速。

实际上我们作为稍显严肃的一个订阅号,要跟大家分享的验证师日常会是下面这样——

  1. 为什么你需要一组合适的鼠标、键盘、座椅和显示器?

  2. 编码的时候怎么屏蔽周围的环境对你的影响?——什么样的耳机、音乐对你有帮助?

  3. 一套完备的验证开发环境对你的重要性究竟有多大?

如果是软文,我们会主要讨论前两个问题,不过这显然不符合我们的气质。有多少位涉世未深的青年在一开始在对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编辑相关的部分有:

  • 实现FILE.svh同FILE.sv之间的自由切换。这是由于一些项目中验证人员习惯将类的方法声明同方法实现分别放入到.svh和.sv两份文件中,通过快捷命令可以实现这两份文件之间的切换。

  • 通过ctags和taglist的插件实现SV的标识符跳转。这项功能对于快速浏览SV类的方法、编辑很有帮助。

  • 自动补全功能。通过插件实现自动补全,这减轻了编码压力和出错概率。

  • 文本高亮和跳转。通过插件实现在数千行的代码中作下高亮标记,来实现编辑位置的跳转。

  • 学会使用折叠。折叠对于大文本的文件会给你带来清爽的感觉。

  • 学会使用语法的域跳转。例如实现module到endmodule、task到endtask、begin到end的快速跳转。

  • 学会使用录制(record)和宏(macro)操作。这对于批量操作文件有明显效果,省时省力。

语法高亮

语法高亮是减少编码错误的有效方式,由于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就是来克服设计验证编码中缺少强有力的开发工具现状的,它包含的主要特性有:

  • 加快新代码开发的速度和质量:通过完善的编辑环境。

  • 简化调试和仿真分析:自动进行语法检查和OVM/UVM框架检查,同时跟NCSim、Specman、VCS和Questa仿真器有良好接口,从而实现在DVT的窗口通过智能记录窗口来分析仿真结果。

  • 使得分析复杂源代码变得更为容易:提取类的UML图、继承关系、成员变量和方法、验证框架的结构图(在未编译的情况下就可以分析得出)、层次组成和连接、驱动和负载分析,这些分析都是动态的方式,而且无需仿真器的介入即可完成。

  • 简化维护旧有代码和可复用库:通过项目的管理方式维护代码。

  • 加快语言的方法学的学习:环境中的快速链接可以直接跳转到目标类定义、方法定义,实现应用层和框架层(OVM/UVM源包)之间的跳转,方便学习。

  • 提高为代码编辑文档的体验:自带的文档生成工具可以帮助提取文本的注释,从而生成可读性更好的HTML文档。

  • 缩短项目进程:由于DVT本身可以同Clearcase、SVN、Git等版本控制插件以及同缺陷跟踪系统例如Bugzilla完成集成,所以对于项目而言它是一个中心化的项目实施平台。

此外,DVT的调试器是开发环境的高级功能,它可以使得在DVT上直接调试代码,无需在仿真器上面做转换调试,这种方式降低了调试的复杂程度。用户可以通过调试器,直接在DVT中进行:

  • 设置断点:设置、使能、关闭断点或者条件断点。

  • 查看变量:可以在断点停止的当前运行栈内查看局部变量、类成员和模块信号,也可以修改变量。

  • 表达式窗口:用户可以自定义表达式,并且观察表达式的值变化。

  • 输出窗口:观察仿真输出,也允许用户敲入仿真器支持的命令来与仿真器互动。

在基础的语言编辑和调试基础之上,DVT的验证平台语义检查器(testbench linter)可以通过静态代码分析发现不合适的语句、代码风格、无用语句、与OVM/UVM相悖的使用方式和性能问题。它可以通过改进验证代码的可靠性和维护性来更好地协助验证人员完成验证任务。通常的编译器会检查代码是否符合语言规范,而报告出语法错误,但是编译错误不会给出代码可靠性和维护性的报告,也不会给出建议如何使得代码与方法学保持一致性。

此外,DVT自带的文档生成器可以用来从代码中的注释自动生成准确的HTML文档。这种方式使得设计人员和验证人员只需花费更少的精力来维护一份组织良好的设计和验证文档。或者设计验证人员也可以在原有的代码基础上通过注释方式生成一份更直观的文档,文档的内容可以包括文字描述、继承树、设计结构、UML类图和验证框架等。

有了一件称手的兵器,我们在接下来打野升级的路上会更顺利一些。我们下一篇中将会继续方法篇,为大家推出《虚拟模型》。

验证的方法篇之四:虚拟模型

(博客链接:http://www.eetop.cn/blog/html/28/1561828-438528.html)

对于系统虚拟建模的广泛定义是它包含高抽象级的系统硬件模型,而与此同时软件开发可以在此硬件模型基础上展开。通过这种方式,虚拟模型不但可以让软件开发在更早期就展开,而且还可以收获软件开发的反馈,从而交给硬件设计。

这种反馈在以往的瀑布模式开发周期中是无法实现的,因为软件往往需要等到硬件设计制造完成以后才能展开。通过虚拟模型,硬件可以更早地收获软件反馈而对现有的设计更早地进行修改。这种硬件和软件之间更紧密的协作方式,譬如在早期软件利用虚拟模型测试性能时就可以提出是否需要硬件加速器,或者在更早期来判断硬件和软件的协同任务是否可以满足总的功耗目标。

在目前多核的移动平台上,一个不断增长的需求就是通过划分不同的任务到多核上面来取得更好的性能,而这种软件层面的估测就可以在更早的虚拟建模阶段完成。目前我们通过多项虚拟建模的技术例如协同设计、协同仿真和协同验证,来企图在更早期就可以发现设计中的缺陷,使得修改这些缺陷可以在相对容易实施的阶段完成。通过这种将设计问题更早期暴露出来的方式来使得芯片可以完成一次流片成功的目标,和贴合市场越来越紧迫的窗口需求。

虚拟建模包括一系列的验证技术,他们有仿真(simulation)、模拟(emulation)、FPGA,而目前的现状是验证人员往往会通过混合这些方法来在最短时间内确定更好的效果。在这里,我们将虚拟模型先限定于仿真(simulation),而将模拟和FPGA归类为硬件加速技术,我们会在后面的文中主要介绍硬件加速技术。

那么,虚拟建模的优点有哪些呢?

  • 在早期可以通过软件测试来发现硬件和软件的问题:这种方式可以提前硅后软件开发,更早暴露软件和硬件之间协作的问题或者是边界定义不清晰的问题,而在RTL阶段甚至模块定义阶段就发现和修改缺陷。

  • 软件开发反馈从而修改硬件结构和RTL设计:软件和硬件紧密协作带来的是,软件也参与到了硬件结构定义的工作中。

  • 减少硬件协同软件的验证工作:由于有了虚拟模型,使得硬件设计有源可寻,同时软件的早期进入也可以帮助硬件完成一些难以通过仿真完成的测试,使得系统级测试更早期可以完成。

  • 为用户建立硅前平台模型:更早期的硅前平台模型一旦经过软件测试,可以为用户提供可开发的平台。

  • 硅后平台的参照模型:硅前平台模型有着更可见的内部性能、功耗和设计信号,而这些内部细节在物理芯片上都是观察不到的。

截止现在,虚拟建模仍然是一项不断完善和发展的技术,而它也正在被广泛的运用的芯片设计验证领域中。那么目前主要的虚拟建模平台有哪些呢?

目前工业界一致推广TLM(Transaction Lelvel Models)用来建立抽象层次的模型,而TLM也已经发展到了TLM 2.0标准。主要支持TLM2.0标准的语言有SystemC和UVM方法学。目前主要的EDA厂商都可以支持SystemC的仿真,我们可以将支持SystemC模型的仿真平台分为两种

  • 各种主要的仿真器(simulator):它们支持SystemC的编译和建模,而由于SystemC本身可以垂直大跨度的硬件抽象度,所以模型既可以拥有TLM端口,也可以拥有硬件信号端口。如果模型在边界上规定了信号时序,那么也可以将端口信号添加到波形窗口中进行查看,当然也可以通过断点的方式来调试SystemC模型。

  • 专用的虚拟建模平台(virutal prototyping platforms):这些专用平台是专门服务于虚拟建模及其仿真的,从抽象级来讲,它们的视野显著高于RTL级仿真,从开发链来看,它们会从更早期的产品定义阶段开始。更详细地说,这些专用虚拟建模平台主要服务的阶段包括有:结构设计和评测、允许硬件软件之间的权衡分析、早期的性能和功耗评估、软件集成和测试、为RTL验证提供参考模型。不同的EDA厂商提供的平台有:First Encounter(Cadence)、Vista(Mentor)和Virtualizer(Synopsys)。

那么在这些平台上,虚拟模型大致建立的方式是什么样的呢?

实际上,虚拟模型的建立也类似于硬件RTL的建模,只是从抽象层次上来讲它们提高了,或者从代码量上来讲它们变少了(但不见得变简单了,这要看逻辑实现的细节程度)。由于芯片中各个子模块都会对照着不同的软件驱动库、应用库,我们需要在芯片系统级建模过程中最大限度地囊括所有子模块对应的TLM模型,这样才会提供给软件最大程度上的自由度(即可以将日后为硅后开发的软件先在虚拟平台上测试)。

在虚拟建模平台上,可以通过可视化界面和自动智能的方式将已经准备好的模块进行集成。在集成过程中,我们需要主要讲模块类别按照提供方分为:

  • 自建虚拟模块(即按照自定义的硬件来对照建立的虚拟模块)。

  • 商业第三方IP(这些虚拟模型IP也对应着硬件IP模块,由于完善的商业IP交付包同时包含多个设计验证部分,包括RTL、SystemC、验证平台等)

如下图,在虚拟模块集成过程中可以从现有库中选择IP

如果虚拟模块需要用户自定义,那么平台工具也可以通过用户大致定义接口、内部属性来生成框架,而后等待用户去填充该完备的功能,例如下图:

同时,通过可视化窗口完成系统集成

当通过虚拟建模平台完成集成以后,虚拟系统会完成编译建立模型,进而交付给软件组以供开发,另外软件组的反馈也会报告给硬件设计组。

此外,由于虚拟模型可以考虑作为参考模型参与到RTL仿真中,这种SystemC同RTL的协同仿真模式包括有:

  • 协同设计(co-design):将SystemC模型集成到现有的设计当中,作为暂时替代设计的一部分。对此种设计的要求是虚拟模型的边界接口应该有合适的时序来同相邻的模块完成时序的一致性。

  • 协同验证(co-verification):将虚拟模型作为参考模型集成在验证环境中,为此一般的要求是虚拟模型通过TLM在环境中实现集成。

至此我们将虚拟建模的优势和方法大致讲完,目前越来越多的公司都已经应用该方法来尽可能地提前软件开发时间,并在早期反馈给硬件设计。同时,此种方法对于团队学习曲线、如何在旧有硬件设计流程中集成并有效组合、如何考虑虚拟建模在远期价值和人力额外投入的性价比、如何实现虚拟模型团队同设计验证团队的整合等等都是对现有工作方式的挑战,这一点需要团队整体都看到它的优势并且愿意为之改变,才会将它的优势更好地发挥出来。

我们下一篇将为你带来《硬件加速》,一起来看看业界最新的硬件加速模拟科技。

(下节内容请查看 验证系列之芯片验证的方法篇(下篇))

来源:路科验证(微信订阅号ROCKER-IC) 及 EETOP BLOG

(0)

相关推荐