Effective FPV for verification 形式验证 第6章

本章将深入探讨两种设计验证技术:bug hunting FPVfull proof FPV

FPV的bug hunting 模式通常应用于相当复杂的块,其中预计还将使用诸如模拟或仿真之类的补充验证方法。FPV在这种区块上的目标将是瞄准复杂场景,并发现不太可能通过仿真实现的corner cases 情况。

full proof FPV是最初FPV研究开发者的传统目标,通常针对复杂或危险的设计,旨在完全证明设计符合其规范;如果处理得当,full proof FPV可用于完全替代单元级仿真测试

做以验证为中心的FPV时,需要决定:是使用它来补充其他形式的验证并查找错误,还是将其作为验证的主要方法并形式上验证设计。

如果对FPV缺乏经验,建议从RTL练习开始,然后继续进行bug hunting,并根据最初的成功程度选择是否扩展到full proof。在一些经验之后,应该能够更好地判断哪种FPV模式最适合你的设计。

一、决定FPV目标

如果考虑以验证为中心的FPV,需要确保选择合适的设计风格;FPV在控制逻辑块或数据传输块上最有效。“数据传输”指的是将数据从一个点路由到另一个点的块。与“数据转换”块形成对比,数据转换对数据执行复杂的操作,如浮点运算或MPEG解码器逻辑:大多数FPV工具无法很好地处理数据转换

当前的工具,简单的算术运算(如整数加法和减法)通常是可以接受的,但对于涉及乘法、除法或浮点方法的主要块,可能需要其他形式的验证。

1、BUG HUNTING FPV

Bug hunting FPV:在设计中寻找潜在的角落案例(corner-case )问题,通过其他技术可能会错过这些问题。

最重要的设计需求被写成断言,证明违反条件的非法断言是不可能的,或者使用FPV工具来发现设计中存在此类场景。

由于大量corner-case,设计的一部分被视为特别危险,并且即使在运行了全套随机仿真之后,如果希望对验证有额外的信心,则通常使用此方法。

当在后期设计阶段遇到仿真覆盖问题时,通常会求助于Bug hunting FPV,以确保没有任何棘手的角落案例等待曝光。

选择Bug hunting FPV的一些常见情况如下:

  • 设计了一个包含许多corner-case的设计,例如一个带有多个交互状态机的大型控制逻辑,并且需要额外的验证。

  • 对设计进行定期仿真,其中的一些部分在随机测试期间反复暴露新的错误。

  • 正在验证设计中的一个关键组件,类似的块有逻辑错误遗留到后期或硅片(芯片)。

  • 已经在模型上完成了 design exercise FPV ,因此通过添加额外的目标断言来增加FPV覆盖率的成本相对较低。

  • 有一个成熟的/重用的模型,它基本上不需要进一步验证,如果添加了一个新特性,希望可以放心地验证。

  • 有一个在更高级别的仿真testbench 上通过随机测试发现的bug,这很难在单元级别重现相同的bug,因为需要一组复杂且罕见的输入条件。

在这FPV被用作仿真的补充,可以允许某种程度的过度约束或其他妥协。不要避免添加限制,

2、FULL PROOF FPV

full proof FPV是最符合FV研究原始动机的使用模型:生成设计100%正确的可靠证明。

full proof FPV是一项高强度的活动,因为它需要证明设计的完整功能。将其用作单元级仿真的替代品,可以节省运行仿真或其他验证方法所花费的精力。

这种方法还降低了由于测试计划期间未预料到的corner-case行为而导致的难以发现的失误和风险,通常在传统验证的后期阶段出现。

如果有以下情况应该考虑在RTL上运行full proof FPV:

  • 提供一个预期实现的详细参考规范。

  • 设计符合标准接口,其中有预先验证的FPV辅助资料包可用,或者所需的约束集合已明确记录。

  • 设计由一组完全封装预期行为的表定义。

  • RTL中有一部分需要防弹验证,以降低设计风险。

  • 已经完成了FPV的初始bug搜索工作,并且非常成功;可以扩展断言集并减少过度约束,以覆盖整个规范。

二、准备FPV工作

由于full proof FPV是一项巨大的工作,建议从design exercise FPV 开始,将其扩展到Bug hunting,并逐步走向full proof 模式

design exercise作为一个初始的健全性检查,以确认选择了一个大小适合FPV的设计,其逻辑的复杂性水平对于FPV工具来说是合理的。

通过广泛的wiggling (调整)观察到了不错的结果,对创建的环境充满信心,并且已经完成了design exercise计划中的目标,那么是时候过渡到Bug hunting

开始Bug hunting时,首先要创建一个Bug hunting验证计划。创建这个计划后,就开始向设计中添加更复杂的断言,并对其进行验证,进一步调整,改进建模,并根据需要细化约束

bug hunting模式中可以过约束,通常会逐渐删除这些约束以查找更大类的bug。完成了Bug hunting计划中的目标后,需要做full proof FPV

在规划full proof FPV时,需要小心设计的全覆盖范围,确保从一个确定的规范文档开始(或要求架构师提供一个),并确保计划不仅包括一整套断言,还包括一系列广泛的覆盖点,这些覆盖点可以为所花费的验证工作注入信心。

总会有逻辑漏洞的问题潜在,如果不检查覆盖点,根本不会想到其中的一些漏洞。商业工具功能也可以帮助提供覆盖信息。但即使有工具功能来帮助检查覆盖率,也需要仔细考虑所需的一组覆盖点:没有任何工具可以完全替代人类的设计直觉。

下面在一个简单的算术逻辑单元(ALU)设计示例的基础上,详细了解实现FPV目标所涉及的步骤。

三、本章示例:简单ALU

使用带有一些故意缺陷的简单设计来说明FPV的使用,但不保证它不会创建别的FDIV错误。

图6.1是ALU的基本框图,以及规范中的一些简单要求:

  • 逻辑单元计算简单的逻辑运算:OR、AND和NOT。

  • 算术单元计算简单的算术计算:加法、减法和比较。

  • 结果伴随着相应的有效信号logresultv/arithresultv,输出的最终选择基于操作。

  • 计算需要三个时钟才能在输出端口产生结果。

  • 有四个线程在大向量上并行计算;即以下逻辑被复制了四次。

