我的 System Verilog 学习记录(13)


引言

本文简单介绍 SystemVerilog 的 断言。

前文链接:

我的 System Verilog 学习记录(1)

我的 System Verilog 学习记录(2)

我的 System Verilog 学习记录(3)

我的 System Verilog 学习记录(4)

我的 System Verilog 学习记录(5)

我的 System Verilog 学习记录(6)

我的 System Verilog 学习记录(7)

我的 System Verilog 学习记录(8)

我的 System Verilog 学习记录(9)

我的 System Verilog 学习记录(10)

我的 System Verilog 学习记录(11)

我的 System Verilog 学习记录(12) 



介绍

系统的行为可以写成在任何时候都应该为真的断言。因此,断言用于验证定义为属性的系统行为,也可以用于功能覆盖。

设计的参数是啥?

如果断言正在检查的设计的属性没有以预期的方式运行,则该断言将失败。例如,假设设计请求仲裁,并期望在接下来的四个周期内收到一个ack。但是,如果设计在第五个周期中得到一个ack,那么在4个时钟内返回一个ack的属性就会被违反,断言将失败。
如果断言正在检查的设计属性被禁止发生,则断言将失败。例如,假设一个小的处理器解码从内存中读取的指令,遇到一个未知的指令,并导致一个致命的错误。如果设计中不会出现这样的场景,则违反设计中只能从内存中读取有效指令的属性,断言失败。
从上面的两个例子中可以明显看出,一个给定设计的属性是通过编写SV断言来检查的。

为何需要断言?

断言只不过是对功能检查器的一种更简洁的表示。由断言所表示的功能也可以被写为一个涉及到更多的代码行的系统验证器任务或检查器。这样做的一些缺点如下:

  • SV 非常冗长,难以维护,并根据属性的数量来缩放代码
  • 作为一种过程性语言,很难编写在同一时间段内涉及许多并行事件的检查器

SystemVerilog断言是一种用于指定时态条件的声明性语言,非常简洁且更易于维护。

断言语句类型

构造断言块 

时序

多个逻辑事件的时序通常构成任何设计的功能。这些事件可能跨越多个时钟,或者只存在于一个时钟周期中。为了保持简单,可以使用简单的断言来描述较小的事件,然后可以使用这些断言来构建更复杂的行为模式。

属性/参数

这些事件可以表示为一个序列,并且可以组合多个序列以创建更复杂的序列或属性。为了断言序列或属性,必须在序列或属性中包括时钟事件。

 有两种断言类型 - 立即和同时。

立即断言

立即断言像过程块中的语句一样执行,并遵循仿真事件语义。这些断言用于在仿真期间验证立即属性。

同时断言

并发断言基于时钟语义并使用其表达式的采样值。电路行为使用SystemVerilog属性描述,该属性在给定时钟上每次都会被评估,并且仿真中的失败表明所描述的功能行为被违反。

创建断言的步骤:

  • 创建布尔表达式
  • 创建序列表达式
  • 创建属性
  • 断言属性

示例

第一序列s_ab在a为高时确认下一个时钟b为高,第二序列s_cd在c被发现为高后2个时钟确认d为高。


立即断言

立即断言基于仿真事件语义执行,需要在程序块中指定。在仿真过程中,它与 if 语句中的表达式相同。
如果表达式在执行语句时保持为true,则立即断言将传递,如果表达式的计算结果为false(X、Z或0),则将失败。这些断言旨在用于仿真,并不适用于形式验证。它可以用于RTL代码和测试台来标记仿真中的错误。

用法

设计中的立即断言

下面是一个示例,其中设计使用立即断言来检查对FIFO的 push 请求是否在FIFO已经满的时候到来。如果 assert 语句中的表达式求值为 true,则执行第一个 begin end 块,如果该表达式求值为false,则计算 else 部分。这与 if 构造非常相似,不同之处在于用户不需要放置 display 语句来标记错误。

如果没有这样的即时断言,使用额外的努力和资源的并发断言来复制通向该特定点的逻辑。

 仿真结果:

Testbench中的立即断言

假设创建了一个名为Packet的类并将其随机化。然而,此示例有一个约束错误,随机化将失败。但是,失败将显示为警告消息,如果用户不够小心,测试可能会显示不正确的行为,甚至可能看起来通过。

仿真结果:

相反,可以在随机化方法调用上放置立即断言,以确保返回值始终为1,表示随机化成功。如果断言失败,它会提示用户首先查看失败,从而减少调试工作。


并发(同时)断言

并发断言描述了跨越仿真时间的行为,并且只在时钟提示出现时进行评估。
SV并发断言语句可以在与其他语句并发运行的模块、接口或程序块中指定。以下是并发断言的属性:

  • 基于采样变量中的值,在时钟边缘评估测试表达式
  • 在准备区域对变量进行采样,并在模拟调度器的观测区域对表达式进行评估。
  • 它可以被放置在程序块、模块、接口或程序块中
  • 它可以用于动态的和形式验证技术

示例1

两个信号a和b被声明并在时钟的正边缘驱动,以说明并发断言是如何工作的。断言是由即时属性上的断言语句编写的,该属性定义了时钟事件中信号之间的关系。
在这个例子中,在整个仿真中,信号a b 都期望在时钟的正边拉高。对于发现a、b为零的所有实例,断言都将失败。

断言在CLK的每个正沿上执行,并使用预置区域中的变量的值来计算表达式,该区域是时钟给定边沿之前的增量周期。因此,如果在与时钟相同的边沿上从0变为1,则Take for Assertion的值将为零,因为它恰好在时钟边沿之前为零。

 可以看出,对于发现a或b为零的所有情况,断言都失败,因为在整个模拟持续时间内,断言语句中给出的表达式预期为真。

示例2

定义为ASSERT语句的属性的表达式从上面的示例修改为OR条件。

示例3

被定义为ASSERT语句的属性的表达式从上面的示例修改为XNOR条件;


$rose,$fell,$stable

序列是SystemVerilog断言中的一个简单构建块,它可以表示某些表达式,以帮助创建更复杂的属性。

简单序列

 $rose

系统任务 $rose 用于检测给定信号的正沿。在这种情况下,$rose 表示预期在CLK的每个后沿上都能看到a的后沿。因为SystemVerilog断言在预置区域中求值,所以它只能在预置区域中检测给定信号的值。当信号的值在第一个边沿为0,然后在下一个边沿为1时,假设已经发生了正边沿。因此,这需要识别2个时钟。

在下图中可以看到,检测到了一个正沿,并且断言在30 ns的时候通过。这是因为AIS的值在10 ns时为0,在30 ns时为1,断言完成并被证明是成功的。

$fell

系统任务 $felli 用于检测给定信号的负边缘。在这种情况下,$fell  表示 a 的负边缘预计会出现在 clk 的每个姿态上。因为 SystemVerilog 断言在预置区域中计算,所以它只能检测预置区域中给定信号的值。当信号的值在第一个边上是1,然后在下一个边上是0时,假设已经发生了负边。因此,这需要识别2个时钟。与 $rose 相反

 $stable

指被检测信号的电平未出现跳变。


断言时延 ##

## 操作符

如果a在任何给定时钟周期不为高,则序列在同一周期开始和失败。但是,如果a在任何时钟上为高,则在两个时钟之后,如果b为高,则断言开始并成功。如果在两个时钟之后,b为低,则断言失败。



猜你喜欢

转载自blog.csdn.net/qq_43045275/article/details/129888840