Skip to content

Commit 2fc1c2d

Browse files
authored
Merge pull request #422 from diffblue/initial-properties
SystemVerilog: distinguish assertions
2 parents 8dbbbc0 + b98e217 commit 2fc1c2d

21 files changed

+355
-193
lines changed

regression/ebmc/Output-Register-Passing/main.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ module main(in1, in2);
1313

1414
and1 A1 (in1, in2, o1, o2);
1515

16-
assert property1: o1 == (in1 & in2);
16+
always assert property1: o1 == (in1 & in2);
1717
/* A2 is another instance of
1818
ports are referenced to the
1919
declaration by name. */
2020
and1 A2 (.c(o1),.d(o2),.a(o1),.b(in2));
21-
assert property2: o1 == (in1 & in2);
21+
always assert property2: o1 == (in1 & in2);
2222
endmodule
2323

2424
// MODULE DEFINITION

regression/ebmc/smv/initial1.desc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
initial1.smv
3+
--bound 0
4+
^\[main::spec1\] main::var::tmp1 = TRUE: PROVED up to bound 0$
5+
^\[main::spec2\] main::var::tmp2 = TRUE: REFUTED$
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring

regression/ebmc/smv/initial1.smv

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
MODULE main
2+
3+
VAR tmp1: boolean;
4+
VAR tmp2: boolean;
5+
6+
ASSIGN init(tmp1):=1;
7+
8+
-- should pass
9+
SPEC tmp1 = 1;
10+
11+
-- should fail
12+
SPEC tmp2 = 1;

regression/verilog/SVA/initial1.desc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
KNOWNBUG
1+
CORE
22
initial1.sv
33
--module main --bound 1
4-
^EXIT=0$
4+
^\[main\.property\.1\] main\.counter == 0: PROVED up to bound 1$
5+
^\[main\.property\.2\] main\.counter == 100: REFUTED$
6+
^\[main\.property\.3\] ##1 main\.counter == 1: PROVED up to bound 1$
7+
^\[main\.property\.4\] ##1 main\.counter == 100: REFUTED$
8+
^\[main\.property\.5\] s_nexttime main\.counter == 1: PROVED up to bound 1$
9+
^EXIT=10$
510
^SIGNAL=0$
611
--
712
^warning: ignoring
813
--
9-
Syntax is missing for initial label: assert property (...);

regression/verilog/SVA/initial1.sv

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ module main(input clk);
1414
// expected to pass
1515
initial p0: assert property (counter == 0);
1616

