IC验证的一种最佳实践:pandora-v0.5

2021-01-11 11:15:19 浏览数 (1)

文前言

不知道大家在验证工作过程中是否遇到如下问题

  • 新人如何快速融入到现有验证体系中
  • IP验证环境如何与SOC验证环境复用
  • 如何进行验证内容的验收保证有效
  • 随机验证的不稳定性使得对机器资源、时间资源过度消耗

希望本文能给出一些上述问题的答案。

在写这篇文章前有过很多的犹豫,要不要与当前大众工作方式更近似一些,不引入迭代、看板,不加入基于针对验证的单元测试、功能测试、接口测试。后来发现如果不加入就会使得整个体系不完整,不能进行有效的质量保证就会使得验证后期压力过大;不能进行可视化管理就会降低对瓶颈发现的概率;不引入迭代就会失去对优先级的判断而产生浪费。

本文作为一个验证指导guide仍有许多的不足,后续会在此基础上不断丰富发展,也希望大家能提出宝贵意见。其中有为解决一些问题而进行的一些尝试性创新;也有从软件领域借鉴来的经验;更有行业内对一些问题的解决方案。希望有经验的verifier能从文章中找到一些灵感,新人能找到一些工作的方向。

1.概览

文章分为三部分

第一部分:介绍三大流程、四大里程碑、八大验证过程。

第二部分:通过验证流水线将上述三部分串联起来。

第三部分:对用到的一些技术进行单独介绍。

整体遵循整体受控、局部敏捷的思想。

1.1.整体受控

ASIC作为一个多工种合作的一个大型项目,需要对每一工种切入的时机,以及切入前是否达到切入要求(DoR)有一个规范性要求,用于多部门协同,对外呈现为有序规划。

1.2.局部敏捷

验证作为一个与需求强相关的工种,时刻受市场、需求变化而带来的项目变化的影响,而且一个好的软件架构表现为浮现式,需要做经常性的修改,做持续的改进,需要我们加强内功修炼以应对外界的变化。

改变引发的改变大体有四个

  • 新需求加入
  • 需求变更
  • 迭代中对需求产生新的理解
  • 方案重做

无论是哪种变化,都需要触发需求的收集与分析,看新的需求对整个体系的影响,并根据变化适当调整优先级。

2.三大流程

2.1.启动流程

输入:spec、业务需求、历史经验教训

输出:verification plan、verification checklist、testbench

目标:根据对需求收集与分析完善verification plan,通过对业务分析与设计形成verification checklist,并根据verification plan和verification checklist进行testbench架构设计与开发,通过冒烟验证。

2.1.1.Verification plan与verification checklist的关系

在verification plan我们进行的场景的分解,事件流的分析与串联,verification checklist是测试用例的设计,根据事件流(基本流 备选流)、数据和不同的配置,进行用例覆盖,确保场景100%覆盖。

又因checklist是最终的验收标准,所以从verification plan中独立出来作为单独的输出文件。

2.1.2.Verification plan

2.1.2.1.干系人分析

在项目管理中,干系人指积极参与项目实施或者再项目完成后其利益可能受积极或消极影响的个人或组织。

干系人也可能对项目及其可交付成果施加影响。为了明确项目需求和所有项目方希望,必须识别所有内部和外部干系人,并管理各种干系人对项目的影响。

干系人分析主要体现在四方面:

  • 进行项目干系人识别
  • 分析项目干系人重要程度
  • 进行项目干系人的支持度分析
  • 针对不同项目干系人,特别是重要的项目干系人,给出管理干系人的建议,并予以实施。
2.1.2.2.领域名词定义与映射关系

输入:spec、需求、技术要求

输出:领域名词、领域名词与需求、spec映射关系,可视化图表

目的:通过对spec、需求、技术要求等的分析,形成验证内部唯一的领域名词,并建立名词与原有spec、需求等的映射关系,提高交流质量。

2.1.2.3.领域名词约束范围

对领域名词范围,以及互相关系进行约束,逐步形成配置transaction和coverage group。

2.1.2.4.协议约束
2.1.2.5.测试场景分析、设计

测试场景对应的是实际的业务场景,业务场景是业务流程中因不同的事件触发后的业务情景。比如I2C传输,先配置寄存器,启动传输,等待结束,取出数据,中间会因为发生不同的异常而产生的过程分支的不同。测试场景就是对这类事件触发时的业务情景在质量角度的描述。测试用例则是对测试场景在测试范围和测试点的详细覆盖

2.1.2.5.1.根据业务需求、spec、技术,确定业务场景分析范围

