Skip to content

Commit d0f0b95

Browse files
authored
Merge pull request #403 from diffblue/SVA-eventually
Verilog: support for weak eventually
2 parents dda4d36 + e2f7917 commit d0f0b95

File tree

9 files changed

+200
-53
lines changed

9 files changed

+200
-53
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
eventually1.sv
3+
--bound 20
4+
^\[main\.property\.p0\] always \(main\.counter == 1 |-> eventually \[1:2\] main\.counter == 3\): PROVED up to bound 20$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

regression/verilog/SVA/eventually1.sv

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module main(input clk, input reset);
2+
3+
// count up from 0 to 10
4+
reg [7:0] counter;
5+
initial counter = 0;
6+
7+
always @(posedge clk)
8+
if(counter != 10)
9+
counter = counter + 1;
10+
11+
// expected to pass
12+
p0: assert property (counter == 1 implies eventually [1:2] counter == 3);
13+
14+
endmodule
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
eventually2.sv
3+
--bound 20
4+
^\[main\.property\.p0\] always \(eventually \[0:2\] main\.counter == 3\): REFUTED$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

regression/verilog/SVA/eventually2.sv

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module main(input clk, input reset);
2+
3+
reg [7:0] counter;
4+
initial counter = 0;
5+
always @(posedge clk) counter = 0;
6+
7+
// expected to fail
8+
p0: assert property (eventually [0:2] counter == 3);
9+
10+
endmodule

