SVA断言 并发断言16.14学习笔记(四)

目录

1、限制语句

2、在程序代码之外使用并发断言语句

3、在过程代码中嵌入并发断言

3、过程并发断言的参数


16.14 Concurrent assertions

1、限制语句

        在形式验证中,为了使工具收敛于属性证明或将设计初始化为特定状态,通常需要约束状态空间。为此,引入了断言语句restrict property。它与assume property具有相同的语义,但又与该语句相反,restrict property语句未在仿真中验证,并且没有动作块。

        该语句有如下的格式:

restrict property (property_spc);

        没有与该语句关联的操作块。例如:

        假设当控制位ctr的值为0时,ALU执行加法,当其为1时,执行减法。当ALU执行加法时,需要正式验证某些行为是否正确(在另一个验证会话中,可以通过更改限制对减法执行相同的操作)。因此,可以使用以下语句约束行为:

restrict property (@(posedge clk) ctr == '0);

        这并不意味着ctr在仿真的任何测试用例中都不能为1。

2、在程序代码之外使用并发断言语句

        并发断言语句可以被用在程序环境外,能被用在mudule、interface、program。并发断言语句是assert、assume、cover、restrict语句,这样的并发断言语句使用always语义,这意味着它指定在每次出现其前导时钟事件时,都开始对底层property_spec进行新的求值尝试。

        下面两种形式等价:

assert property ( property_spec ) action_block
always assert property ( property_spec ) action_block ;

        这两种也等价

cover property ( property_spec ) statement_or_null
always cover property ( property_spec ) statement_or_null

        例如:

module top(input logic clk);
logic a,b,c;
property rule3;
@(posedge clk) a |-> b ##1 c;
endproperty
a1: assert property (rule3);
...
endmodule

        在模块top中声明属性rule3,断言语句a1从仿真开始到结束开始检查属性,属性始终处于检查状态。同样,

module top(input logic clk);
logic a,b,c;
sequence seq3;
@(posedge clk) b ##1 c;
endsequence
c1: cover property (seq3);
...
endmodule

        覆盖语句c1从仿真开始到结束开始覆盖序列seq3,始终监视序列的覆盖范围。

3、在过程代码中嵌入并发断言

        并发断言语句能被嵌入到程序代码中,例如:

property rule;
a ##1 b ##1 c;
endproperty
always @(posedge clk) begin
<statements>
assert property (rule);
end

        术语过程并发断言(procedural concurrent assertion)用于指出现在过程代码中的任何并发断言语句,与立即断言不同,过程并发断言在到达过程代码时不会立即评估。相反,断言及其断言参数中出现的所有常量和自动表达式的当前值,被放置在与当前执行的进程相关联的过程断言队列中。该队列中的每个条目都被称为挂起的过程断言实例。由于过程中的任何给定语句都可能执行多次(例如在循环中),因此特定的过程并发断言可能会在单个时间步长内导致许多挂起的过程断言实例,出现在过程代码之外的并发断言语句称为静态并发断言语句。

        在每个仿真时间步的观察区,当前存在于过程断言队列的每一个待处理过程断言实例会成熟,这意味着它将被确认执行。当待处理的过程性断言实例成熟时,如果当前时间步长对应于该断言实例的前导时钟事件,则断言的评估尝试将在观察到的区域内立即开始。如果断言的前导时钟事件在此时间步中未发生,则成熟实例应放在成熟断言队列上,这将导致断言在与断言的前导时钟事件对应的下一个时钟事件上开始评估尝试。


感觉上面这部分好学术,我太垃圾了看不懂。

        例如,在下面的代码片段中,时钟事件@(posedge mclk)被推断为r1_p1的时钟事件,而r1_p2被@(posedge scanclk)写入

property r1;
q != d;
endproperty
always @(posedge mclk) begin
q <= d1;
r1_p1: assert property (r1);
r1_p2: assert property (@(posedge scanclk)r1);
end

        上述断言r1_p2的结果行为取决于mclkscanclk的相对频率。例如:
(1)如果scanclk以两倍于mclk的频率运行,则只有scanclk的每隔一个posedge将导致r1_p2的评估。它仅在过程执行期间到达时排队,这发生在mclk的上升沿上。
(2)如果mclk以两倍于scanclk的频率运行,则通过scanclk的每个posedger1_p2的两个待处理过程实例将成熟。因此,scanclk的每个posedge都将看到r1_p2的评估结果和两次报告的结果。

        如下所示更复杂的例子也是合法的:

property r2;
q != d;
endproperty
always_ff @(posedge clock iff reset == 0 or posedge reset) begin
cnt <= reset ? 0 : cnt + 1;
q <= $past(d1);
r2_p: assert property (r2);
end

        在之前的例子中,推断出的时钟是posedge clock iff reset == 0,推断出的时钟不是posedge clock,因为posedge clockposedge clock iff reset==0的正确子表达式。

        相反,在以下情况,不会推断出always_ff上下文的时钟:

property r3;
q != d;
endproperty
always_ff @(clock iff reset == 0 or posedge reset) begin
cnt <= reset ? 0 : cnt + 1;
q <= $past(d1); // no inferred clock
r3_p: assert property (r3); // no inferred clock
end

       无法推断边缘表达式posedge reset,因为在过程中引用了reset,并且无法推断表达式clock iff reset==0,因为它没有边缘标识符。在没有默认时钟的情况下,上述代码会导致错误。

        在以下例子中,在always过程块中,由于多种事件控制和延迟,不会推断出时钟。

property r4;
q != d;
endproperty
always @(posedge mclk) begin
#10 q <= d1; // delay prevents clock inference
@(negedge mclk) // event control prevents clock inference
#10 q1 <= !d1;
r4_p: assert property (r4); // no inferred clock
end

3、过程并发断言的参数

      过程并发断言在将断言求值(评估)尝试添加到过程断言队列时,保存其常量表达式和自动变量的值,这个断言求值尝试使用这些保存的值进行求值。例如:

// Assume for this example that (posedge clk) will not occur at time 0
always @(posedge clk) begin
int i = 10;
for (i=0; i<10; i++) begin
a1: assert property (foo[i] && bar[i]);
a2: assert property (foo[const'(i)] && bar[i]);
a3: assert property (foo[const'(i)] && bar[const'(i)]);
end
end

        在任何给定的时钟循环,每个断言将导致10个排队执行,然而断言a1的每次执行,将会检查(foo[10] && bar[10])的值,因为i的采样值始终是10,它是该过程前一次执行的最终值。在a2的情况中,其执行会检查(foo[0] && bar[10]), (foo[1] && bar[10]), ...(foo[9] && bar[10]);断言a3,因为它对i的两种用法都有const强制转换,将会检查(foo[0] && bar[0]), (foo[1] && bar[1]), ... (foo[9] && bar[9]),因此,上面的代码片段在逻辑上等同于(除了实例名)以下代码:

default clocking @(posedge clk); endclocking
generate for (genvar i=0; i<10; i++) begin
a1: assert property (foo[10] && bar[10]);
a2: assert property (foo[i] && bar[10]);
a3: assert property (foo[i] && bar[i]);
end
endgenerate

       由于自动变量也保留了其直接值,因此在以下示例中,所有三个属性a4、a5和a6在逻辑上是等效的:

always @(posedge clk) begin
// variable declared in for statement is automatic (see 12.7.1)
for (int i=0; i<10; i++) begin
a4: assert property (foo[i] && bar[i]);
a5: assert property (foo[const'(i)] && bar[i]);
a6: assert property (foo[const'(i)] && bar[const'(i)]);
end
end

        当过程并发断言包含时态表达并已成熟,程序(过程)的执行流不在直接影响未来时间步的成熟实例。另外,过程执行仅影响断言实例的激励,而不影响将来时态表达式的完成。然而,由于常量或自动变量而传递到断言实例的任何常量值,在该实例求值期间都将保持不变。以下示例说明了此行为:

wire w;
always @(posedge clk) begin : procedural_block_1
if (my_activation_condition == 1) begin
for (int i=0; i<2; i++) begin
a7: assume property (foo[i] |=> bar[i] ##1 (w==1'b1));
end
end
end

        当my_activation_condition是1时的时间步期间,a7的两个待处理实例会被放置在过程断言队列上,的每个值对应一个实例。假设他们成功成熟,foo[0]在当拍是真,这意味着在下一个clk的上升沿上,不管procedural_block_1求值或者my_activation_condition的值如何,a7成熟的实例会检查bar[0]是否为真。断言在排队时的自动i的常量值仍然有效,用于此断言评估的此时钟周期和任何未来时钟周期,然后,一个周期后,断言也会检查w的采样值是否为1'b1。

        同样的规则使用于过程并发断言参数,也适用于出现在其动作块的参数。因此,常量或自动值可用于动作块以及断言语句本身,其中它们作为动作块的输入,不应修改。下面的示例显示了此行为:

// Assume for this example that (posedge clk) will not occur at time 0
always @(posedge clk) begin
int i = 10;
for (i=0; i<10; i++) begin
a8: assert property (foo[const'(i)] && bar[i]) else
$error("a8 failed for const i=%d and i=%d",
const'(i), $sampled(i));
end
end

        失败时,前面断言的任何实例都将显示该实例中,用于“const i=”的常量值i(可以是0到9),而打印的字符串将始终以“i=10”结尾,因为10将是从前置区域捕获的采样值。

      当使用条件在代码中嵌入过程并发断言时,重要的是要记住使用过程中条件的当前值,而不是采样值。这与使用采样值的断言表达式形成对比。下面的例子说明了这种情况:

// Assume a, b, c, and en are not automatic
always @(posedge clk) begin
en = ...;
if (en) begin
a9: assert property p1(a,b,c);
end
if ($sampled(en)) begin
a10: assert property p1(a,b,c);
end
end

        当en变为true时,断言a9在任何时间步排队,而当en的采样值为true时,断言a10在任何时间步排队。因此,假设代码中没有其他内容修改en,a10的检查将比a9的检查晚一个时间步,即使两者都在各自的时间步上使用a、b和c的采样值。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值