《SVA断言系统学习之路》【01】即时断言概览
今天,开始学习SVA相关知识,确切说是系统学习相关知识,希望整理完该系列文章之后,自己能熟练掌握相关知识点,并总结常见错误。
系列文章,围绕的主题内容如下:
— 即时断言
— 并发断言
— 序列规范
— 属性规范
一 断言概要
断言用于规定系统行为规范,主要应用于验证设计行为的正确性。此外,断言还可提供功能覆盖率指标,并标记验证过程中不符合预设要求的输入激励。
断言以声明语句形式呈现,用于声明需要执行的验证功能。该语句应属于以下类型之一:
— assert(断言):将属性指定为设计必须满足的义务,通过检查确认属性是否成立;
— assume(假设):将属性指定为环境前提条件,仿真器验证属性是否成立,形式化工具则利用该信息生成输入激励;
— cover(覆盖):监测属性执行情况以获取覆盖率数据;
— restrict(约束):将属性指定为形式化验证的计算约束条件(仿真器不检查该属性)。
二 断言分类
断言可分为两类:并发断言、即时断言。
— 即时断言遵循仿真事件语义执行,其行为类似于过程块中的语句。该类断言主要适用于仿真场景,且不存在即时类型的restrict断言语句。
— 并发断言基于时钟语义,并采用表达式的采样值进行计算(参见16.5.1节)。
SystemVerilog断言的核心目标之一是为断言提供统一语义规范,使其能够驱动多种设计与验证工具。形式验证等工具通常采用基于周期的语义评估电路描述,这类评估依赖一个或多个时钟信号驱动电路分析,并将时钟边沿之间的时序或事件行为进行抽象化处理。并发断言正是融合了这种时钟语义。
虽然这种方式通常能简化电路描述的评估过程,但在某些场景下,这种基于周期的评估会产生与SystemVerilog标准事件驱动评估不同的行为特征。
三 即时断言
即时断言语句是对表达式的一种测试,该测试在过程代码执行该语句时进行。表达式不具有时序性,其解释方式与过程化if语句中的条件表达式完全相同。具体而言:若表达式计算结果为X、Z或0值,则判定为假值,此时断言语句被视为失败;若表达式计算结果为其他非零值,则判定为真值,此时断言语句被视为通过(或等效称为成功)。
即时断言分为两种模式:简单即时断言、延迟即时断言。
简单即时断言在评估完成后立即执行通过/失败操作;而延迟即时断言则将相关操作延迟至当前时间步长的后期执行,这种机制可有效规避因瞬态值或"毛刺"值导致的意外多次执行问题。延迟即时断言的具体规范详见16.4节。
3.1 即时断言的语法
这条规则说明,一个“过程断言语句”可以是多种类型之一(用
procedural_assertion_statement ::= ... | immediate_assert_statement
...
表示),其中一种就是“即时断言语句”(immediate_assert_statement
)。|
表示“或”。“即时断言语句”由以下部分组成:
immediate_assert_statement ::= assert ( expression ) action_block
动作块
action_block
: 定义了当断言成功或失败时该执行什么操作。表达式
expression
: 这是断言的核心,是一个返回真或假的逻辑条件(例如a == b
,data_valid && !data_error
)。关键字
assert
: 声明这是一个断言。“动作块”有两种写法:
action_block ::= statement_or_null | [ statement ] else statement
[ statement ] else statement
: 这是更完整的格式。
[ statement ]
: 这是可选的 “成功语句”。当断言成功时执行。它被方括号[ ]
包裹,表示它是可选的,可以省略。关键字
else
: 连接成功和失败分支。
statement
: 这是 “失败语句”。当断言失败时执行。
statement_or_null
: 一个单独的语句(如$display(...)
),或者空(即只有一个分号;
)。如果使用这种格式,只有当断言失败时,才会执行这条语句。断言成功则不执行任何操作。
3.2 模块名+%m
可选语句标签(标识符和冒号)可为断言语句(或任何其他SystemVerilog语句)创建命名的代码块,该标签可通过%m格式规范显示。
assert_foo : assert(foo) $display("%m passed"); else $display("%m failed");
举例:
module my_chip (input logic clk, foo);always @(posedge clk) begin// 我们的带标签的断言assert_foo : assert(foo) $display("%m passed"); else $display("%m failed");end
endmodulemodule testbench;logic clk, foo;my_chip dut (.clk(clk), .foo(foo)); // 实例化模块,实例名为 dut
endmodule仿真运行时可能出现的输出:当 foo 为 1(断言通过)时:testbench.dut.assert_foo passed
当 foo 为 0(断言失败)时:testbench.dut.assert_foo failed
3.3 辅助打印函数
由于断言是对某项条件必须为真的陈述,因此断言失败必须具有与之关联的严重级别。默认情况下,断言失败的严重级别为错误(error)。可通过在失败语句中包含以下严重性系统任务来指定其他严重级别:
— $fatal:运行时致命错误
— $error:运行时错误(默认级别)
— $warning:运行时警告,可通过工具特定方式抑制
— $info:指示断言失败不携带特定严重性
若断言失败且未指定else子句,默认情况下工具应调用$error,除非启用了工具特定选项(如命令行选项)来抑制失败。
所有此类严重性系统任务都应打印工具特定的消息,其中应包含以下信息:
— 断言语句所在的文件名和行号
— 若断言带有标签,则包含其层次化名称;若未标签,则包含其作用域范围
对于仿真工具,这些任务还应包含调用严重性系统任务时的仿真运行时间。
每个系统任务还可使用与Verilog $display相同的格式来包含用户指定的附加信息。
若else子句中包含多个此类系统任务,则应按照指定顺序全部执行。
若严重性系统任务在断言失败之外的时间点执行,则可通过编程方式记录并显示断言的实际失败时间。例如:
此外,警告(warning)和信息(info)类消息的显示可通过工具特定选项(如命令行选项)进行控制。
由于失败语句(fail statement)与通过语句(pass statement)一样,同属合法的SystemVerilog过程语句,因此也可用于向测试平台的其他部分发送故障信号。举例:
assert (myfunc(a,b)) count1 = count + 1; else ->event1;assert (y == 0) else flag = 1;