Skip to content

Commit 4c3a4db

Browse files
committed
Implement SVA cover in BMC
This adds support for SVA cover properties to the BMC engine.
1 parent 5612fe0 commit 4c3a4db

File tree

9 files changed

+123
-53
lines changed

9 files changed

+123
-53
lines changed

regression/verilog/SVA/cover1.desc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
KNOWNBUG
22
cover1.sv
3-
--bound 10
4-
^\[main\.property\.p0\] cover main\.counter == 1: REFUTED$
5-
^\[main\.property\.p1\] cover main\.counter == 100: REFUTED$
3+
--bound 10 --numbered-trace
4+
^\[main\.property\.p0\] cover main\.counter == 1: PROVED$
5+
^main\.counter@0 = 0$
6+
^main\.counter@1 = 1$
7+
^\[main\.property\.p1\] cover main\.counter == 100: REFUTED up to bound 20$
68
^EXIT=10$
79
^SIGNAL=0$
810
--

src/ebmc/bdd_engine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ void bdd_enginet::compute_counterexample(
402402
throw "unexpected result from SAT solver";
403403
}
404404

405-
property.counterexample =
405+
property.witness_trace =
406406
compute_trans_trace(property.timeframe_literals, bmc_map, solver, ns);
407407
}
408408

src/ebmc/bmc.cpp

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -98,38 +98,77 @@ void bmc(
9898

9999
message.status() << "Checking " << property.name << messaget::eom;
100100

101-
auto assumption = not_exprt(conjunction(property.timeframe_handles));
102-
103-
decision_proceduret::resultt dec_result = solver(assumption);
104-
105-
switch(dec_result)
101+
if(property.is_exists_path())
102+
{
103+
auto assumption = disjunction(property.timeframe_handles);
104+
105+
decision_proceduret::resultt dec_result = solver(assumption);
106+
107+
switch(dec_result)
108+
{
109+
case decision_proceduret::resultt::D_SATISFIABLE:
110+
property.proved();
111+
message.result() << "SAT: path found" << messaget::eom;
112+
113+
property.witness_trace = compute_trans_trace(
114+
property.timeframe_handles,
115+
solver,
116+
bound + 1,
117+
ns,
118+
transition_system.main_symbol->name);
119+
break;
120+
121+
case decision_proceduret::resultt::D_UNSATISFIABLE:
122+
message.result() << "UNSAT: No path found within bound"
123+
<< messaget::eom;
124+
property.refuted_with_bound(bound);
125+
break;
126+
127+
case decision_proceduret::resultt::D_ERROR:
128+
message.error() << "Error from decision procedure" << messaget::eom;
129+
property.failure();
130+
break;
131+
132+
default:
133+
property.failure();
134+
throw ebmc_errort() << "Unexpected result from decision procedure";
135+
}
136+
}
137+
else // universal path property
106138
{
107-
case decision_proceduret::resultt::D_SATISFIABLE:
108-
property.refuted();
109-
message.result() << "SAT: counterexample found" << messaget::eom;
110-
111-
property.counterexample = compute_trans_trace(
112-
property.timeframe_handles,
113-
solver,
114-
bound + 1,
115-
ns,
116-
transition_system.main_symbol->name);
117-
break;
118-
119-
case decision_proceduret::resultt::D_UNSATISFIABLE:
120-
message.result() << "UNSAT: No counterexample found within bound"
121-
<< messaget::eom;
122-
property.proved_with_bound(bound);
123-
break;
124-
125-
case decision_proceduret::resultt::D_ERROR:
126-
message.error() << "Error from decision procedure" << messaget::eom;
127-
property.failure();
128-
break;
129-
130-
default:
131-
property.failure();
132-
throw ebmc_errort() << "Unexpected result from decision procedure";
139+
auto assumption = not_exprt{conjunction(property.timeframe_handles)};
140+
141+
decision_proceduret::resultt dec_result = solver(assumption);
142+
143+
switch(dec_result)
144+
{
145+
case decision_proceduret::resultt::D_SATISFIABLE:
146+
property.refuted();
147+
message.result() << "SAT: counterexample found" << messaget::eom;
148+
149+
property.witness_trace = compute_trans_trace(
150+
property.timeframe_handles,
151+
solver,
152+
bound + 1,
153+
ns,
154+
transition_system.main_symbol->name);
155+
break;
156+
157+
case decision_proceduret::resultt::D_UNSATISFIABLE:
158+
message.result() << "UNSAT: No counterexample found within bound"
159+
<< messaget::eom;
160+
property.proved_with_bound(bound);
161+
break;
162+
163+
case decision_proceduret::resultt::D_ERROR:
164+
message.error() << "Error from decision procedure" << messaget::eom;
165+
property.failure();
166+
break;
167+
168+
default:
169+
property.failure();
170+
throw ebmc_errort() << "Unexpected result from decision procedure";
171+
}
133172
}
134173
}
135174