完整的SystemVerilog模型可从以下网站下载:http://formalverificationbook.com

从图6.1中可以看出,这些操作是并行计算的,因此有机会实现作为设计一部分嵌入的简单节能。

选定的计算逻辑是 active,单元的其他部分可以进行时钟门控,与时钟线断开以防逻辑转换并减少总体功耗。该设计的顶层代码如下所示:

// uopcode definitions
 parameter OPAND = 5'b00000;
 parameter OPOR  = 5'b00001;
 parameter OPXOR = 5'b00010;
 parameter OPADD = 5'b01000;
 parameter OPSUB = 5'b01001;
 parameter OPCMP = 5’b01011;
 //
 parameter DSIZE08 = 2'b00;
 parameter DSIZE16 = 2'b01;
 parameter DSIZE32 = 2'b10;
 parameter MAXDSIZE = DSIZE08;
 // Top-level wrapper module
 module alu0(
 Clk,
 uopv,
 uopcode,
 uopsize,
 src1,
 src2,
 resultv,
 result,
 dfts1ovrd,
 dftdata,
 defeature_addck
 );
logical logical (
 .Clk ( Clk ),
 .uopv ( uopv ),
 .uopcode ( uopcode ),
 .uopsize ( uopsize ),
 .src1 ( src1 ),
 .src2 ( src2 ),
 .logresultv ( logresultv ),
 .logresult ( logresult ),
 .dftdata (dftdata),
 .dfts1ovrd(dfts1ovrd)
 );
arithmetic arithmetic (
 .Clk ( Clk ),
 .uopv ( uopv ),
 .uopcode ( uopcode ),
 .uopsize ( uopsize ),
 .src1 ( src1 ),
 .src2 ( src2 ),
 .arithresultv ( arithresultv )
 .arithresult ( arithresult )
 .defeature_addck(defeature_addck)
 );