业务分析就是需求分析的过程,这里不仅仅要考虑需求的逻辑功能,还要结合不同的业务类型,结合历史经验沉淀和风险沉淀进行综合考虑。

2.1.2.5.2.业务流程梳理

将需求说明转变为业务流程,完成事件流(基本流 备选流)以及业务分析过程和技术分析过程的梳理,细分出原子级别的场景分支。

事件流:同一事件的不同的触发顺序和处理结果形成事件流,事件流分为基本流和备选流。

基本流:程序从开始执行直到成功结束所经过的最短路径。

备选流:一个备选流可以从基本流开始,在特定条件下执行,然后重新加入基本流中;也可以源于另一个备选流,执行后加入基本流或终止用例。根节点的备选流需要具备原子性。

基本流和备选流:如下图所示,图中经过用例的每条路径都用基本流和备选流表示,直黑线表示基本流,是经过用例的最简单的路径。备选流使用不同的彩色表示。一个备选流可以从基本流开始,在特定条件下执行,然后重新加入基本流中(备选流2和4);也可以源于另一个备选流,执行后加入基本流或终止用例(备选流1和3)。

2.1.2.5.3.场景串联

通过业务流程梳理中拆解的场景,根据沉淀后的场景集,用组合、并行的方法梳理出所有的事件流,必须100%覆盖所有的基本流和备选流组合。

2.1.2.6.覆盖率
2.1.2.6.1.功能覆盖率有效性确认

在进入迭代流程之前,需要确认transaction和coverage设置的合理性,确认方法相对简单,通过将transaction进行多次随机看是否能达到功能覆盖率100%。

同时需要确认case有效比是否满足要求(transaction随机次数与对覆盖率增长有效的次数之间的比值),一般来说有效比在100:1~50:1是比较合理的区间,如果超过100:1就需要查看是否哪里设置的不合理,低于50:1可能是设置的比较简单。

2.1.3.Verification checklist

Verification checklist应该包含simulation、formal、fpga、emulation,需要验证的feature和对应的事件流组合而成的case,并对case验收通过标准加以定义。

Checklist为一个大而全的清单,包括所有验证的feature,以及对应的testcase,在清单模板中包含的可以相对抽象一些。主要目的是:为资深人员提供一个二次检查的机会,防止因为疏忽产生的遗漏;为新人提供验证方向。

2.1.3.1.Simulation

Simulation一般包括ip、subsystem、soc、netlist。

simulation验收条件一般包含五部分:

  • case完成状态
  • case对应的代码覆盖率(可选)
  • case一定要覆盖的功能覆盖率
  • case事件流覆盖率
  • case一定要覆盖的assertion覆盖率

一个与simulation相关的例子

2.1.3.2.formal
2.1.3.3.fpga
2.1.3.4.emulation
2.1.3.5.Simulation与formal的关系

2.1.4.Testbench架构设计

2.1.4.1.Env层次结构与rtl层次结构一致

为了保证ip验证环境可以被集成环境使用,这里将env定义为root,且自身需是全功能,agent、sb等都是围绕env进行连接的,集成复用ip环境只能以env形式进行整体复用。同时应当将公共组件进行独立,以便在不同的层次进行使用,比如总线类agent。

通过bind的形式进行interface的绑定,减少连线带来的工作量,每个env都可以在driver disable的情况下进行自主运作完成对应check。

验证env层次结构与设计结构一致性的特点可以为DOM实现提供了条件。

2.1.4.2.满足7层验证结构
2.1.4.2.1.为什么要分层

一般层次分为业务层、工作层和技术实现层,业务层定义为了完成需求需要执行的活动,工作层决定着人员的交互关系和工作范围,技术实现层进行功能边界的定义,重点关注重用性和质量。

在此基础上的验证分层能够实现

v简化设计,每一层各司其职,降低学习成本

v高复用,有着明确的技术责任边界,有利于复用环境的产生

v横向扩展,挂载接口的一致性极大提高了扩展能力

v进行验证框架的抽象,提供稳定可靠的调用关系

在每一个层次我们还可以以控制 逻辑 数据的方式进一步进行功能拆解。

2.1.4.2.2.怎么进行分层

场景是不同的transaction在不同时间以不同的时序关系进行功能组合得到的,通过驱动层将transaction由传输单元运送到对应执行单元,由执行单元进行transaction的解析与处理。

底层通过信号采样形成对transaction不同的处理逻辑,通过不同开始结束条件定义了transaction处理的边界,处理完成后的transaction由传输层运输到不同的使用单元。