src/ebmc/ebmc_base.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ int ebmc_baset::finish_bit_level_bmc(const bmc_mapt &bmc_map, propt &solver)
9595

9696
namespacet ns(transition_system.symbol_table);
9797

98-
property.counterexample =
98+
property.witness_trace =
9999
compute_trans_trace(property.timeframe_literals, bmc_map, solver, ns);
100100
}
101101
break;

src/ebmc/ebmc_properties.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ std::string ebmc_propertiest::propertyt::status_as_string() const
2626
return "PROVED up to bound " + std::to_string(bound);
2727
case statust::REFUTED:
2828
return "REFUTED";
29+
case statust::REFUTED_WITH_BOUND:
30+
return "REFUTED up to bound " + std::to_string(bound);
2931
case statust::UNKNOWN:
3032
return "UNKNOWN";
3133
case statust::INCONCLUSIVE:

src/ebmc/ebmc_properties.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Author: Daniel Kroening, [email protected]
1515
#include <solvers/prop/literal.h>
1616
#include <trans-netlist/trans_trace.h>
1717
#include <trans-word-level/property.h>
18+
#include <temporal-logic/temporal_logic.h>
1819

1920
#include "transition_system.h"
2021

@@ -42,18 +43,19 @@ class ebmc_propertiest
4243
PROVED, // property is true, unbounded
4344
PROVED_WITH_BOUND, // property is true, with bound
4445
REFUTED, // property is false, possibly counterexample
46+
REFUTED_WITH_BOUND,// property is false, with bound
4547
DROPPED, // given up
4648
FAILURE, // error during anaysis
4749
INCONCLUSIVE // analysis can't determine truth
4850
} status = statust::UNKNOWN;
4951

5052
std::size_t bound = 0;
51-
std::optional<trans_tracet> counterexample;
53+
std::optional<trans_tracet> witness_trace;
5254
std::optional<std::string> failure_reason;
5355

54-
bool has_counterexample() const
56+
bool has_witness_trace() const
5557
{
56-
return counterexample.has_value();
58+
return witness_trace.has_value();
5759
}
5860

5961
bool is_unknown() const
@@ -122,6 +124,12 @@ class ebmc_propertiest
122124
status = statust::REFUTED;
123125
}
124126

127+
void refuted_with_bound(std::size_t _bound)
128+
{
129+
status = statust::REFUTED_WITH_BOUND;
130+
bound = _bound;
131+
}
132+
125133
void drop()
126134
{
127135
status = statust::DROPPED;
@@ -146,6 +154,11 @@ class ebmc_propertiest
146154
{
147155
return ::requires_lasso_constraints(normalized_expr);
148156
}
157+
158+
bool is_exists_path() const
159+
{
160+
return ::is_exists_path(original_expr);
161+
}
149162
};
150163

151164
typedef std::list<propertyt> propertiest;