resultv = logresultv | arithresultv;
`MUX2_1( result,
 logresultv, logresult,
 arithresultv, arithresult )
end
endmodule // alu0

为了简洁起见,这里只描述了实例化和最终连接。

四、了解设计

在做以验证为中心的FPV工作之前,无论是bug hunting还是full proof ,都应该从design exercise FPV开始。

基于轻量级的初始努力,在帮助判断FPV在设计上的总体可行性方面发挥关键作用。

后面的讨论是基于在ALU上已经完成了design exercise FPV,将工作扩展到错误查找,并最终实现full proof FPV。

当从design exercise过渡到bug hunting FPV时,第一步是确定正确的DUT块以进行验证,从定义上来说,形式化工具探索了被测试的设计块所表现出的所有可能行为,这是一个计算量很高的问题。

FPV引擎的性能可根据逻辑的内部结构而变化很大,与模型大小无关,因此最好避免对引擎的最大容量造成影响;不应该向形式工具提供任意大的设计块来进行测试。

为了最大限度地利用工具的有限容量,在选择DUT时,将设计中最有趣的部分划分出来;在选择任意逻辑和足够大且有充分文件证明的DUT之间,需要有一个很好的平衡,以便创建一个清晰的验证计划。

在ALU示例中,设计包含ALU的四个并行副本,每个线程一个。如果主要关注点是ALU功能,而不是顶层的线程调度逻辑,那么最好关注ALU逻辑本身,验证一个通用ALU实例,而不是包含四个实例的顶层模型。这提供了显著的潜在复杂性节省,四分之一的逻辑用于分析整个模型。

在大多数情况下,是对大型嵌入式内存进行黑盒处理,这会在复杂性一节中介绍。

应该先看首字母的框图DUT,并通过以下操作:

  • 确定每个主要子模块的状态元素数量的大致大小,许多EDA工具可以为已编译的模型显示此信息

  • 确定想要使用的FPV目标块,同时考虑设计尺寸和逻辑风格:控制逻辑或数据传输块往往最适合使用FPV工具。

  • 确定备选黑盒:如果有需要,从考虑中删除的子模块,黑盒的逻辑一般不会影响主要目标。如果它影响了目标,还需要考虑创建接口假设所需的潜在工作,以模拟该块的输出行为。

  • 确定需要适当约束的主要外部接口

上述项目并不总是很容易确定,如果有来自当前设计或以前项目的类似设计的仿真波形可用,也应该检查它们以获得指导。这些波形可以帮助确定在典型事务期间接口的哪些部分是活动的,以及关键活动是否发生在提议的黑盒接口上。

对于ALU,可能会生成一个像这样的图6.3。假设算术逻辑已经被确定为主要风险区域,因此希望确保FPV环境最终会测试这个逻辑。

一旦生成了这个图并理解了模型的基本设计流程、块和接口,就可以开始进行缺陷查找FPV计划了。

注意:当开始bug hunting或者full proof FPV计划过程时,从单元的框图开始,包括所有主要块的大小,并标记接口、黑箱候选和验证重点区域。这个图表将为您的验证计划提供一个重要的基础。

五、创建FPV验证计划

假设选择了FPV,因为想详尽地检查算术逻辑的极端情况,并对设计的功能获得更多的信心,应该试着从以下开始:

  • 明确目标。

  • 将关注的属性类型,包括应该命中的cover points

  • 分期计划如何验证过约束并逐渐消除过约束

  • 可以部署分解策略来处理复杂度级别

  • 确定何时完成足够的FPV的成功标准

开始以验证为重点的FPV工作时,创建一个验证计划,要描述待验证的逻辑、属性和覆盖点、分期计划、分解策略和成功标准。

验证计划可能会变更;应该能够从最初的FPV运行中获得反馈,并调整计划以推动其余的验证工作。该计划应该很容易转换到FPV环境,这将涉及创建可能是约束(假设)、功能检查的属性(assertion)和健全检查器(cover)。当发现新问题和新知识时,不要对多次执行这个细化循环感到惊讶,这促使对验证计划和FPV环境进行微调。在所有阶段,覆盖点都可以持续地检查。

1、FPV目标

bug hunting FPV的主要目标之一是解决通过模拟很难解决的角落情况问题,为了更好地检查极端情况,应该尝试创建涉及设计的每个主要功能的属性,或者认为具有最大风险的设计部分的属性。在本章的ALU例子中,会考虑验证特定类型的操作和DSIZE的特定情况下的所有操作码,而在full proof FPV模式中,会考虑所有的情况:所有DSIZE和所有操作码的交叉积。

大多数设计行为将在规范文档中定义,进行bug hunting FPV时,可以用它来指导最重要的特性。如果做full proof FPV,应该仔细检查这个文件,并确保它的要求已经包含在FPV计划中

基于上面的考虑,可以提出在ALU上进行bug hunting FPV的初始目标:

  • 验证算术单元的行为,没有任何不寻常的活动时,如电源门或扫描/调试挂钩,默认是DSIZE 08。

  • 如果时间允许,还可以扩展到检查逻辑运算符DSIZE值

  • 完成以上所有检查后,考虑给电源门控和扫描/调试特性添加检查

2、FPV的主要属性

根据验证计划,决定希望包含在FPV环境中的主要属性。SystemVerilog中的编码断言(SVA)将在后面介绍。

(1)cover points

对于任何FPV活动,cover points在早期阶段是最关键的属性,从编写典型情况的cover points和基本行为的有趣组合开始。给规范文档中以波形形式描述的每个操作码和流,定义一个覆盖属性

图6.4显示了规范中可能出现的波形示例,演示了算术和逻辑操作的流程,目标是在形式环境中复制这些流程。

除了从规范中复制适用的波形之外,还应该计划覆盖点来执行算术操作,并查看设计如何响应预定义的输入集。所以最初的cover points计划是这样的:

  • 创建覆盖点,复制说明算术单元行为的规范中的每个波形

  • 用非零输入覆盖每个算术操作(ADD、SUB、CMP),单独地或back-to-back使用另一个随机操作

  • 覆盖上述每个操作的案例,使用特定的数据来运行所有位

(2)Assumptions

bug hunting模式中,希望针对设计的特定行为,这意味着会应用约束,这样行为就被限制在检查所选操作上。试图验证具体行为时,不应该回避过度约束。可能无法在第一次尝试中提出正确的假设,因此会花费一些时间来收敛所有需要的假设。这是任何模式开始的普遍做法。

在上述例子中,环境过约束的初始假设包括:

  • 假设uopsize的输入总是DSIZE 08

  • 假设dfx(scan)输入被关闭

  • 假设所有操作都是算术运算,而不是逻辑运算。

还应该检查在框图中确定的接口:需要确保假设集正确地模拟了每个接口的行为。在简单ALU的例子中,已经确定了指令驱动接口和数据传输接口,作为模型和外部世界之间的交互点。这个简单的示例,这些接口没有任何复杂的协议需求来建模

在更复杂的情况下,设计中的接口可能与标准协议规范(如USB、AXI或AHB)一致,或者与以前的设计或版本中的块匹配。拥有一组定义协议的可重用假设(和断言),或者能够利用以前项目中类似的接口假设集,一定要利用任何重用机会。在简单ALU示例中,没有这样的情况。

如果用独立的断言来描述接口比较复杂,并且没有可重用的附属品,那么也可以考虑开发参考模型,这将在下一小节介绍。

(3)Assertions

下面是这个例子的断言类型:

  • 断言当一个有效的操作到达时,一个有效的输出将在三个周期内出现

  • 断言每个操作都会产生预期的结果:如果选择ADD,输出应该匹配输入的和,等等。

注意,上面的两个属性都是基于规范的端到端属性:根据预期的输入讨论期望的输出。在更复杂的设计中,可能希望使用白盒断言来补充这些断言,以检查内部节点上的中间活动。通常情况下,可以使用端到端属性完整地描述规范,但在许多情况下,这些属性也可能是逻辑上最复杂的,包含大量的逻辑来证明并挑战形式化引擎。考虑在内部模块上创建更多的局部断言,并在遇到复杂性问题时验证计算的中间步,仍然希望指定端到端属性,但是在调试过程中使用这些较小的属性可以显著提高调试过程的效率。

查看上面的断言时,将它们写成一堆独立的属性似乎有点困难。可以考虑引用模型。

(4)引用建模和属性

根据正在验证的逻辑,DUT可能与相邻逻辑有不同程度的复杂度交互。通常通过创建SystemVerilog模块来处理这个问题,这些模块模拟周围逻辑的行为,并在任何给定的时间步骤生成预期的结果,这些类型的模块称为参考模型。

那什么时候应该创建一个参考模型,什么时候一个更简单的SVA假设或断言集合就足够了?

对于假设,周围逻辑的抽象的创建应该以验证过程中暴露的失败场景为指导。因为对于给定的DUT,几乎不可能预先知道足够的约束集。必要的约束不仅依赖于DUT和周围逻辑之间的交互,还依赖于正在验证的规范。如果向模型中添加约束需要大量的统计,那么最好开发一个参考模型以非常简单的方式捕获了这个抽象。

在不需要大量统计和过去事件的信息跟踪的情况下,收集简单的SVA假设通常就足够了。通常从一开始就很难确定是否需要在正确的行为约束中表示相邻单元的全部复杂性,或者是否一小组基本假设就足够了。因此,通常建议从简单的假设开始,如果需要,可以在后面的阶段演变成周围逻辑的抽象参考模型

考虑可能需要的潜在参考模型,并在必要时为它们制定计划。如果有一些遵循复杂协议的接口,那么可能需要一个参考模型。在这种情况下,对输入没有太多要求。如果接口更复杂,考虑指令驱动程序接口和结果传输接口,并考虑创建参考模型需要什么。

除了用于假设的环境参考模型之外,还应该考虑用于断言的功能参考模型的可能需求,这通常是验证完整操作的可靠方法。

一般来说,设计的RTL实现需要考虑时序需求、调试相关钩子、时钟门控和其他需求。

为FPV编写的参考模型在某种程度上可以被抽象:不需要考虑任何这样的需求,可以只集中在设计的功能方面。

把这种局部的或抽象的逻辑模型称为shadow modeling ,这些局部影子模型通常对bug hunting FPV非常有帮助,如果需要full proof FPV证明,可以稍后扩展为完整的抽象模型。RTL输出总是等于抽象模型输出的简单断言将为建模的逻辑部分提供一种形式完整性的感觉。

有一个相对简单的模型,正在执行一个多步算术操作的情况,在断言中指定它会很混乱。

在这种情况下,考虑对ALU操作的行为进行独立建模,将预期结果与实际模型的结果进行比较。可以在验证计划中添加:如果指定断言很复杂,可以考虑使用阴影模型根据输入从每个算术操作中生成预期的结果

3、定位复杂度

作为FPV计划的一部分,应该减少设计的大小或复杂性,并使其更符合FV。

基于FPV设计实践环境中某些属性的初始大小或收敛困难,应该及早判断是否需要在初始FPV计划中解决某些复杂性问题。最初的断言可能很快得到证明,但是当添加更复杂的断言或放松一些过约束以扩大验证范围时,可能需要解决复杂性。

在第10章会介绍在验证过程中,可以在具有挑战性的块上使用的高级复杂性技术,本章只讨论一些应该在FPV计划阶段考虑的基本技术。

(1)阶段计划

建议从一个过度受限的环境开始,专注于设计中确定的风险最大的领域或操作。

为了使验证环境的价值最大化,应该有一个可靠的阶段计划来逐步放松约束,逐步将bug hunting FPV构建为一个bug hunting 运行。因此可以通过添加数据大小为常数的假设,将验证限制在特定的数据大小DSIZE08上。一旦这个受限制的环境稳定下来并经过调试,就可以放松这个条件,并尝试在启用更多可能性的情况下达到与以前相同的水平。

如果成功地验证了算术子单元,主要关注区域,所有的数据大小,可能会考虑将这些额外的函数添加回模型中。

  • 对于FPV的第一阶段,希望关注算术子模块,DFT被禁用,数据大小为DSIZE08。

  • 在下一阶段,希望验证所有数据大小的模块

  • 根据上述阶段的成功,稍后会验证DFT和逻辑块。

(2)黑盒

除了考虑过约束之外,还应该考虑那些很适合被黑盒的子模块,这意味着它们将被FPV忽略,应该再次参考框图,已经确定了每个主要子模块的大小,并标记了可能被黑盒的候选对象。一般来说,如果块包含大的嵌入式队列或内存,这些是黑盒的主要候选者,在上述例子ALU中没有这样的元素。

在选择黑盒时,需要仔细考虑通过块的数据流以及黑盒可能产生的影响。由于最初关注的是算术运算,所以第一个确定的黑盒(逻辑单元)基本上是无害的:关注的操作不会使用这个单元。因此将计划在初始阶段对其进行黑盒处理,以帮助最小化复杂性。

  • 初始化将逻辑子单元黑盒化

但是黑盒的输出变成了自由变量——可以在任何时候取任何值,就像输入一样,所以它们可能需要新的假设。对于上述例子ALU,需要在黑盒逻辑单元时添加一个新的假设,这样它就不会为最终的MUX产生有效的逻辑结果:

  • 由于对逻辑单元进行了黑盒化,因此要添加一个假设,即logresultv总是0

还确定了一个次要的潜在黑盒目标:算术子单元前端的解码块。已经有了一个形式 design exercise 环境(如前所述,建议将其作为FPV工作的起点),那么提出一些附加黑盒活动的覆盖点,并检查在设计中生成的波形可能是有用的FPV工具,以获得可能需要的额外假设的想法。如下面的图6.5所示。

在波形开始的几个周期后,看到所有算术操作同时启用的情况,这是一种不希望出现的情况,并且不能保证在块的输出处有任何正确的结果。如果现在分析情况,已经删除了清除操作码的块,并为一个时钟周期生成一个且仅一个操作,现在解码器块的所有输出都可以自由选择任何值,因此观察到一些看起来像疯狂的行为。

需要通过添加一些与黑盒相关的新假设来纠正这种情况,或者放弃并得出结论,认为解码器不是一个好的黑盒候选。选择想要黑盒设计中的块时,需要格外谨慎。因为已经确定这个黑盒不是真正必要的,所以最好暂时将这个逻辑保留在模型中。

从本质上讲,这个问题源于这样一个事实:黑盒候选对象直接位于正在检查的操作路径中;如果把它黑盒化,这更可能需要一些更复杂的额外假设。在ALU的非黑盒部分的总状态计数完全低于目标范围(40000个状态元素),所以可以避免这个额外的黑盒,除非它是必要的。因此,最初应该计划不黑盒化这个子单位,以防遇到复杂度问题。

注意:考虑黑盒化子模块时,查看从仿真或design exercise FPV覆盖点提取的常见操作中涉及的波形,以帮助决定是否需要复杂的假设来建模相关输出

(3)结构抽象

另一个有用的降低复杂性的技术是数据/结构抽象,其中逻辑结构的大小减小:例如,通过减少缓冲区条目的数量或限制数据总线的宽度。

结构抽象不仅减少了逻辑的大小,因此减少了工具必须搜索的状态空间;它还允许工具在更低的边界上到达流中有趣的微架构点。例如,当缓冲区/队列满时,如果在微体系结构流中有几个角落的情况,那么将缓冲区的大小从40减少到4将允许工具在更低的范围内探索“队列满”周围的行为。

注意:结构抽象不仅减少了逻辑和状态空间的大小,而且还允许工具在更低的范围内达到有趣的微体系结构点。

上面的ALU示例,因为有MAXDSIZE作为参数。也许最大8位的模式并不是最终产品所需要的,但有了它可以在一个更简单、更小的环境中进行初始验证,这可能会揭示绝大多数潜在的错误。

  • 在初始FPV运行时,将参数MAXDSIZE设置为DSIZE08,允许在编译时进行一些逻辑最小化。

4、质量检查和退出标准

一个pass的证明并不一定意味着DUT在所有可能的输入场景下都满足该性质,证明开发容易出现人为错误:涉及到调试失败的过程,向证明环境添加约束和建模,并引导该过程走向最终验证目标。

要进行质量检查,以尽快发现这些错误或证明限制。判断FPV质量必须考虑的主要因素包括:

  • 已证明的属性集的质量:断言集是否提供了目标规范的良好表示,并使用了模型的所有相关部分?

  • 约束的质量:假设、黑盒和其他工具指令限制了证明空间,确定没有忽略关键行为并隐藏bug吗?

  • 验证质量:FPV工具是否实现了完全验证,还是在保证高质量的深度上实现了有限验证?

FPV质量的第一个基本组成部分取决于实际设计的重要方面,确保与架构师和设计专家一起检查断言、假设和覆盖点。

这个检查应该检查试图验证的每个主要功能部分是否都有断言和覆盖点,并且假设是合理的,或者与FPV环境的有意限制相对应。如果使用FPV作为模拟的补充,应该关注模拟计划未涵盖的风险领域,并确保这些在FPV计划中涵盖。

质量检查的另一个主要目标是确保没有任何证明是空pass的,或者由于假设和其他工具约束太强而排除了正常的设计行为或禁用RTL模型的重要部分。

获得覆盖率信心和防止假pass的最好方法是一组好的cover points ,在FPV专家中有一个共同的声明:“使用cover points,而不是断言,以检查FPV活动是否完整。”大多数工具自动给形式是A->B的任何断言或假设生成触发条件cover points,检查触发条件A是否可能。

这些自动生成的前提条件covers是有用的,但要确保不完全依赖它们:好的手动编写的cover points,捕捉设计师或验证者的直觉或来自规范的明确示例更有价值。

对于没有多少FPV经验的项目,推荐的另一个简单的测试是插入一些已知的错误(基于类似设计的escapes ),并尝试重现它们,作为确认证明环境非空性的过程的一部分。这在说服管理人员当前环境确实有助于验证工作时尤其有效,如果他们主要看到的是成功证明的报告,这通常是一个值得怀疑的地方。

质量检查的第三个主要方面是验证本身的强度。情况下FPV工具将为断言提供完整的证明,确信任何可能的执行都不会违反它们。但在实践中,可能会有许多断言只能得到有界证明。事实上,许多英特尔项目主要使用有界证明(bounded proofs),而不是完全证明( full proof s)来完成他们的FPV目标。

有界证明仍然是一个非常强大的结果,表明断言在任何可能的系统执行中都不会失败,直到重置后的周期数,实际上相当于运行了指数数量的仿真测试。需要确保有良好的证明边界,而不隐藏重要的模型行为。

最重要的质量检查是,检查cover points是否通过,跟踪长度小于断言的证明界限。这表明证明中考虑的潜在执行包括由覆盖点表示的操作,通常最好在至少两倍于最长覆盖点跟踪长度的深度对断言进行证明,以确信证明包含了由设计中多个连续操作引起的问题。

注意:如果使用有界证明(bounded proofs),请确保断言的证明深度大于最长覆盖点跟踪,最好至少是该跟踪长度的两倍

另一个重要的质量检查是,如果有一个包含被测单元的可用仿真环境,那么将断言和假设与仿真结果进行协调。一些工具允许在存储库中存储模拟跟踪的集合,并检查针对仿真跟踪集合添加的任何新假设,这将为添加的假设是否正确提供早期反馈。

在动态仿真中,对SVA假设的处理方式与断言相同:如果任何一组测试值违反了它的条件,就会标记一个错误。确保在仿真运行中触发这些属性,大多数现代仿真工具都可以为SVA报告这些属性。但要仔细考虑过约束:断言和假设的某些子集可能在仿真中没有意义。例如,假设DFT功能被关闭,需要确保选择一个不使用这些功能的仿真测试子集。

注意:确保将FPV假设附加为动态仿真环境中的检查器(如果可用的话),以便可以收集关于正式环境质量的反馈。

许多商业FPV工具都提供自动覆盖功能,可以帮助用户确定形式断言集覆盖RTL代码的程度。更高级的工具提供诸如表达式覆盖或切换覆盖( expression coverage or toggle coverage )等特性,以对FPV测试中可能存在的差距进行更细粒度的测量。

尽可能使用这些工具,因为它们可以为FPV环境中的主要差距提供很好的提示。但不要仅依赖于这样的工具:再多的自动检查也不能代替创建代表用户实际设计和验证意图的覆盖点的人类直觉。

(1)退出标准

从定义FPV的目标开始,然后调整设计并探索它,创建与最终目标相一致的验证计划,定义达到目标的属性,制定阶段计划,并理解要完成的抽象。现在需要定义退出标准,以自信地退出设计活动。为了实现这些退出标准,建议尝试持续测量上描述的质量形式,跟踪每个质量指标的进度,以及跟踪通过的属性比例,以及分期计划中的进度。

假设一直在衡量自己的工作质量,那么以下是一些合理的退出标准:

  • 时间限制:确定一个合适的退出验证的时间,虽然花一周的时间进行design exercise 是很常见的,但建议至少花两到三周的时间进行缺陷查找FPV,这取决于所考虑的块的复杂性。从bug搜索模式中看到更多的价值时,发现新的bug或在一些角落的情况下获得更多的信心时,一定要考虑对块进行full proof FPV。如果转到full proof 模式,可能会期望至少加倍的长期努力。如果full proof FPV能够减少或消除单元级别的仿真工作,这可能会带来回报。

  • 质量:可以根据上面定义的质量类别的进展来定义退出标准,可能必须在分期计划中修改当前阶段的这些质量检查:每个阶段在验证质量中都有一些已知限制的子集。如果目标是寻找错误,并且有一个互补的仿真环境,可能不需要完成所有阶段,或者允许一定比例的属性完成,而不是当前验证阶段的全部完成。一般而言,质量退出标准可能包括:

  1. 被证明的属性集的质量:确保验证计划已经被完全审查,已经创建了计划好的所有断言和覆盖点,并且所有断言都是通过的。

  1. 约束条件的质量:确保所有的覆盖点都通过了,并且在仿真回归中没有假设失败。

  1. 验证的质量:确保所有有界证明都达到一个可接受的范围,就像根据覆盖点判断的那样。如果可用,还可以包括一些与报告的自动覆盖率相关的标准FPV工具。

  • 成功测试:与许多验证任务一样,有时可能会达到一个收益递减的点,在FPV环境达到一定的成熟度后,开始看到较少的投资回报。通常经过一段时间的初始调整以改进假设,将经历数周的快速错误查找,随着设计的成熟逐渐消失。可能想要设置一些与此模式相关的标准,例如,当一周过去了,所有的证明都传递到预期的边界,并且新属性没有发现任何错误时,结束bug hunting FPV。

对于在ALU的bug搜索FPV计划中的退出标准,可以选择以下这些:

  • 在选择的过约束条件下,运行了所有指定的covers,并在50个循环的范围内证明了正确ALU功能的算术单元断言。由于这种设计的逻辑深度,预计所有覆盖将在少于25个周期内覆盖;如果事实并非如此,需要重新评估上述50的界限。

  • 假设通过了可用的模拟运行。

  • 时间限制:两周。

(2)把所有内容联合起来

基于在前面小节中描述的各种考虑因素,ALU的FPV计划如表6.1所示。这比前一章中简单的 design exercise 计划要复杂一些。不要让这吓到你,计划是任何FV努力的关键部分。

目标

验证算术单元的正确行为,在没有任何不寻常的活动(如电源门控制或扫描/调试挂钩)的情况下,默认DSIZE 08

属性

创建覆盖点,复制说明算术单元行为的规范中的每个波形。

用非零输入覆盖每个算术操作(ADD、SUB、CMP),单独地或背靠背地使用另一个任意操作。

覆盖上述每个操作的案例,使用特定的数据来执行所有位,假设dft(扫描)输入被关闭。

假设所有操作都是算术运算,而不是逻辑运算。

•如果最初的假设证明编写起来很复杂,可以考虑一个参考模型来驱动输入逻辑,以确保每个循环只驱动两个有效指令。

由于对逻辑单元进行了黑盒化,因此添加了一个假设,即逻辑子单元结果有效信号logresultv总是0。

断言当一个有效的操作到达时,一个有效的输出将在三个周期内出现。

断言每个操作都会产生预期的结果:如果选择ADD,输出应该匹配输入的和,等等

•如果指定断言很复杂,可以考虑使用参考模型从每个操作中获得预期的结果。

复杂度分段

初始阶段:黑箱逻辑子单元。设置参数MAXDSIZE为

DSIZE08。假设DFT是非活动的。

如果太复杂:黑盒解码器太,并添加适当的假设。

在时间允许的情况下,提高核查质量的阶段:

•允许所有DSIZE值。

•允许DFT功能。

•非黑盒逻辑子单元

退出标准

在上面指定的过约束条件下,运行了所有覆盖,并证明了算术单元断言为正确的ALU功能,到50个循环的界限。

假设必须通过模拟回归。

时间限制:2周。如果在此之前实现了上述目标,那么通过放弃上述复杂性妥协,机会性地扩展到进一步的FPV阶段。

(3)运行bug hunting FPV

现在已经提出了一个很好的验证计划,是时候开始验证了。跳过将仿真加载到FPV工具,因为假设已经为这个模型开发了一个 design exercise FPV环境。如FPV计划中所述,其中一部分将包括为初始复杂度妥协集提供必要的工具指令。

根据特定的FPV工具而有所不同,但在控制文件中应该会产生类似这样的命令:

# blackbox logic unit
BLACKBOX inst*.logical
# Turn off dft
SET dftslowrd = 0

(4)初始化覆盖点

一组基本的cover points ,检查是否覆盖了每一个算术运算

generate for (j = OPADD; j <= OPCMP; j++) begin: g1
arithmetic1: cover property
(( uopcode == j) ##3 (resultv != 0) );
end
endgenerate

覆盖这些属性将确保所有操作码都可以在设定的环境中使用,证明这些cover points并检查波形就能证实事实。假设对这些的初始覆盖是成功的,并且已经检查了波形。

接下来要验证一个cover points,以便对于一组特定的数据,设计返回一个期望值。为操作码和数据选择一个特殊的值,并检查设计是否正常运行。不打算为每个操作指定所有的值,因为这将违背不需要提供任何向量的形式的基本要求。但是编写这些基本的covers是为了使用者对设计的正确性有一个基本的理解,而不是完整的covers

add08: cover property ( ( uopv &
uopcode == OPADD &
uopsize == DSIZE08
) ##1
( src1 == 32'h8 &
src2 == 32'h4
) ##2
result == 32'hC);

规格书强制要求操作应该在应用实际数据之前启动一个时钟周期,结果计算在数据读入之后需要两个周期,这个covers的执行将展示设计的基本正确性,接下来进行进一步探索。

一个RTL在验证过程中,不希望出现非常基本的错误。这只是第一套covers,看看环境是否设置正确,可以继续添加更多的cover points,以受到额外有趣的启发。随着在bug hunting方面的进一步进展,因为调试FPV波形时观察到的其他有趣案例,可能会想添加更多的覆盖点。

(5)扩展的摆动(wiggling

第五章详细讨论了改动(wiggling)的过程。在开始看到有用的行为之前,可以在一个典型的单元上预期大约10-20次修改

对于本章中所考虑的简单单元,会在摆动周期中更早地达到正常状态。如果之前已经完成了,那么已经经历了一些改动,在这个单元上进行 design exercise FPV,所以不需要完全从头开始

从简单ALU上的改动过程开始。在FPV的初始阶段,cover points比断言更重要,确保在波形中观察到的基本流和行为符合预期,这样就不会错过事实。

wiggling的开始时,cover要重要得多。首先尝试证明上面描述的基本覆盖点,检查每个操作都是可行的,并且示例ADD操作在一个特定的值集上正确地工作(表6.2)。

其中一个算术运算还没有覆盖到,未被发现的覆盖点表明某些设计行为不能在当前的证明设置和假设下重现。这意味着失败的覆盖点不会生成波形,因此调试它可能有点棘手。

可以使用以下几种方法来获取可观测波形,这可以提供关于covers失败原因的线索:

  • 查看相关但略有不同的cover points的波形,以查找意外或不正确的模型行为

  • 创建部分cover points,检查比原始cover points更弱的条件

  • 如果cover points涉及在一个SVA序列中发生的几个事件,则删除一些事件并观察更简单的cover points

在这种情况下,失败的cover points相对简单,因此使用上面的第一种方法来显示已经覆盖的cover points的波形并寻找意外的或不正确的模型行为是最有意义的。调出OPADD运算的波形,可以发现这里覆盖了一个错误的条件,如图6.6所示。

期望在三个时钟周期之后,源输入0x8和0x4的输出变成0x0C。从上图看到自复位以来,结果值始终是0x0C,因此covers通过。进一步调试时,结果值为常量的原因是结果的状态元素是不可复位的——触发器输出可以是任何值。非复位触发器随机获得所需的值。

而且发现结果的有效位始终很高,触发器单元的时钟是完全门控的。引入时钟信号的方程,看到设计的“特征位”信号,最初没有考虑到这是一个问题,在一段时间后被驱动得很高。通常需要与块设计人员或架构师交谈,以找出这个特征位的含义,在大多数实际使用中,这个位将被驱动为零,因此验证团队可以安全地优先考虑这个位为1的情况。

现在需要解决以下两个问题:

  • 使触发器可复位

  • 通过增加假设,即特定位为1'b0,对设计进行过约束。

一旦完成对环境的修改并重新运行,应该看到一个真实的通道,其中cover波形真实地代表了所期望的活动,可能还想修改FPV计划,以记录添加了一个新的过约束的事实。但同一个cover points的失败需要进行第二轮分析,重复观察不同但相关覆盖点的波形过程,得到如图6.7所示的波形

可以看到一个add操作所花费的时间比预期的两个时钟周期还要多:正好多用了一个时钟周期,这是设计中的一个明确的错误,需要修复。修复了设计重新运行,所有的cover points都通过了。在观察了每个passcover points的波形,并特别密切关注之前失败的波形后,对于cover points集,设计是合理的。

虽然可以编写一组独立的断言来检查每个操作,但在这种情况下,创建一个引用模型,计算每个操作的预期结果似乎更有意义。

可以应用一个抽象级别,使其更像是一个影子模型,而不是一个完整的行为模型:我们希望计算逻辑的核心结果,而不包括实际设计的任何复杂性,如流水线、扫描或调试逻辑,还可以利用在最初的bug hunting中所做的过约束的决策。

例如最初选择专注于DSIZE 08。在这种情况下,最初可能会生成这样的东西:

module my_arithmetic ( Clk, uopv, uopcode, uopsize, src1, src2, resultv,
result );
input Clk;
input node uopv;
input node [3:0] uopcode;
input node [2:0] uopsize;
input node [31:0] src1;
input node [31:0] src2;
output node resultv;
output node [31:0] result;
always_comb isuop = (uopcode == OPADD | uopcode == OPSUB
| uopcode == OPCMP );
always_comb begin
opadd = ( uopcode == OPADD );
opsub = ( uopcode == OPSUB );
opcmp = ( uopcode == OPCMP );
end
always_comb begin
unique casex ( 1'b1 )
opadd : result0 = src1 + src2;
opsub : result0 = src1 - src2;
opcmp : result0  =(src1 > src2);
endcase
end;
`MSFF( result1, result0, Clk );
`MSFF( result2, result1, Clk );
`MSFF( result, result2, Clk );
endmodule // my_arithmetic