场景层:各种活动的组合,比如寄存器配置,开始传输,等传输结束即为一个场景,不同的活动都会依赖场景流程图进行相应的跳转。

功能层:为实现某一活动需要存在的逻辑功能,主要是进行transaction处理。

驱动层:建立、管理和维护驱动,即transaction具体应该怎么发、发给谁、怎么接、从哪接,另一方面seqr、env、sb等都有一个静态的聚合根进行指针的保存,并且可以支持以正则表达式方式进行查找,可以使得在任何层次下vseq都能找到对应的serqr进行transaction发送,达到case与component树解耦的目的。

传输层:相对独立,建立、管理和维护端到端的通道,即transaction传输的通道。

事物层:将transaction分解为一个个cmd,通过cmd进行信号驱动,也可以通过不同的cmd组合为transaction。

数据链路层:可以将cmd转化为固定的逻辑驱动,也可以通过采样将信号生成cmd,比如一个data的发送。在该层之上的所有操作为全软件类型操作,任何与信号相关的时序信息都被封装为一个个cmd,完成硬件世界与软件世界的交互。

物理层:我们通常理解的signal。

在软件领域的原型开发目的是进行业务有效性的快速验证,这里的原型开发目的是进行基础平台构建,并验证技术可行性,为后续功能迭代提供基础。如果不能提前做大框架的有效开发,后续迭代就没有了依靠,时间节点和进度就不好预估而丧失了迭代的可能性。

2.1.4.3.验证的测试

详情参考:验证的测试

2.2.迭代流程

输入:verification checklist、优先级需求

输出:testbench、verification checklist验收结果文件

目标:以看板可视化形式呈现,以优先级方式逐步完成verification checklist的编写、测试与验收。

迭代的主要过程为case依据优先级选取、case编写与执行、验证debug与验证环境的更新、设计debug、验收五部分组成。通过看板进行动态可视化的进度展示。

2.2.1.Bug曲线

随着迭代不断进行,逐步形成设计、验证bug的时间曲线和分布曲线,以便后期进行针对性的复盘。

2.2.2.迭代中的testbench更新

Testbench修改需要被测试,参考 验证的测试

Testbench修改需要被测试,参考 验证的测试

Testbench修改需要被测试,参考 验证的测试

启动流程中的testbench设计与开发,只是完成了一个基本能够跑通冒烟case的testbench,仍然有大量功能的没有添加。这些功能需要我们随着case迭代不断进行完善,不需要一开始就想的特别全,只要可以提前一点,能为下次case编写执行提供必要的验证跑道即可。

可以说testbench是在开发中持续迭代、不断优化的,为了保证新加功能不影响原有功能,需要有完善的测试以进行质量保证,应对不断重构的需要。为了保证testbench的可扩展性,许多软件领域的设计原则、设计模式应该被使用。

2.2.2.1.重构

重构的目的是保持代码质量处于一个可控状态,不至于腐化到一种不可救药状态。

2.2.2.1.1.重构分类

大规模高层次重构处理内容有代码分层、模块化、解耦、梳理类之间的交互关系、抽象复用组件等,理论基础为设计思想、原则和模式。

小规模低层次重构处理内容有规范命名、注释、修正函数参数过多、消除超大类、提取重复代码等变成细节问题,主要针对类、函数级别重构,理论基础为编程规范。

2.2.2.1.2.什么时候重构

需要建立持续重构的意识,将重构作为开发必不可少的部分融入到开发工作中去。

2.2.2.1.3.如何重构

对于大规模高层次重构,难度较大,需要有组织、有计划的进行,分阶段的小步快跑。

对于小规模低层次重构,由于影响范围小,改动耗时短,随时随地就可以进行。

2.2.2.2.设计原则

包括SOLID-SRP单一职责原则,SOLID-OCP开闭原则,SOLID-LSP里氏替换原则,SOLID-ISP接口隔离原则,SOLID-DPI依赖倒置原则,KISS原则,YAGNI原则,DRY原则,LOD原则等

2.2.2.3.设计模式

在GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》共收录有23种设计模式,大多是工作经验的总结。

2.2.3.看板

2.2.3.1.指示作用

只按照看板指示进行case搬运,使得参与人员对优先级与流程一目了然。

2.2.3.2.目视管理作用

自动控制生产过程,对于问题积压点一目了然,可以及时进行人员分配与管理。

通过看板,管理者可以容易发现生产和搬运量是否过量。

2.2.3.3.现场改善作用

