Skip to content

Commit c89476e

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

File tree

9 files changed

+87
-39
lines changed

9 files changed

+87
-39
lines changed

regression/verilog/SVA/cover1.desc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
KNOWNBUG
1+
CORE
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+
^Trace:$
6+
^main\.counter@0 = 0$
7+
^main\.counter@1 = 1$
8+
^\[main\.property\.p1\] cover main\.counter == 100: REFUTED up to bound 10$
69
^EXIT=10$
710
^SIGNAL=0$
811
--

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: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,25 @@ void bmc(
9898

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

101-
auto assumption = not_exprt(conjunction(property.timeframe_handles));
101+
auto assumption = not_exprt{conjunction(property.timeframe_handles)};
102102

103103
decision_proceduret::resultt dec_result = solver(assumption);
104104

105105
switch(dec_result)
106106
{
107107
case decision_proceduret::resultt::D_SATISFIABLE:
108-
property.refuted();
109-
message.result() << "SAT: counterexample found" << messaget::eom;
110-
111-
property.counterexample = compute_trans_trace(
108+
if(property.is_exists_path())
109+
{
110+
property.proved();
111+
message.result() << "SAT: path found" << messaget::eom;
112+
}
113+
else // universal path property
114+
{
115+
property.refuted();
116+
message.result() << "SAT: counterexample found" << messaget::eom;
117+
}
118+
119+
property.witness_trace = compute_trans_trace(
112120
property.timeframe_handles,
113121
solver,
114122
bound + 1,
@@ -117,9 +125,18 @@ void bmc(
117125
break;
118126

119127
case decision_proceduret::resultt::D_UNSATISFIABLE:
120-
message.result() << "UNSAT: No counterexample found within bound"
121-
<< messaget::eom;
122-
property.proved_with_bound(bound);
128+
if(property.is_exists_path())
129+
{
130+
message.result() << "UNSAT: No path found within bound"
131+
<< messaget::eom;
132+
property.refuted_with_bound(bound);
133+
}
134+
else // universal path property
135+
{
136+
message.result() << "UNSAT: No counterexample found within bound"
137+
<< messaget::eom;
138+
property.proved_with_bound(bound);
139+
}
123140
break;
124141

125142
case decision_proceduret::resultt::D_ERROR:

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: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/message.h>
1414

1515
#include <solvers/prop/literal.h>
16+
#include <temporal-logic/temporal_logic.h>
1617
#include <trans-netlist/trans_trace.h>
1718
#include <trans-word-level/property.h>
1819

@@ -37,23 +38,24 @@ class ebmc_propertiest
3738

3839
enum class statust
3940
{
40-
UNKNOWN, // no work done yet
41-
DISABLED, // turned off by user
42-
PROVED, // property is true, unbounded
43-
PROVED_WITH_BOUND, // property is true, with bound
44-
REFUTED, // property is false, possibly counterexample
45-
DROPPED, // given up
46-
FAILURE, // error during anaysis
47-
INCONCLUSIVE // analysis can't determine truth
41+
UNKNOWN, // no work done yet
42+
DISABLED, // turned off by user
43+
PROVED, // property is true, unbounded
44+
PROVED_WITH_BOUND, // property is true, with bound
45+
REFUTED, // property is false, possibly counterexample
46+
REFUTED_WITH_BOUND, // property is false, with bound
47+
DROPPED, // given up
48+
FAILURE, // error during anaysis
49+
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: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,8 @@ 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"] = json(property.witness_trace.value(), ns);
6463

6564
json_properties.push_back(std::move(json_property));
6665
}
@@ -81,8 +80,8 @@ void report_results(
8180
xml_result.set_attribute("property", id2string(property.name));
8281
xml_result.set_attribute("status", property.status_as_string());
8382

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

8786
std::cout << xml_result << '\n' << std::flush;
8887
}
@@ -109,6 +108,7 @@ void report_results(
109108
case statust::PROVED: message.status() << messaget::green; break;
110109
case statust::PROVED_WITH_BOUND: message.status() << messaget::green; break;
111110
case statust::REFUTED: message.status() << messaget::bright_red; break;
111+
case statust::REFUTED_WITH_BOUND: message.status() << messaget::bright_red; break;
112112
case statust::DROPPED: message.status() << messaget::red; break;
113113
case statust::FAILURE: message.status() << messaget::red; break;
114114
case statust::UNKNOWN: message.status() << messaget::yellow; break;
@@ -121,24 +121,28 @@ void report_results(
121121

122122
message.status() << messaget::reset << messaget::eom;
123123

124-
if(property.has_counterexample())
124+
if(property.has_witness_trace())
125125
{
126+
auto term = [&property]() {
127+
return property.is_exists_path() ? "Trace" : "Counterexample";
128+
};
129+
126130
if(cmdline.isset("trace"))
127131
{
128-
message.status() << "Counterexample:\n" << messaget::eom;
132+
message.status() << term() << ":\n" << messaget::eom;
129133
show_trans_trace(
130-
property.counterexample.value(), message, ns, std::cout);
134+
property.witness_trace.value(), message, ns, std::cout);
131135
}
132136
else if(cmdline.isset("numbered-trace"))
133137
{
134-
message.status() << "Counterexample:\n" << messaget::eom;
138+
message.status() << term() << ":" << messaget::eom;
135139
show_trans_trace_numbered(
136-
property.counterexample.value(), message, ns, std::cout);
140+
property.witness_trace.value(), message, ns, std::cout);
137141
}
138142
else if(cmdline.isset("waveform"))
139143
{
140-
message.status() << "Counterexample:" << messaget::eom;
141-
show_waveform(property.counterexample.value(), ns);
144+
message.status() << term() << ":" << messaget::eom;
145+
show_waveform(property.witness_trace.value(), ns);
142146
}
143147
}
144148
}
@@ -148,13 +152,13 @@ void report_results(
148152
{
149153
for(const auto &property : properties.properties)
150154
{
151-
if(property.has_counterexample())
155+
if(property.has_witness_trace())
152156
{
153157
std::string vcdfile = cmdline.get_value("vcd");
154158
std::ofstream vcd(widen_if_needed(vcdfile));
155159

156160
messaget message(message_handler);
157-
show_trans_trace_vcd(property.counterexample.value(), message, ns, vcd);
161+
show_trans_trace_vcd(property.witness_trace.value(), message, ns, vcd);
158162

159163
break;
160164
}

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)