一旦上面的模块在主ALU中被实例化或绑定,可以添加以下断言来检查实际RTL中的结果是否与参考模型匹配:

assert_equi_check: assert property (uopv |-> ##3 (result == 
my_arithmetic.result ) );

在这里编写了一个非常简单的操作模型。一个简单的断言,即两个单元应该产生相同的输出,将涵盖所有可能的输入组合,为这些操作提供整个数据空间的完整覆盖(在已知的假设和过约束下)。这个参考模型只涵盖了操作和数据大小的一个子集,但是对于它所涵盖的部分是正确的,假设相应的RTL模型被适当地约束为不使用逻辑的其他部分

现在已经编写了参考模型,并且对初始覆盖点上的波形感到满意时,可以尝试证明了。当运行这个设置时,会看到另一个失败,如图6.8所示。

当重新分析失败时,看到src1上的数据没有用于计算,而是使用了dftdata,这是因为没有正确地禁用DFT(扫描)功能,尽管已经计划将其作为最初的过约束之一。

DFT信号通常是与调试相关的信号,通过单独的端口以某种模式提供,并帮助调试现有设计,因此当运行FPV没有关闭DFT后,通常会观察到一些情况,即工具找到了使用它的聪明方法来为断言生成糟糕的结果。

使用了一个过约束的假设来将信号dftslowrd置为0,但在检查波形后,发现这是一个活跃的低信号,确实需要将其设置为1。