src/trans-word-level/instantiate_word_level.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,34 @@ exprt wl_instantiatet::instantiate_rec(exprt expr, const mp_integer &t) const
240240
else
241241
return true_exprt(); // works on NNF only
242242
}
243+
else if(expr.id() == ID_sva_eventually)
244+
{
245+
const auto &eventually_expr = to_sva_eventually_expr(expr);
246+
const auto &range = eventually_expr.range();
247+
const auto &op = eventually_expr.op();
248+
249+
mp_integer lower;
250+
if(to_integer_non_constant(range.op0(), lower))
251+
throw "failed to convert sva_eventually index";
252+
253+
mp_integer upper;
254+
if(to_integer_non_constant(range.op1(), upper))
255+
throw "failed to convert sva_eventually index";
256+
257+
// This is weak, and passes if any of the timeframes
258+
// does not exist.
259+
if(t + lower >= no_timeframes || t + upper >= no_timeframes)
260+
return true_exprt();
261+
262+
exprt::operandst disjuncts = {};
263+
264+
for(mp_integer u = t + lower; u <= t + upper; ++u)
265+
disjuncts.push_back(instantiate_rec(op, u));
266+
267+
return disjunction(disjuncts);
268+
}
243269
else if(
244-
expr.id() == ID_sva_eventually || expr.id() == ID_sva_s_eventually ||
245-
expr.id() == ID_F || expr.id() == ID_AF)
270+
expr.id() == ID_sva_s_eventually || expr.id() == ID_F || expr.id() == ID_AF)
246271
{
247272
const auto &p = to_unary_expr(expr).op();
248273

src/verilog/expr2verilog.cpp

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/std_expr.h>
1818
#include <util/symbol.h>
1919

20+
#include "sva_expr.h"
2021
#include "verilog_expr.h"
2122
#include "verilog_types.h"
2223

@@ -385,35 +386,53 @@ Function: expr2verilogt::convert_sva
385386

386387
std::string expr2verilogt::convert_sva(
387388
const std::string &name,
388-
const exprt &src)
389+
const std::optional<exprt> &range,
390+
const exprt &op)
389391
{
390-
if(src.operands().size()==1)
392+
std::string range_str;
393+
394+
if(range.has_value())
391395
{
392-
auto &op = to_unary_expr(src).op();
393-
unsigned p;
394-
auto s = convert(op, p);
395-
if(p == 0 && op.operands().size() >= 2)
396-
s = "(" + s + ")";
397-
return name + " " + s;
396+
auto &range_binary = to_binary_expr(range.value());
397+
range_str = "[" + convert(range_binary.lhs()) + ':' +
398+
convert(range_binary.rhs()) + "] ";
398399
}
399-
else if(src.operands().size()==2)
400-
{
401-
auto &binary_expr = to_binary_expr(src);
402400

403-
unsigned p0;
404-
auto s0 = convert(binary_expr.op0(), p0);
405-
if(p0 == 0)
406-
s0 = "(" + s0 + ")";
401+
unsigned p;
402+
auto s = convert(op, p);
403+
if(p == 0 && op.operands().size() >= 2)
404+
s = "(" + s + ")";
405+
return name + " " + range_str + s;
406+
}
407407

408-
unsigned p1;
409-
auto s1 = convert(binary_expr.op1(), p1);
410-
if(p1 == 0)
411-
s1 = "(" + s1 + ")";
408+
/*******************************************************************\
412409
413-
return s0 + " " + name + " " + s1;
414-
}
415-
else
416-
return "?";
410+
Function: expr2verilogt::convert_sva
411+
412+
Inputs:
413+
414+
Outputs:
415+
416+
Purpose:
417+
418+
\*******************************************************************/
419+
420+
std::string expr2verilogt::convert_sva(
421+
const exprt &lhs,
422+
const std::string &name,
423+
const exprt &rhs)
424+
{
425+
unsigned p0;
426+
auto s0 = convert(lhs, p0);
427+
if(p0 == 0)
428+
s0 = "(" + s0 + ")";
429+
430+
unsigned p1;
431+
auto s1 = convert(rhs, p1);
432+
if(p1 == 0)
433+
s1 = "(" + s1 + ")";
434+
435+
return s0 + " " + name + " " + s1;
417436
}
418437

419438
/*******************************************************************\
@@ -1046,10 +1065,16 @@ std::string expr2verilogt::convert(
10461065
return convert_function("$onehot0", src);
10471066

10481067
else if(src.id()==ID_sva_overlapped_implication)
1049-
return precedence = 0, convert_sva("|->", src);
1068+
{
1069+
auto &binary = to_binary_expr(src);
1070+
return precedence = 0, convert_sva(binary.lhs(), "|->", binary.rhs());
1071+
}
10501072

10511073
else if(src.id()==ID_sva_non_overlapped_implication)
1052-
return precedence = 0, convert_sva("|=>", src);
1074+
{
1075+
auto &binary = to_binary_expr(src);
1076+
return precedence = 0, convert_sva(binary.lhs(), "|=>", binary.rhs());
1077+
}
10531078

10541079
else if(src.id()==ID_sva_cycle_delay)
10551080
return convert_sva_cycle_delay(to_ternary_expr(src), precedence = 0);
@@ -1061,31 +1086,49 @@ std::string expr2verilogt::convert(
10611086
// not sure about precedence
10621087

10631088
else if(src.id()==ID_sva_always)
1064-
return precedence = 0, convert_sva("always", src);
1089+
return precedence = 0, convert_sva("always", to_sva_always_expr(src).op());
10651090

10661091
else if(src.id()==ID_sva_nexttime)
1067-
return precedence = 0, convert_sva("nexttime", src);
1092+
return precedence = 0,
1093+
convert_sva("nexttime", to_sva_nexttime_expr(src).op());
10681094

10691095
else if(src.id()==ID_sva_s_nexttime)
1070-
return precedence = 0, convert_sva("s_nexttime", src);
1096+
return precedence = 0,
1097+
convert_sva("s_nexttime", to_sva_s_nexttime_expr(src).op());
10711098

10721099
else if(src.id()==ID_sva_eventually)
1073-
return precedence = 0, convert_sva("eventually", src);
1100+
return precedence = 0, convert_sva(
1101+
"eventually",
1102+
to_sva_eventually_expr(src).range(),
1103+
to_sva_eventually_expr(src).op());
10741104

10751105
else if(src.id()==ID_sva_s_eventually)
1076-
return precedence = 0, convert_sva("s_eventually", src);
1106+
return precedence = 0,
1107+
convert_sva("s_eventually", to_sva_s_eventually_expr(src).op());
10771108

10781109
else if(src.id()==ID_sva_until)
1079-
return precedence = 0, convert_sva("until", src);
1110+
return precedence = 0, convert_sva(
1111+
to_sva_until_expr(src).lhs(),
1112+
"until",
1113+
to_sva_until_expr(src).rhs());
10801114

10811115
else if(src.id()==ID_sva_s_until)
1082-
return precedence = 0, convert_sva("s_until", src);
1116+
return precedence = 0, convert_sva(
1117+
to_sva_s_until_expr(src).lhs(),
1118+
"s_until",
1119+
to_sva_s_until_expr(src).rhs());
10831120

10841121
else if(src.id()==ID_sva_until_with)
1085-
return precedence = 0, convert_sva("until_with", src);
1122+
return precedence = 0, convert_sva(
1123+
to_sva_until_with_expr(src).lhs(),
1124+
"until_with",
1125+
to_sva_until_with_expr(src).rhs());
10861126

10871127
else if(src.id()==ID_sva_s_until_with)
1088-
return precedence = 0, convert_sva("s_until_with", src);
1128+
return precedence = 0, convert_sva(
1129+
to_sva_s_until_with_expr(src).lhs(),
1130+
"s_until_with",
1131+
to_sva_s_until_with_expr(src).rhs());
10891132

10901133
else if(src.id()==ID_function_call)
10911134
return convert_function_call(to_function_call_expr(src));

src/verilog/expr2verilog_class.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,18 @@ class expr2verilogt
8282
const std::string &name,
8383
const exprt &src);
8484

85-
virtual std::string convert_sva(
85+
std::string convert_sva(
8686
const std::string &name,
87-
const exprt &src);
87+
const std::optional<exprt> &range,
88+
const exprt &op);
89+
90+
std::string convert_sva(const std::string &name, const exprt &op)
91+
{
92+
return convert_sva(name, {}, op);
93+
}
94+
95+
std::string
96+
convert_sva(const exprt &lhs, const std::string &name, const exprt &rhs);
8897

8998
virtual std::string
9099
convert_replication(const replication_exprt &, unsigned precedence);

src/verilog/sva_expr.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ class sva_eventually_exprt : public binary_predicate_exprt
6969
{
7070
}
7171

72-
// These come with a range
73-
const exprt &range() const
72+
// These come with a range, which is binary
73+
const binary_exprt &range() const
7474
{
75-
return op0();
75+
return static_cast<const binary_exprt &>(op0());
7676
}
7777

78-
exprt &range()
78+
binary_exprt &range()
7979
{
80-
return op0();
80+
return static_cast<binary_exprt &>(op0());
8181
}
8282

8383
const exprt &op() const
@@ -95,6 +95,14 @@ class sva_eventually_exprt : public binary_predicate_exprt
9595
const exprt &rhs() const = delete;
9696
exprt &rhs() = delete;
9797

98+
static void check(
99+
const exprt &expr,
100+
const validation_modet vm = validation_modet::INVARIANT)
101+
{
102+
binary_exprt::check(expr, vm);
103+
binary_exprt::check(to_binary_expr(expr).op0(), vm);
104+
}
105+
98106
protected:
99107
using binary_predicate_exprt::op0;
100108
using binary_predicate_exprt::op1;

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
#include <cctype>
10-
#include <cstdlib>
11-
#include <algorithm>
9+
#include "verilog_typecheck_expr.h"
1210

1311
#include <util/bitvector_expr.h>
1412
#include <util/ebmc_util.h>
@@ -20,10 +18,14 @@ Author: Daniel Kroening, [email protected]
2018
#include <util/std_expr.h>
2119

2220
#include "expr2verilog.h"
21+
#include "sva_expr.h"
2322
#include "verilog_expr.h"
24-
#include "verilog_typecheck_expr.h"
25-
#include "vtype.h"
2623
#include "verilog_types.h"
24+
#include "vtype.h"
25+
26+
#include <algorithm>
27+
#include <cctype>
28+
#include <cstdlib>
2729

2830
/*******************************************************************\
2931
@@ -1853,11 +1855,9 @@ exprt verilog_typecheck_exprt::convert_unary_expr(unary_exprt expr)
18531855
no_bool_ops(expr);
18541856
expr.type() = expr.op().type();
18551857
}
1856-
else if(expr.id()==ID_sva_always ||
1857-
expr.id()==ID_sva_nexttime ||
1858-
expr.id()==ID_sva_s_nexttime ||
1859-
expr.id()==ID_sva_eventually ||
1860-
expr.id()==ID_sva_s_eventually)
1858+
else if(
1859+
expr.id() == ID_sva_always || expr.id() == ID_sva_nexttime ||
1860+
expr.id() == ID_sva_s_nexttime || expr.id() == ID_sva_s_eventually)
18611861
{
18621862
assert(expr.operands().size()==1);
18631863
convert_expr(expr.op());
@@ -2167,6 +2167,28 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
21672167

21682168
return std::move(expr);
21692169
}
2170+
else if(expr.id() == ID_sva_eventually)
2171+
{
2172+
auto &range = to_binary_expr(expr.op0());
2173+
auto lower = convert_integer_constant_expression(range.op0());
2174+
auto upper = convert_integer_constant_expression(range.op1());
2175+
if(lower > upper)
2176+
{
2177+
throw errort().with_location(expr.source_location())
2178+
<< "range must be lower <= upper";
2179+
}
2180+
2181+
range.op0() = from_integer(lower, natural_typet())
2182+
.with_source_location<exprt>(range.op0());
2183+
range.op1() = from_integer(upper, natural_typet())
2184+
.with_source_location<exprt>(range.op1());
2185+
2186+
convert_expr(expr.op1());
2187+
make_boolean(expr.op1());
2188+
expr.type() = bool_typet();
2189+
2190+
return std::move(expr);
2191+
}
21702192
else if(expr.id()==ID_hierarchical_identifier)
21712193
{
21722194
return convert_hierarchical_identifier(

0 commit comments

Comments
 (0)