看板作为目视化管理工具,如果能够正确理解、应用,会发现它还可以作为改善工具而发挥重要作用。通过看板,管理者可以发现异常,并及时采取措施来减少事故发生以及对异常问题的改善。

2.2.4.验证评审

由于验证是一种增量迭代的方式不断演进,很难找到某个节点进行专门的评审,在验证评审一般分为常态性的每日评审与验收时的评审。

每日评审更像是常态review的过程,互相学习互相交流,将问题解决在平时。

验收评审,除了具有常规评审属性外,利用验收时间节点查看大的验证方向是否有问题,以免跑偏。

2.2.5.回顾

每当开发工作进行到某一节点的时候,整个团队就聚在一起召开一个特别的会议,审视并调整方法和团队合作。给团队提供一个自我激励和自我愉悦的机会。回顾可以改善团队合作、改进工作方法、提升工作满意度,以及实现更好的工作效果。

回顾会议召开有很多种方式,可以参考《敏捷回顾:团队从优秀到卓越之道》。

2.3.收尾流程

输入:verification plan、验收的verification checklist

输出:项目总结报告

目的:进行项目总结,资料收集、归档,满意度调查,最终形成针对该项目的项目报告,同时在收尾时仍然会进行探索性验证的质量活动。

3.四大里程碑

3.1.验证启动评审

3.2.Rtl完成评审

3.3.Rtl freeze评审

3.4.TO评审

4.八大验证过程

4.1.Case编写->交付

4.1.1.Case编写与执行

只需要按照需求优先级进行有效case编写运行,如果遇到问题进入debug阶段。

4.1.2.验证debug

如果在case运行发生错误,验证人员需要进行debug,查看是否是验证本身的问题。如果是验证本身问题,需要增加相应的check保证问题不会再次发生;如果是验证系统的问题,需要在已有check的保护下进行重构。

经过初步评估可能不是验证环境本身的问题,这个时候就要做选择,是需要设计debug还是验证继续debug,针对不同情况选择可能有所不同,并不是无论什么时候验证都要追到问题具体发生在代码的哪一行。

4.1.3.设计debug

这里主要分为2部分,一部分为验证抛过来的有问题的case,另一部分是自己进行了设计修改,通过运行santity而发现的case错误。如果是设计本身问题需要修改;如果是验证问题,需要验证人员进行相应的修改和check添加;如果验证没有发现的问题,同样需要验证添加对应的check,并着重分析下没有发现的原因。

4.1.4.验收

通过前面定义的checklist,验收case是否通过,对应的覆盖率是否达到,这里的覆盖率信息是每个case独立运行后得到的,如果与其它case一起运行容易产生互相影响。

4.2.冒烟验证(基本流)

4.3.定向验证(基本流 备选流)

4.4.定向功能覆盖率验证(基本流)

通过对transaction和coverage分析提取出对功能覆盖率增长有效配置,并将对覆盖率增长有效的所有配置提取为DOM可以识别的格式,形成可以完成100%功能覆盖率的定向case。

如果transaction、coverage等有变化,需要重新生成。

4.5.鲁棒性验证(基本流 备选流)

鲁棒性测试时对各个模块的功能和系统进行容错性测试,检测模块在异常输入和苛刻环境下是否可以保持正常工作,包括不仅限于错误数据处理、异常情况处理、非法操作处理等。

鲁棒性测试大大提高了错误覆盖率,其测试的目的和依据都是在验证三个特性:

v成熟性:避免因错误而导致失效的能力

v容错性:在错误数据或者违规操作下,仍能维持规定性能的能力

v易恢复性:在发生故障的情况下,重建规定的性能并恢复受影响功能的能力。

4.6.非功能验证(基本流 备选流)

测试用例在设计上除了考虑功能性质量属性,还需要对非功能性进行覆盖。比如安全、性能、功耗等。

4.7.随机验证-代码覆盖率收敛(基本流 备选流)

4.8.定向代码覆盖率收敛验证(基本流 备选流)

4.9.随机验证-探索性验证(基本流 备选流)

前面几步已经完成在想象内绝大部分的验证,但仍然可能有一些bug逍遥法外,利用已经构建好的完整的随机与场景体系,进行完全放开的自由式探索,让机器帮我们探索更多未知的边界。

4.10.每日/每周构建

针对每日/每周构建,可以从八大过程中选取定向部分进行自定义组合,确定不同构建的粒度和范围。因为许多部分为定向测试,能够保证构建的稳定性,一个稳定的构建也可以为设计持续集成提供保证,但需要在构建运行时间和何时构建上进行折中选择。

