Skip to content

Commit c92ff47

Browse files
committed
BMC: implement weak/strong sequences
This implements strong semantics for SVA sequences in the word-level BMC engine. Strong semantics are used with an explicit strong(...) operator or for SVA cover. The difference between weak and strong semantics arises in BMC when the sequence reaches the end of the unwinding: using weak semantics, the sequence matches, whereas using strong semantics the sequence does not.
1 parent 2c58750 commit c92ff47

File tree

9 files changed

+156
-43
lines changed

9 files changed

+156
-43
lines changed

regression/verilog/SVA/cover_sequence2.desc

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
KNOWNBUG
1+
CORE
22
cover_sequence2.sv
3-
--bound 2
4-
^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 100\): PROVED$
5-
^\[main\.p1\] cover \(main\.x == 98 ##1 main\.x == 99 ##1 main\.x == 100\): REFUTED up to bound 2$
3+
--bound 5
4+
^\[main\.p0\] cover \(main\.x == 2 ##1 main\.x == 3 ##1 main\.x == 100\): REFUTED up to bound 5$
5+
^\[main\.p1\] cover \(main\.x == 98 ##1 main\.x == 99 ##1 main\.x == 100\): REFUTED up to bound 5$
6+
^\[main\.p2\] cover \(main\.x == 3 ##1 main\.x == 4 ##1 main\.x == 5\): PROVED$
7+
^\[main\.p3\] cover \(main\.x == 4 ##1 main\.x == 5 ##1 main\.x == 6\): REFUTED up to bound 5$
68
^EXIT=10$
79
^SIGNAL=0$
810
--
911
^warning: ignoring
1012
--
11-
Cover property p0 cannot ever hold, but is shown proven when using a small bound.
+9-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
module main(input clk);
22

33
// count up
4-
reg [7:0] x = 0;
4+
int x = 0;
55

6-
always @(posedge clk)
6+
always_ff @(posedge clk)
77
x++;
88

99
// expected to fail
1010
p0: cover property (x==2 ##1 x==3 ##1 x==100);
1111

12-
// expected to fail until bound reaches 100
12+
// expected to fail until x reaches 100
1313
p1: cover property (x==98 ##1 x==99 ##1 x==100);
1414

15+
// expected to pass once x reaches 5
16+
p2: cover property (x==3 ##1 x==4 ##1 x==5);
17+
18+
// expected to pass once x reaches 6
19+
p3: cover property (x==4 ##1 x==5 ##1 x==6);
20+
1521
endmodule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
cover_sequence3.sv
3+
--bound 3
4+
^\[main\.p0\] cover \(1 \[\*10\]\): REFUTED up to bound 3$
5+
^\[main\.p1\] cover \(1 \[\*4:10\]\): PROVED$
6+
^\[main\.p2\] cover \(1 \[\*5:10\]\): REFUTED up to bound 3$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module main(input clk);
2+
3+
// count up
4+
int x = 0;
5+
6+
always_ff @(posedge clk)
7+
x++;
8+
9+
// passes with bound >=9
10+
p0: cover property (1[*10]);
11+
12+
// passes with bound >=3
13+
p1: cover property (1[*4:10]);
14+
15+
// passes with bound >=4
16+
p2: cover property (1[*5:10]);
17+
18+
endmodule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
KNOWNBUG
2+
cover_sequence4.sv
3+
--bound 3
4+
^\[main\.p0\] cover \(1 \[=10\]\): REFUTED up to bound 3$
5+
^\[main\.p1\] cover \(1 \[=4:10\]\): PROVED$
6+
^\[main\.p2\] cover \(1 \[=5:10\]\): REFUTED up to bound 3$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module main(input clk);
2+
3+
// count up
4+
int x = 0;
5+
6+
always_ff @(posedge clk)
7+
x++;
8+
9+
// passes with bound >=9
10+
p0: cover property (1[=10]);
11+
12+
// passes with bound >=3
13+
p1: cover property (1[=4:10]);
14+
15+
// passes with bound >=4
16+
p2: cover property (1[=5:10]);
17+
18+
endmodule

src/trans-word-level/property.cpp

+33-8
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,17 @@ static obligationst property_obligations_rec(
530530
// The sequence must not match.
531531
auto &sequence = to_sva_sequence_property_expr_base(op).sequence();
532532

533+
// clang-format off
534+
auto semantics =
535+
op.id() == ID_sva_strong ? sva_sequence_semanticst::STRONG
536+
: op.id() == ID_sva_weak ? sva_sequence_semanticst::WEAK
537+
: op.id() == ID_sva_implicit_strong ? sva_sequence_semanticst::STRONG
538+
: op.id() == ID_sva_implicit_weak ? sva_sequence_semanticst::WEAK
539+
: sva_sequence_semanticst::WEAK;
540+
// clang-format on
541+
533542
const auto matches =
534-
instantiate_sequence(sequence, current, no_timeframes);
543+
instantiate_sequence(sequence, semantics, current, no_timeframes);
535544

536545
obligationst obligations;
537546

@@ -577,10 +586,13 @@ static obligationst property_obligations_rec(
577586
auto &implication = to_binary_expr(property_expr);
578587

579588
// The LHS is a sequence, the RHS is a property.
580-
// The implication must hold for _all_ matches on the LHS,
589+
// The implication must hold for _all_ (strong) matches on the LHS,
581590
// i.e., each pair of LHS match and RHS obligation yields an obligation.
582-
const auto lhs_match_points =
583-
instantiate_sequence(implication.lhs(), current, no_timeframes);
591+
const auto lhs_match_points = instantiate_sequence(
592+
implication.lhs(),
593+
sva_sequence_semanticst::STRONG,
594+
current,
595+
no_timeframes);
584596

585597
obligationst result;
586598

@@ -620,9 +632,12 @@ static obligationst property_obligations_rec(
620632
// the result is a property expression.
621633
auto &followed_by = to_sva_followed_by_expr(property_expr);
622634

623-
// get match points for LHS sequence
624-
auto matches =
625-
instantiate_sequence(followed_by.antecedent(), current, no_timeframes);
635+
// get (proper) match points for LHS sequence
636+
auto matches = instantiate_sequence(
637+
followed_by.antecedent(),
638+
sva_sequence_semanticst::STRONG,
639+
current,
640+
no_timeframes);
626641

627642
exprt::operandst disjuncts;
628643
mp_integer t = current;
@@ -663,9 +678,19 @@ static obligationst property_obligations_rec(
663678
auto &sequence =
664679
to_sva_sequence_property_expr_base(property_expr).sequence();
665680

681+
// clang-format off
682+
auto semantics =
683+
property_expr.id() == ID_sva_strong ? sva_sequence_semanticst::STRONG
684+
: property_expr.id() == ID_sva_weak ? sva_sequence_semanticst::WEAK
685+
: property_expr.id() == ID_sva_implicit_strong ? sva_sequence_semanticst::STRONG
686+
: property_expr.id() == ID_sva_implicit_weak ? sva_sequence_semanticst::WEAK
687+
: sva_sequence_semanticst::WEAK;
688+
// clang-format on
689+
666690
// sequence expressions -- these may have multiple potential
667691
// match points, and evaluate to true if any of them matches
668-
const auto matches = instantiate_sequence(sequence, current, no_timeframes);
692+
const auto matches =
693+
instantiate_sequence(sequence, semantics, current, no_timeframes);
669694
exprt::operandst disjuncts;
670695
disjuncts.reserve(matches.size());
671696
mp_integer max = current;

src/trans-word-level/sequence.cpp

+47-27
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Author: Daniel Kroening, [email protected]
99
#include "sequence.h"
1010

1111
#include <util/arith_tools.h>
12-
#include <util/ebmc_util.h>
1312

1413
#include <temporal-logic/temporal_logic.h>
1514
#include <verilog/sva_expr.h>
@@ -20,6 +19,7 @@ Author: Daniel Kroening, [email protected]
2019

2120
sequence_matchest instantiate_sequence(
2221
exprt expr,
22+
sva_sequence_semanticst semantics,
2323
const mp_integer &t,
2424
const mp_integer &no_timeframes)
2525
{
@@ -32,17 +32,21 @@ sequence_matchest instantiate_sequence(
3232
{
3333
const auto u = t + from;
3434

35-
// Do we exceed the bound? Make it 'true'
35+
// Do we exceed the bound? Make it 'false'/'true', depending
36+
// on semantics.
3637
if(u >= no_timeframes)
3738
{
3839
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
39-
return {{no_timeframes - 1, true_exprt()}};
40+
if(semantics == sva_sequence_semanticst::WEAK)
41+
return {{no_timeframes - 1, true_exprt{}}};
42+
else // STRONG
43+
return {}; // no match
4044
}
4145
else
4246
return instantiate_sequence(
43-
sva_cycle_delay_expr.op(), u, no_timeframes);
47+
sva_cycle_delay_expr.op(), semantics, u, no_timeframes);
4448
}
45-
else
49+
else // ##[from:to] something
4650
{
4751
mp_integer to;
4852

@@ -51,25 +55,34 @@ sequence_matchest instantiate_sequence(
5155
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
5256
to = no_timeframes - 1;
5357
}
54-
else if(to_integer_non_constant(sva_cycle_delay_expr.to(), to))
58+
else if(!sva_cycle_delay_expr.to().is_constant())
5559
throw "failed to convert sva_cycle_delay offsets";
60+
else
61+
to = numeric_cast_v<mp_integer>(
62+
to_constant_expr(sva_cycle_delay_expr.to()));
5663

5764
auto lower = t + from;
5865
auto upper = t + to;
5966

60-
// Do we exceed the bound? Make it 'true'
67+
// Do we exceed the bound? Make it 'true' if we are doing
68+
// weak semantics.
6169
if(upper >= no_timeframes)
6270
{
63-
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
64-
return {{no_timeframes - 1, true_exprt()}};
71+
if(semantics == sva_sequence_semanticst::WEAK)
72+
{
73+
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
74+
return {{no_timeframes - 1, true_exprt()}};
75+
}
76+
else
77+
upper = no_timeframes - 1;
6578
}
6679

6780
sequence_matchest matches;
6881

6982
for(mp_integer u = lower; u <= upper; ++u)
7083
{
71-
auto sub_result =
72-
instantiate_sequence(sva_cycle_delay_expr.op(), u, no_timeframes);
84+
auto sub_result = instantiate_sequence(
85+
sva_cycle_delay_expr.op(), semantics, u, no_timeframes);
7386
for(auto &match : sub_result)
7487
matches.push_back(match);
7588
}
@@ -84,21 +97,25 @@ sequence_matchest instantiate_sequence(
8497

8598
// This is the product of the match points on the LHS and RHS
8699
const auto lhs_matches =
87-
instantiate_sequence(implication.lhs(), t, no_timeframes);
100+
instantiate_sequence(implication.lhs(), semantics, t, no_timeframes);
88101

89102
for(auto &lhs_match : lhs_matches)
90103
{
91104
auto t_rhs = lhs_match.end_time;
92105

93-
// Do we exceed the bound? Make it 'true'
106+
// Do we exceed the bound? Make it 'false'/'true', depending
107+
// on semantics.
94108
if(t_rhs >= no_timeframes)
95109
{
96110
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
97-
return {{no_timeframes - 1, true_exprt()}};
111+
if(semantics == sva_sequence_semanticst::WEAK)
112+
return {{no_timeframes - 1, true_exprt{}}};
113+
else // STRONG
114+
return {}; // no match
98115
}
99116

100-
const auto rhs_matches =
101-
instantiate_sequence(implication.rhs(), t_rhs, no_timeframes);
117+
const auto rhs_matches = instantiate_sequence(
118+
implication.rhs(), semantics, t_rhs, no_timeframes);
102119

103120
for(auto &rhs_match : rhs_matches)
104121
{
@@ -119,9 +136,9 @@ sequence_matchest instantiate_sequence(
119136
auto &intersect = to_sva_sequence_intersect_expr(expr);
120137

121138
const auto lhs_matches =
122-
instantiate_sequence(intersect.lhs(), t, no_timeframes);
139+
instantiate_sequence(intersect.lhs(), semantics, t, no_timeframes);
123140
const auto rhs_matches =
124-
instantiate_sequence(intersect.rhs(), t, no_timeframes);
141+
instantiate_sequence(intersect.rhs(), semantics, t, no_timeframes);
125142

126143
sequence_matchest result;
127144

@@ -146,7 +163,7 @@ sequence_matchest instantiate_sequence(
146163
auto &first_match = to_sva_sequence_first_match_expr(expr);
147164

148165
const auto lhs_matches =
149-
instantiate_sequence(first_match.lhs(), t, no_timeframes);
166+
instantiate_sequence(first_match.lhs(), semantics, t, no_timeframes);
150167

151168
// the match of seq with the earliest ending clock tick is a
152169
// match of first_match (seq)
@@ -183,7 +200,7 @@ sequence_matchest instantiate_sequence(
183200
auto &throughout = to_sva_sequence_throughout_expr(expr);
184201

185202
const auto rhs_matches =
186-
instantiate_sequence(throughout.rhs(), t, no_timeframes);
203+
instantiate_sequence(throughout.rhs(), semantics, t, no_timeframes);
187204

188205
sequence_matchest result;
189206

@@ -210,16 +227,16 @@ sequence_matchest instantiate_sequence(
210227

211228
auto &within_expr = to_sva_sequence_within_expr(expr);
212229
const auto matches_rhs =
213-
instantiate_sequence(within_expr.rhs(), t, no_timeframes);
230+
instantiate_sequence(within_expr.rhs(), semantics, t, no_timeframes);
214231

215232
sequence_matchest result;
216233

217234
for(auto &match_rhs : matches_rhs)
218235
{
219236
for(auto start_lhs = t; start_lhs <= match_rhs.end_time; ++start_lhs)
220237
{
221-
auto matches_lhs =
222-
instantiate_sequence(within_expr.lhs(), start_lhs, no_timeframes);
238+
auto matches_lhs = instantiate_sequence(
239+
within_expr.lhs(), semantics, start_lhs, no_timeframes);
223240

224241
for(auto &match_lhs : matches_lhs)
225242
{
@@ -245,8 +262,10 @@ sequence_matchest instantiate_sequence(
245262
// 3. The end time of the composite sequence is
246263
// the end time of the operand sequence that completes last.
247264
auto &and_expr = to_sva_and_expr(expr);
248-
auto matches_lhs = instantiate_sequence(and_expr.lhs(), t, no_timeframes);
249-
auto matches_rhs = instantiate_sequence(and_expr.rhs(), t, no_timeframes);
265+
auto matches_lhs =
266+
instantiate_sequence(and_expr.lhs(), semantics, t, no_timeframes);
267+
auto matches_rhs =
268+
instantiate_sequence(and_expr.rhs(), semantics, t, no_timeframes);
250269

251270
sequence_matchest result;
252271

@@ -268,7 +287,7 @@ sequence_matchest instantiate_sequence(
268287
sequence_matchest result;
269288

270289
for(auto &op : expr.operands())
271-
for(auto &match : instantiate_sequence(op, t, no_timeframes))
290+
for(auto &match : instantiate_sequence(op, semantics, t, no_timeframes))
272291
result.push_back(match);
273292

274293
return result;
@@ -277,7 +296,8 @@ sequence_matchest instantiate_sequence(
277296
{
278297
// x[*n] is syntactic sugar for x ##1 ... ##1 x, with n repetitions
279298
auto &repetition = to_sva_sequence_consecutive_repetition_expr(expr);
280-
return instantiate_sequence(repetition.lower(), t, no_timeframes);
299+
return instantiate_sequence(
300+
repetition.lower(), semantics, t, no_timeframes);
281301
}
282302
else if(
283303
expr.id() == ID_sva_sequence_repetition_plus ||

src/trans-word-level/sequence.h

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Author: Daniel Kroening, [email protected]
1212
#include <util/expr.h>
1313
#include <util/mp_arith.h>
1414

15+
#include <verilog/sva_expr.h>
16+
1517
/// A match for an SVA sequence.
1618
class sequence_matcht
1719
{
@@ -32,6 +34,7 @@ using sequence_matchest = std::vector<sequence_matcht>;
3234
/// for the given sequence expression starting at time t
3335
[[nodiscard]] sequence_matchest instantiate_sequence(
3436
exprt expr,
37+
sva_sequence_semanticst,
3538
const mp_integer &t,
3639
const mp_integer &no_timeframes);
3740

0 commit comments

Comments
 (0)