第二章SVA 断言语言基础

SVA 断言的三种类型

SystemVerilog Assertions (SVA) 是 IEEE 标准的断言语言。在 FPV 中,SVA 用于编写属性来验证设计行为。

Assert(断言)

断言描述设计必须始终满足的行为。如果断言被违反,工具会产生反例。

Assume(假设)

假设约束输入环境。形式验证工具只考虑满足所有假设的输入序列。合理的假设是避免虚假反例(false failure)的关键。

Cover(覆盖)

覆盖点指定设计应该能到达的状态。如果覆盖点被击中(covered),说明该行为是可达的。

断言语法结构

一个典型的 SVA 断言模块如下(来自示例中的 v_arbiter.sva):

example/.../v_arbiter.sva
module v_arbiter (
  clk, rstN,
  gnt, req,
  int_ready, int_valid, trans_started
);
input clk, rstN;
input [3:0] gnt, req;
input int_ready, int_valid, trans_started;

  // Assertion "grant_is_onehot0"
  //  Grant signal is one-hot or zero
  //
  property grant_is_onehot0;
    @(posedge clk) $onehot0(gnt);
  endproperty
  a_grant_is_onehot0: assert property (grant_is_onehot0);

  // Assertion "grant_is_one_cycle"
  //  Grant signal is high for one cycle only
  //
  property grant_is_one_cycle;
    @(posedge clk) (gnt!=4'b0) |=> (gnt==4'b0);
  endproperty
  a_grant_is_one_cycle: assert property (grant_is_one_cycle);

  // Functional coverage points
  //
  // Request
  c_req0: cover property (@(posedge clk) (req[0]));
  c_req1: cover property (@(posedge clk) (req[1]));
  c_req2: cover property (@(posedge clk) (req[2]));
  c_req3: cover property (@(posedge clk) (req[3]));
  //
  // Grant
  c_gnt0: cover property (@(posedge clk) (gnt[0]));
  c_gnt1: cover property (@(posedge clk) (gnt[1]));
  c_gnt2: cover property (@(posedge clk) (gnt[2]));
  c_gnt3: cover property (@(posedge clk) (gnt[3]));
  //
  // Control signals
  c_int_ready: cover property (@(posedge clk) (int_ready));
  c_int_valid: cover property (@(posedge clk) (int_valid));
  c_trans_started: cover property (@(posedge clk) (trans_started));
  //
  
  // Same functional coverage as above, described using covergroups
  covergroup cg @(posedge clk);
    c_req: coverpoint req {
      bins port[4] = {8, 4, 2, 1};
    }
   

关键语法元素

语法文档中的名称含义
@(posedge clk)clocking eventclocking event 是 posedge/negedge 指示符与一个时钟信号的组合;表达式在每个 clocking event 上被检查
|->overlapping implication
(重叠蕴含)
蕴含式左边是 antecedent(前提),右边是 consequent(后果);后果与前提在同一拍求值
|=>nonoverlapping implication
(非重叠蕴含)
后果在前提的下一拍求值
##ncycle delay(周期延迟)n 为非负整数。除 ##<num> 外还支持 ##<constant id>##(<expr>)##[<left>:<right>]##[<leftLim>:$];其中 expr / left / right 必须能求值为常量
e[*n]consecutive repeat
连续重复)
连续重复 n 次。支持非负整数及区间 <leftLim>:<rightLim><leftLim>:$
e[=n]nonconsecutive repeat
(非连续重复)
非连续地重复 n 次,区间写法同上
e[->n]goto repeat"一直走到第 n 次成立为止",区间写法同上
$onehot0()Bit Vector System Functionevaluates all onehot values including 0——即 one-hot 或全零都算成立
$past()Sampled Value System Function引用之前若干拍的采样值。可带周期数参数,如 $past(src, 2) 表示前 2 拍;不写则为前 1 拍
工具相关的两点:①同属 Sampled Value System Function 的还有 $rose$fell$stable$changed$sampled;文档提示"在当前实现中,flop 在复位周期内不被驱动,其复位值由 reset analysis 决定"。②同属 Bit Vector System Function 的还有 $onehot$countones$isunknown

Bind 机制

SVA 的 bind 语句允许将断言模块绑定到 RTL 模块上,无需修改 RTL 源码:

bind arbiter
  v_arbiter i_arbiter (
    .clk(clk), .rstN(rstN),
    .gnt(gnt), .req(req),
    .int_ready(int_ready),
    .int_valid(int_valid),
    .trans_started(trans_started)
  );

这将断言模块 v_arbiter 实例化到 arbiter 模块内部,信号按名称映射。

断言命名规范

官方示例文件 v_arbiter.sva 里用的是这两个前缀:

assumption 的前缀在这两个示例里没有出现——它们不含 assume。Cadence 自己的 Proof Accelerator 文档中用的是 asm_