17+
// expected to fail
18+
initial p1: assert property (counter == 100);
19+
20+
// expected to pass
21+
initial p2: assert property (##1 counter == 1);
22+
23+
// expected to fail
24+
initial p2: assert property (##1 counter == 100);
25+
1726
// expected to pass if there are timeframes 0 and 1
18-
initial p1: assert property (s_nexttime counter == 1);
27+
initial p3: assert property (s_nexttime counter == 1);
1928

2029
endmodule

regression/verilog/modules/parameters2.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module test(in1, in2);
1010

1111
my_m #( .Ptop(P), .Qtop(Q) ) m_instance(in1, in2, o1, o2);
1212

13-
assert property1: tmp == 4; // should pass
13+
always assert property1: tmp == 4; // should pass
1414

1515
endmodule
1616

@@ -25,6 +25,6 @@ module my_m(a, b, c, d);
2525

2626
wire [3:0] tmp_in_m = Ptop; // tmp1 should be 4 now
2727

28-
assert property2: tmp_in_m == 4; // should pass
28+
always assert property2: tmp_in_m == 4; // should pass
2929

3030
endmodule

regression/verilog/tasks/tasks1.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ module main;
1212
some_task(x, y);
1313
end
1414

15-
assert p1: y==x+1;
15+
always assert p1: y==x+1;
1616

1717
endmodule

src/hw-cbmc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ OBJ+= $(CPROVER_DIR)/goto-checker/goto-checker$(LIBEXT) \
3535
$(CPROVER_DIR)/solvers/solvers$(LIBEXT) \
3636
$(CPROVER_DIR)/util/util$(LIBEXT) \
3737
$(CPROVER_DIR)/json/json$(LIBEXT) \
38+
../temporal-logic/temporal-logic$(LIBEXT) \
3839
../trans-netlist/trans_trace$(OBJEXT) \
3940
../trans-word-level/trans-word-level$(LIBEXT)
4041

src/hw_cbmc_irep_ids.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ IREP_ID_ONE(force)
6666
IREP_ID_ONE(deassign)
6767
IREP_ID_ONE(continuous_assign)
6868
IREP_ID_ONE(wait)
69+
IREP_ID_ONE(verilog_assert_property)
70+
IREP_ID_ONE(verilog_assume_property)
71+
IREP_ID_ONE(verilog_cover_property)
72+
IREP_ID_ONE(verilog_smv_assert)
73+
IREP_ID_ONE(verilog_smv_assume)
6974
IREP_ID_ONE(verilog_always)
7075
IREP_ID_ONE(verilog_always_comb)
7176
IREP_ID_ONE(verilog_always_ff)
@@ -76,7 +81,6 @@ IREP_ID_ONE(initial)
7681
IREP_ID_ONE(verilog_label_statement)
7782
IREP_ID_ONE(disable)
7883
IREP_ID_ONE(fork)
79-
IREP_ID_ONE(cover)
8084
IREP_ID_ONE(instance)
8185
IREP_ID_ONE(named_parameter_assignment)
8286
IREP_ID_ONE(parameter_assignment)

src/temporal-logic/temporal_logic.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,28 @@ Author: Daniel Kroening, [email protected]
1010

1111
#include <util/expr_iterator.h>
1212

13+
bool is_temporal_operator(const exprt &expr)
14+
{
15+
return expr.id() == ID_AG || expr.id() == ID_EG || expr.id() == ID_AF ||
16+
expr.id() == ID_EF || expr.id() == ID_AX || expr.id() == ID_EX ||
17+
expr.id() == ID_A || expr.id() == ID_E || expr.id() == ID_U ||
18+
expr.id() == ID_R || expr.id() == ID_G || expr.id() == ID_F ||
19+
expr.id() == ID_X || expr.id() == ID_sva_always ||
20+
expr.id() == ID_sva_always || expr.id() == ID_sva_nexttime ||
21+
expr.id() == ID_sva_s_nexttime || expr.id() == ID_sva_until ||
22+
expr.id() == ID_sva_s_until || expr.id() == ID_sva_until_with ||
23+
expr.id() == ID_sva_s_until_with || expr.id() == ID_sva_eventually ||
24+
expr.id() == ID_sva_s_eventually || expr.id() == ID_sva_cycle_delay;
25+
}
26+
1327
bool has_temporal_operator(const exprt &expr)
1428
{
1529
for(auto subexpr_it = expr.depth_cbegin(), subexpr_end = expr.depth_cend();
1630
subexpr_it != subexpr_end;
1731
subexpr_it++)
1832
{
19-
// clang-format off
20-
if(
21-
subexpr_it->id() == ID_AG || subexpr_it->id() == ID_EG ||
22-
subexpr_it->id() == ID_AF || subexpr_it->id() == ID_EF ||
23-
subexpr_it->id() == ID_AX || subexpr_it->id() == ID_EX ||
24-
subexpr_it->id() == ID_A || subexpr_it->id() == ID_E ||
25-
subexpr_it->id() == ID_U || subexpr_it->id() == ID_R ||
26-
subexpr_it->id() == ID_G || subexpr_it->id() == ID_F ||
27-
subexpr_it->id() == ID_X ||
28-
subexpr_it->id() == ID_sva_always || subexpr_it->id() == ID_sva_always ||
29-
subexpr_it->id() == ID_sva_nexttime || subexpr_it->id() == ID_sva_s_nexttime ||
30-
subexpr_it->id() == ID_sva_until || subexpr_it->id() == ID_sva_s_until ||
31-
subexpr_it->id() == ID_sva_until_with || subexpr_it->id() == ID_sva_s_until_with ||
32-
subexpr_it->id() == ID_sva_eventually ||
33-
subexpr_it->id() == ID_sva_s_eventually)
34-
{
33+
if(is_temporal_operator(*subexpr_it))
3534
return true;
36-
}
37-
// clang-format on
3835
}
3936

4037
return false;

src/temporal-logic/temporal_logic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ Author: Daniel Kroening, [email protected]
1414
/// Returns true iff the given expression contains a temporal operator
1515
bool has_temporal_operator(const exprt &);
1616

17+
/// Returns true iff the given expression has a temporal operator
18+
/// as its root
19+
bool is_temporal_operator(const exprt &);
20+
1721
#endif

src/trans-word-level/instantiate_word_level.cpp

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -148,60 +148,55 @@ exprt wl_instantiatet::instantiate_rec(exprt expr, const mp_integer &t) const
148148
}
149149
else if(expr.id()==ID_sva_cycle_delay) // ##[1:2] something
150150
{
151-
if(expr.operands().size()==3)
151+
auto &sva_cycle_delay_expr = to_sva_cycle_delay_expr(expr);
152+
153+
if(sva_cycle_delay_expr.to().is_nil())
152154
{
153-
auto &ternary_expr = to_ternary_expr(expr);
155+
mp_integer offset;
156+
if(to_integer_non_constant(sva_cycle_delay_expr.from(), offset))
157+
throw "failed to convert sva_cycle_delay offset";
154158

155-
if(ternary_expr.op1().is_nil())
156-
{
157-
mp_integer offset;
158-
if(to_integer_non_constant(ternary_expr.op0(), offset))
159-
throw "failed to convert sva_cycle_delay offset";
159+
const auto u = t + offset;
160160

161-
const auto u = t + offset;
161+
// Do we exceed the bound? Make it 'true'
162+
if(u >= no_timeframes)
163+
return true_exprt();
164+
else
165+
return instantiate_rec(sva_cycle_delay_expr.op(), u);
166+
}
167+
else
168+
{
169+
mp_integer from, to;
170+
if(to_integer_non_constant(sva_cycle_delay_expr.from(), from))
171+
throw "failed to convert sva_cycle_delay offsets";
162172

163-
// Do we exceed the bound? Make it 'true'
164-
if(u >= no_timeframes)
165-
return true_exprt();
166-
else
167-
return instantiate_rec(ternary_expr.op2(), u);
173+
if(sva_cycle_delay_expr.to().id() == ID_infinity)
174+
{
175+
assert(no_timeframes != 0);
176+
to = no_timeframes - 1;
168177
}
169-
else
178+
else if(to_integer_non_constant(sva_cycle_delay_expr.to(), to))
179+
throw "failed to convert sva_cycle_delay offsets";
180+
181+
// This is an 'or', and we let it fail if the bound is too small.
182+
183+
exprt::operandst disjuncts;
184+
185+
for(mp_integer offset = from; offset < to; ++offset)
170186
{
171-
mp_integer from, to;
172-
if(to_integer_non_constant(ternary_expr.op0(), from))
173-
throw "failed to convert sva_cycle_delay offsets";
187+
auto u = t + offset;
174188

175-
if(ternary_expr.op1().id() == ID_infinity)
189+
if(u >= no_timeframes)
176190
{
177-
assert(no_timeframes!=0);
178-
to=no_timeframes-1;
179191
}
180-
else if(to_integer_non_constant(ternary_expr.op1(), to))
181-
throw "failed to convert sva_cycle_delay offsets";
182-
183-
// This is an 'or', and we let it fail if the bound is too small.
184-
185-
exprt::operandst disjuncts;
186-
187-
for(mp_integer offset=from; offset<to; ++offset)
192+
else
188193
{
189-
auto u = t + offset;
190-
191-
if(u >= no_timeframes)
192-
{
193-
}
194-
else
195-
{
196-
disjuncts.push_back(instantiate_rec(ternary_expr.op2(), u));
197-
}
194+
disjuncts.push_back(instantiate_rec(sva_cycle_delay_expr.op(), u));
198195
}
199-
200-
return disjunction(disjuncts);
201196
}
197+
198+
return disjunction(disjuncts);
202199
}
203-
else
204-
return expr;
205200
}
206201
else if(expr.id()==ID_sva_sequence_concatenation)
207202
{

src/trans-word-level/property.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414
#include <util/symbol_table.h>
1515

1616
#include <temporal-logic/temporal_expr.h>
17+
#include <temporal-logic/temporal_logic.h>
1718
#include <verilog/sva_expr.h>
1819

1920
#include "instantiate_word_level.h"
@@ -34,8 +35,19 @@ Function: bmc_supports_property
3435

3536
bool bmc_supports_property(const exprt &expr)
3637
{
37-
if(expr.is_constant())
38-
return true;
38+
if(!is_temporal_operator(expr))
39+
{
40+
if(!has_temporal_operator(expr))
41+
return true; // initial state only
42+
else
43+
return false;
44+
}
45+
else if(expr.id() == ID_sva_cycle_delay)
46+
return !has_temporal_operator(to_sva_cycle_delay_expr(expr).op());
47+
else if(expr.id() == ID_sva_nexttime)
48+
return !has_temporal_operator(to_sva_nexttime_expr(expr).op());
49+
else if(expr.id() == ID_sva_s_nexttime)
50+
return !has_temporal_operator(to_sva_s_nexttime_expr(expr).op());
3951
else if(expr.id() == ID_AG)
4052
return true;
4153
else if(expr.id() == ID_G)
@@ -68,9 +80,20 @@ void property(
6880
{
6981
messaget message(message_handler);
7082

71-
if(property_expr.is_true())
83+
// Initial state only property?
84+
if(
85+
!is_temporal_operator(property_expr) ||
86+
property_expr.id() == ID_sva_cycle_delay ||
87+
property_expr.id() == ID_sva_nexttime ||
88+
property_expr.id() == ID_sva_s_nexttime)
7289
{
7390
prop_handles.resize(no_timeframes, true_exprt());
91+
if(no_timeframes > 0)
92+
{
93+
exprt tmp = instantiate(property_expr, 0, no_timeframes, ns);
94+
prop_handles.push_back(solver.handle(tmp));
95+
}
96+
7497
return;
7598
}
7699

0 commit comments

Comments
 (0)