一旦添加了正确的DFT约束,并完成了几轮修改,以确定需要在假设中修正的细节,就到达了断言assert_equi_check通过的位置。因为这涵盖了许多操作的综合断言,所以还应该确保在断言传递之后再次检查覆盖点跟踪。

在完成了验证计划中的初始目标之后,可以考虑通过放松先前所做的一些初始妥协来改进验证范围。

一个好的开始是放松禁用defeature位的约束,根据调试过程中发现的问题添加的最后的约束,这是一个后期的妥协,而不是最初的FPV计划的一部分,所以最好找到一种方法来解释它,并正确地验证它的功能。现在应该消除这个过约束,并允许它假设0或1的任意值,而不是将它驱动为0。需要弄清楚在这个信号的不同值下模型的预期行为是什么,并改进参考模型以考虑到这个新功能。

上述有效的话,可以针对复杂度分割计划中提到的项目,进一步扩大验证的范围:允许所有DSIZE值,允许DFT功能,并解除逻辑子模块的黑盒。这些变化中的每一个都可能需要扩展引用模型(或添加第二个并行引用模型)来包括行为的这些新方面。

本例展示了对代码建模的强大功能,并将其用于验证。对于大多数现实生活中的单元,摆动需要更多的迭代才能达到有用的验证阶段。