asm_my_tag_constant: assume property (@(posedge clk) $stable(my_tag));
这类前缀是工程惯例,不是工具强制要求。JasperGold 并不靠标签前缀区分属性类型——类型由 assert / assume / cover 关键字本身决定。统一前缀的实际好处是在 Property Table 里便于按名称过滤。

VHDL + PSL 支持

JasperGold 也支持 VHDL 设计使用 PSL 语言编写断言:

example/.../vhdl_psl/source/properties/v_arbiter.vhd.psl
vunit v_arbiter (arbiter(rtl)) {

  default clock is rose(clk);

  -- Assertion "grant_is_onehot0"
  --  Grant signal is one-hot or zero
  --
  property grant_is_onehot0 is onehot0(gnt);
  a_grant_is_onehot0: assert always grant_is_onehot0;

  -- Assertion "grant_is_one_cycle"
  --  Grant signal is high for one cycle only
  --
  property grant_is_one_cycle is (gnt/="0000")  -> next(gnt="0000");
  a_grant_is_one_cycle: assert always grant_is_one_cycle;

  -- Functional coverage points
  --
  -- Request
  c_req0: cover {req(0)};
  c_req1: cover {req(1)};
  c_req2: cover {req(2)};
  c_req3: cover {req(3)};

} -- v_arbiter

这是与前面 SVA 版本完全对应的 PSL 写法,可以对照着看清两种语言的差异:

概念SVAPSL
时钟声明@(posedge clk) 写在每条 property 里default clock is rose(clk); 在 vunit 里声明一次
蕴含|-> / |=>->
下一拍|=>next(...)
one-hot0$onehot0(gnt)onehot0(gnt)
覆盖点cover property (...)cover {...}
断言绑定bind 语句vunit v_arbiter (arbiter(rtl))

PSL 文件用 analyze -psl 读入(该开关用于分析没有内嵌在 RTL 里的 PSL,例如 vunit 文件)。

建议初学者从 SVA 开始学习,因为 SVA 与 SystemVerilog 设计语言紧密集成,是工业界最广泛使用的断言语言。

断言设计原则

学会 SVA 语法不等于会写好断言。写有效的断言是形式验证的核心技能。

好断言的特征

assert vs assume vs cover:三剑客分工

类型用途含义
assert检查器"这个性质必须始终成立"——如果违反,是 bug
assume约束"假设输入始终满足这个条件"——限制形式引擎的输入空间
cover覆盖点"这个场景应该能够到达"——验证约束不过强、确认设计能进入关键状态
黄金三角:每个关键功能应该同时有 assert(验证输出正确)、assume(约束输入合法)、cover(确认合法场景可达)。三者缺一不可。

bind 机制的优势

SVA 的 bind 指令允许将断言文件"绑定"到 RTL 模块实例上,而无需修改 RTL 源码:

example/.../verilog_sva/source/properties/bindings.sva
// bindings.sva — 不修改 RTL 就能加断言
bind arbiter
//   ↑被绑定的目标模块名
  v_arbiter i_arbiter (
//↑断言模块  ↑实例名
  .clk(clk), .rstN(rstN),
  .gnt(gnt), .req(req),
  .int_ready(int_ready), .int_valid(int_valid), .trans_started(trans_started)
);
官方示例一律使用按名称连接.port(signal))而不是按位置连接。断言模块 v_arbiter 的端口顺序是 clk, rstN, gnt, req, int_ready, int_valid, trans_started,按位置连接时一旦顺序记错(例如把 gntreq 写反)就会静默接错线,而按名称连接不会有这个风险。

好处:RTL 代码保持干净;同一套断言可以绑定到不同实例;断言可以独立版本管理。

常见断言错误

错误类型症状解决
断言太强合法输入也触发 fail(假反例)添加前提条件(antecedent |-> consequent)
断言太弱bug 漏过去了(假 proven)增加检查条件,更精确描述预期行为
不可证引擎永远超时加时间窗限制、拆分为更小的断言
蕴含时序用错consequent 的求值时刻比预期早一拍或晚一拍分清两者:|->(overlapping)让 consequent 与 antecedent 在同一拍求值,|=>(nonoverlapping)让它在下一拍求值

完整断言编写思路

  1. 确定协议:用自然语言写下要检查的设计行为("当 req 拉高后,最多等 3 个周期 gnt 必须拉高")
  2. 定义前提:什么条件下这个规则适用?("当复位释放后且没有全局错误")
  3. 描述后果:在前提满足时应该发生什么?
  4. 添加 cover:写一个 cover 属性确认这个场景确实能到达
  5. 写反例测试:故意造一个 bug 验证断言会 fail,确保断言真的在检查

来源文档

  • AN_scripting.pdf
  • example_jaspergold_apps/FPV/
  • example_jaspergold_apps/designs/reference_design/verilog_sva/source/properties/(v_arbiter.sva、bindings.sva)
  • example_jaspergold_apps/designs/reference_design/vhdl_psl/source/properties/(v_arbiter.vhd.psl)
  • jaspergold_command_reference.pdf(analyze -psl)