src/ebmc/report_results.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ void report_results(
5858
json_property["identifier"] = json_stringt(id2string(property.name));
5959
json_property["status"] = json_stringt(property.status_as_string());
6060

61-
if(property.has_counterexample())
62-
json_property["counterexample"] =
63-
json(property.counterexample.value(), ns);
61+
if(property.has_witness_trace())
62+
json_property["trace"] =
63+
json(property.witness_trace.value(), ns);
6464

6565
json_properties.push_back(std::move(json_property));
6666
}
@@ -81,8 +81,8 @@ void report_results(
8181
xml_result.set_attribute("property", id2string(property.name));
8282
xml_result.set_attribute("status", property.status_as_string());
8383

84-
if(property.has_counterexample())
85-
xml_result.new_element() = xml(property.counterexample.value(), ns);
84+
if(property.has_witness_trace())
85+
xml_result.new_element() = xml(property.witness_trace.value(), ns);
8686

8787
std::cout << xml_result << '\n' << std::flush;
8888
}
@@ -109,6 +109,7 @@ void report_results(
109109
case statust::PROVED: message.status() << messaget::green; break;
110110
case statust::PROVED_WITH_BOUND: message.status() << messaget::green; break;
111111
case statust::REFUTED: message.status() << messaget::bright_red; break;
112+
case statust::REFUTED_WITH_BOUND: message.status() << messaget::bright_red; break;
112113
case statust::DROPPED: message.status() << messaget::red; break;
113114
case statust::FAILURE: message.status() << messaget::red; break;
114115
case statust::UNKNOWN: message.status() << messaget::yellow; break;
@@ -121,24 +122,28 @@ void report_results(
121122

122123
message.status() << messaget::reset << messaget::eom;
123124

124-
if(property.has_counterexample())
125+
if(property.has_witness_trace())
125126
{
127+
auto term = [&property]() {
128+
return property.is_exists_path() ? "Trace" : "Counterexample";
129+
};
130+
126131
if(cmdline.isset("trace"))
127132
{
128-
message.status() << "Counterexample:\n" << messaget::eom;
133+
message.status() << term() << ":\n" << messaget::eom;
129134
show_trans_trace(
130-
property.counterexample.value(), message, ns, std::cout);
135+
property.witness_trace.value(), message, ns, std::cout);
131136
}
132137
else if(cmdline.isset("numbered-trace"))
133138
{
134-
message.status() << "Counterexample:\n" << messaget::eom;
139+
message.status() << term() << ":" << messaget::eom;
135140
show_trans_trace_numbered(
136-
property.counterexample.value(), message, ns, std::cout);
141+
property.witness_trace.value(), message, ns, std::cout);
137142
}
138143
else if(cmdline.isset("waveform"))
139144
{
140-
message.status() << "Counterexample:" << messaget::eom;
141-
show_waveform(property.counterexample.value(), ns);
145+
message.status() << term() << ":" << messaget::eom;
146+
show_waveform(property.witness_trace.value(), ns);
142147
}
143148
}
144149
}
@@ -148,13 +153,13 @@ void report_results(
148153
{
149154
for(const auto &property : properties.properties)
150155
{
151-
if(property.has_counterexample())
156+
if(property.has_witness_trace())
152157
{
153158
std::string vcdfile = cmdline.get_value("vcd");
154159
std::ofstream vcd(widen_if_needed(vcdfile));
155160

156161
messaget message(message_handler);
157-
show_trans_trace_vcd(property.counterexample.value(), message, ns, vcd);
162+
show_trans_trace_vcd(property.witness_trace.value(), message, ns, vcd);
158163

159164
break;
160165
}

src/temporal-logic/temporal_logic.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ bool has_temporal_operator(const exprt &expr)
3636

3737
return false;
3838
}
39+
40+
bool is_exists_path(const exprt &expr)
41+
{
42+
return expr.id() == ID_sva_cover;
43+
}

src/temporal-logic/temporal_logic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ bool has_temporal_operator(const exprt &);
1818
/// as its root
1919
bool is_temporal_operator(const exprt &);
2020

21+
/// Returns true iff the given expression is an existential path
22+
/// property.
23+
bool is_exists_path(const exprt &);
24+
2125
#endif

0 commit comments

Comments
 (0)