到目前为止,我们对环境有了良好的信心,并有能力检查各种操作。

(6)扩大覆盖点

在完成FPV工作的每个主要阶段之后,需要再看一看以确保能够达到各种有趣的微架构条件,并且没有不必要地限制模型。

最初的一组覆盖点帮助我们评估开始时的环境质量,并更好地理解设计。

最后的覆盖点,灵感来自于我们对规格书的知识和调试FPV工作期间发现的有趣的角落用例的经验的结合,给了我们必要的信心。

覆盖点是所执行的验证质量的主要指示。

在设计上,covers大多是“白盒”,应该毫不犹豫地观察内部转换和已知的内部逻辑的临界条件。至少应该能够将大多数仿真覆盖规范转换为SVA覆盖点并进行验证;可能还有一些设计领域没有被发现,因为先前通过假设排除了它们。因此,这些保险在评估实现FPV目标的过程中非常重要。

注意:当放松过约束并扩展验证空间时,要再次检查基本覆盖点,因为任何约束的放松都可能导致整体功能的重大变化。

一些基本操作可能会以不同的方式覆盖,或者覆盖点可能变得不那么有用。

例如,打开DFT逻辑时,它允许为每个主要状态元素扫描任意值,我们会发现突然间每个覆盖点都被一个微不足道的例子覆盖了DFT打开,恰好扫描到正确的值。需要仔细地修改覆盖点,以便它们仍然能够真正覆盖预期的功能。