5.验证流水线

验证流水线是将三大流程、八大验证过程进行串联的一个状态图,希望对现有工作进行分解,显示了在每一个状态下遇到的不同事件的应对措施。

6.验证的测试

6.1.为什么要进行验证的测试

6.1.1.提升对验证代码的信心

每次修改后快速测试都通过至少可以告诉我们之前发现的问题没有因为修改再出现,将能暴露的问题在最短时间内暴露。 在上层发现的问题同样可以通过增加测试来保证,避免问题的再次发生,实现对验证代码质量的保证。

6.1.2.为重构质量提供保障

看着代码比较差,想改,改了后要怕出问题,设计debug半天发现是验证的事情,这个时候测试可以充当保护神,新的修改可以让原有测试通过,就会有很大 的信心相信新修改没有改变原有的功能。

6.1.3.通过测试快速熟悉代码

测试也被称为活文档,通过阅读测试就可以知道代码如何使用,怎么工作,包含哪些业务。

6.1.4.通过测试提高可测性、可扩展、可复用能力

如果将功能写到1000行的函数中容易测试么,想加个功能应该也不容易,想被其它模块用也不现实,一般来说可测性与可扩展和可复用是一同出现的,当我们通过测试满足了可测性,就可以被动提高代码的可扩展和可复用能力。

6.1.5.将bug消灭在过程中

一个bug隐藏的时间越长,修复的代价越高,对于任何要进库的代码进行单元测试也是对一起工作的小伙伴负责,当然这一步可以隐藏在自动化流水线中。

6.2.验证的测试的种类

Signal的驱动存在大量的并行处理,所有在单元测试与功能测试需要对signal进行屏蔽,以降低并行带来的复杂度。

这里的测试分类只针对粒度(class),而不针对层级,在subsystem、soc级别也会存在用于特定处理的class,就需要进行对应的测试。

6.2.1.单元测试

定义:用于验证基本的class或class中的function、task的测试叫做单元测试。

6.2.2.功能测试

定义:用于验证有限多个class组成的最小的功能单元的测试叫做功能测试,比如environment中的比较功能单元。

6.2.3.信号驱动测试

定义:验证用于驱动signal的task的正确性的测试叫做信号驱动测试。

6.2.4.Assertion测试

定义:验证assertion单元正确性的测试叫assertion测试

在这里的测试主要有三种(集成、系统测试不在讨论之列):

7.DOM

目的:可以通过xml进行testbench的配置,也可以进行具有rand属性的变量的配置。

为什么选用xml:

  • 有较多语言支持xml树解析
  • 有现成的语法格式不需要自定义
  • 可扩展性较强

特殊处理:

  • 在uvm基础上增加anticorruption layer,降低uvm版本变化对系统的影响。
  • 将object的继承方式做了相应处理,可以得到与uvm_component一样的full_name。

7.1.使用DOM进行case编写

使用sv进行case编写遇到的最大的问题是重新编译,产生了大量的时间消耗。这个问题有2个解决方案

v使用dpi的方式模拟cpu,通过c进行case编写。

v使用DOM进行配置配合事件流完成整个case构造过程。

7.2.作为定向功能覆盖率配置导入导出媒介

在定向功能覆盖率生成阶段,通过DOM将内部配置生成为文件,而不是sv case,在执行阶段将事件流与配置文件进行组合实现对应case。

8.展现的可视化

我们在进行文档描述时尽可能以可视化形式呈现,包括不仅限于以下六种。

9.与传统方法的数据对比(待收集)

10.自动化的未来

11.结语

验证应当有2方面责任,价值和质量。

价值属于业务端的事情,是要告诉我们要做正确的事情,我们可以通过在事情开始前的checklist来确定业务范围,和结束后的验收看事情是否做完,做事情的顺序需要满足一定的优先级,优先级应当被PM或其他角色定义,而不是验证工程师自己觉得什么重要就做什么。

质量属于技术端的事情,需要保证我们持续输出正确性,即正确的做事,属于内建质量的范畴,需要满足可测性、可复用、可扩展等特性,通过快速的单元测试、功能测试保证。

在多个价值交付中可能会复用很多相同的组件,对组件进行增删改查操作,需要我们通过本身组件的测试保证每次修改不影响之前的功能和通过增加新的测试保证本次提交的正确性。

当验证本身的质量有保证后,设计就可以通过高质量的验证来验证设计本身修改是否引入问题。

功在当下利在千秋。

0 人点赞