六、去除简化,探索更多行为

假设已经达到了对算术逻辑的验证有信心的地步,并且现在已经解除了逻辑子单元的黑盒,同时删除了之前限制进行算术操作的假设。经在顶层模型中添加了一个断言,用于检查操作是否总是具有适当的延迟。

Resultv_correct_wrt_uopv: assert property ( uopv |-> ##3 resultv );

试图证明上述断言时,可能会得到如图6.9所示的反例

上图可以看出,操作码5'h10在设计的可接受操作码列表中没有定义。因此,试图在一次测试中启用所有操作码的检查时,设计行为是错误的。

放宽一些假设和扩大验证空间时的另一种常见情况:允许更广泛的合法行为为更广泛的非法行为开放。因此需要添加另一个假设:

Legal_opcode: assume property
( valid_arithmetic_op ( uopcode ) ||
valid_logical_op (uopcode) );

1、通向Full proof FPV之路

如果在模型上运行FPV有了经验,可以从一开始就开始计划full proof FPV ,将bug hunting 作为计划的初始阶段。

如果缺乏经验,首先要进行bug hunting FPV,并可能考虑在这些工作成功的基础上扩展到full proof 。能否验证规范的所有要求,使基于仿真的单元级验证对于当前模块来说是多余的?

在上述的ALU例子中,看起来full proof FPV可能是一个合理的目标。一旦完成了复杂度阶段(分割)计划中确定的所有步骤,并发现向证明中添加更多的一般性并不会导致复杂度的爆炸,可以退一步并问一个问题:是否可以使这成为一个完整的证明环境并退出我们的仿真工作?

最初的计划是基于bug hunting的,所以有一些关于验证的完整性的重要问题要问:

专注于寻找bug时,只要想出一小组有趣的属性就足够了,这有助于找到并揭示一些bug。一般必须在质量检查中制定更严格的计划,以对full proof FPV有信心。

需要问一个更难的问题:是否拥有一组完整的属性,能够完全检查设计规范的所有需求?FPV运行包含了整个RTL模型,或机械测量覆盖率,工具声称所有行都已执行,这并不意味着我们已经完全验证了规格书。

在大多数情况下,规格书是用非机器语言编写的非正式文档,因此没有简单的方法直接回答这个问题。必须仔细检查此文档,并确保列出的每个需求都被转换为断言,或者可以被描述为不可翻译的。

还需要检查断言是否足够强,以充分执行规格书。

例如,假设上述断言不需要3的延迟,写了一个像下面这样的断言,最终会得到一个答案:

resultv_correct_sometime: assert property
(uopv |-> s_eventually(resultv));

这可以检查ALU的正确性,并可能帮助我们找到一些与完全丢弃的操作相关的错误,但实际上这将无法完全检查延迟需求。

检查假设和覆盖点也是这个审查的关键部分,必须确保覆盖点涵盖了所有的主要操作,以确保在验证中没有留下任何空白。

还应该检查假设集,并确保它没有意外地排除对规范的任何部分的分析。这样做之后,一定要向设计架构师展示我们提议的规范属性集,并让他们相信我们的验证计划确实是完整的。

在上述ALU中,整体的功能是非常明确的:有一组操作,对于每一个操作,需要确保它根据输入生成适当的输出。

还需要检查像DFT这样的极端情况异常,从最初的bug hunting FPV中排除了它,并确保我们的单元在这些情况下正确运行。

应该确保创建了描述每个异常的正确操作的断言,以及重复检查的覆盖点,以确保每个异常都可以在最终的假设集下执行。

只要密切关注设计规范的要求,这在单元级别上通常是可行的,并且可以比通过全面的仿真测试平台进行验证要小得多。在任何情况下,仔细审查的需求并不是FPV引入的新需求:同样的担忧和危险,例如不完整或过于弱的检查的危险,也适用于仿真和其他验证方法。

full proof FPV 已经在英特尔的许多项目的选定单元上成功运行,并被发现从长远来看,以更低的工作量显著提高设计质量。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值