Skip to content

Commit 6a5bbbd

Browse files
committed
SVA Monitors
This adds an alternative flow for checking SVA properties, by translating the property into a monitor, which is added to the transition system.
1 parent 3e92aeb commit 6a5bbbd

File tree

7 files changed

+181
-1
lines changed

7 files changed

+181
-1
lines changed

src/ebmc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ SRC = \
3232
show_formula_solver.cpp \
3333
show_properties.cpp \
3434
show_trans.cpp \
35+
sva_monitor.cpp \
3536
transition_system.cpp \
3637
waveform.cpp \
3738
#empty line

src/ebmc/ebmc_parse_options.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Author: Daniel Kroening, [email protected]
2626
#include "ranking_function.h"
2727
#include "show_properties.h"
2828
#include "show_trans.h"
29+
#include "sva_monitor.h"
2930

3031
#include <iostream>
3132

@@ -231,6 +232,9 @@ int ebmc_parse_optionst::doit()
231232
if(cmdline.isset("liveness-to-safety"))
232233
liveness_to_safety(transition_system, properties);
233234

235+
if(cmdline.isset("sva-monitor"))
236+
sva_monitor(transition_system, properties);
237+
234238
if(cmdline.isset("show-varmap"))
235239
{
236240
auto netlist =
@@ -361,6 +365,7 @@ void ebmc_parse_optionst::help()
361365
" {y--show-properties} \t list the properties in the model\n"
362366
" {y--property} {uid} \t check the property with given ID\n"
363367
" {y--liveness-to-safety} \t translate liveness properties to safety properties\n"
368+
" {y--sva-monitor} \t translate SVA properties into a monitor circuit\n"
364369
"\n"
365370
"Methods:\n"
366371
" {y--k-induction} \t do k-induction with k=bound\n"

src/ebmc/ebmc_parse_options.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ebmc_parse_optionst:public parse_options_baset
4848
"(random-traces)(trace-steps):(random-seed):(traces):"
4949
"(random-trace)(random-waveform)"
5050
"(bmc-with-assumptions)"
51-
"(liveness-to-safety)"
51+
"(liveness-to-safety)(sva-monitor)"
5252
"I:D:(preprocess)(systemverilog)(vl2smv-extensions)"
5353
"(warn-implicit-nets)",
5454
argc,

src/ebmc/sva_monitor.cpp

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*******************************************************************\
2+
3+
Module: SVA Monitor
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "sva_monitor.h"
10+
11+
#include <temporal-logic/ltl.h>
12+
#include <temporal-logic/temporal_logic.h>
13+
#include <verilog/sva_expr.h>
14+
15+
#include "ebmc_properties.h"
16+
#include "transition_system.h"
17+
18+
struct monitor_resultt
19+
{
20+
exprt safety = true_exprt{};
21+
exprt liveness = true_exprt{};
22+
exprt as_LTL() const;
23+
};
24+
25+
exprt monitor_resultt::as_LTL() const
26+
{
27+
exprt::operandst conjuncts;
28+
29+
if(!safety.is_true())
30+
conjuncts.push_back(G_exprt{safety});
31+
32+
if(!liveness.is_true())
33+
conjuncts.push_back(G_exprt{F_exprt{liveness}});
34+
35+
return conjunction(conjuncts);
36+
}
37+
38+
/// Recursion for creating a safety automaton for a safety property.
39+
/// * the property is assumed to be in NNF.
40+
/// * the monitor starts with the given "start" signal
41+
/// * the return value is the "safety" signal, or {} if not supported
42+
std::optional<exprt> create_sva_safety_monitor_rec(
43+
transition_systemt &transition_system,
44+
const exprt &start,
45+
const exprt &property_expr)
46+
{
47+
if(!has_temporal_operator(property_expr))
48+
{
49+
// A state formula only. Needs to hold in "start" states only.
50+
return and_exprt{start, property_expr};
51+
}
52+
else if(
53+
property_expr.id() == ID_not || property_expr.id() == ID_implies ||
54+
property_expr.id() == ID_nor || property_expr.id() == ID_nand ||
55+
property_expr.id() == ID_xor || property_expr.id() == ID_xnor)
56+
{
57+
// We rely on NNF.
58+
return {};
59+
}
60+
else if(property_expr.id() == ID_and)
61+
{
62+
// The conjunction of safety automata is built by conjoining the
63+
// safety signal.
64+
65+
exprt::operandst conjuncts;
66+
67+
for(auto &op : property_expr.operands())
68+
{
69+
auto rec = create_sva_safety_monitor_rec(transition_system, start, op);
70+
if(!rec.has_value())
71+
return {};
72+
conjuncts.push_back(rec.value());
73+
}
74+
75+
return conjunction(conjuncts);
76+
}
77+
else if(property_expr.id() == ID_or)
78+
{
79+
// Build automaton per disjunct.
80+
// Keep a state bit per automaton to record an unsafe state.
81+
// Signal an unsafe state when all subautomata signalled an unsafe state.
82+
return {};
83+
}
84+
else if(property_expr.id() == ID_sva_always)
85+
{
86+
// Nondeterministically guess when to start monitoring.
87+
//auto &op = to_sva_always_expr(expr).op();
88+
//return create_sva_safety_monitor_rec(transition_system, op);
89+
return {};
90+
}
91+
else if(property_expr.id() == ID_sva_s_nexttime)
92+
{
93+
// Simply wait one time frame.
94+
return {};
95+
}
96+
else
97+
return {}; // not supported
98+
}
99+
100+
exprt sva_monitor_initial(transition_systemt &transition_system)
101+
{
102+
return nil_exprt{};
103+
}
104+
105+
/// top-level formula
106+
std::optional<monitor_resultt>
107+
create_sva_monitor(transition_systemt &transition_system, exprt property_expr)
108+
{
109+
if(property_expr.id() == ID_sva_always)
110+
{
111+
auto &op = to_sva_always_expr(property_expr);
112+
113+
// Special-case "always p".
114+
if(!has_temporal_operator(op))
115+
return monitor_resultt{.safety = op};
116+
117+
// Create the top-level "start" signal -- on in the initial states exactly.
118+
auto start = sva_monitor_initial(transition_system);
119+
120+
// always X
121+
auto result_rec =
122+
create_sva_safety_monitor_rec(transition_system, start, op);
123+
if(result_rec.has_value())
124+
return monitor_resultt{.safety = result_rec.value()};
125+
}
126+
127+
return {}; // not supported
128+
}
129+
130+
void create_sva_monitor(
131+
transition_systemt &transition_system,
132+
ebmc_propertiest::propertyt &property)
133+
{
134+
auto result = create_sva_monitor(transition_system, property.normalized_expr);
135+
136+
if(result.has_value())
137+
property.normalized_expr = result.value().as_LTL();
138+
}
139+
140+
void sva_monitor(
141+
transition_systemt &transition_system,
142+
ebmc_propertiest &properties)
143+
{
144+
for(auto &property : properties.properties)
145+
{
146+
if(has_SVA_operator(property.normalized_expr))
147+
create_sva_monitor(transition_system, property);
148+
}
149+
}

src/ebmc/sva_monitor.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*******************************************************************\
2+
3+
Module: SVA Monitor
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_TEMPORAL_LOGIC_SVA_MONITOR_H
10+
#define CPROVER_TEMPORAL_LOGIC_SVA_MONITOR_H
11+
12+
class transition_systemt;
13+
class ebmc_propertiest;
14+
15+
void sva_monitor(transition_systemt &, ebmc_propertiest &);
16+
17+
#endif

src/temporal-logic/temporal_logic.cpp

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

135135
return !has_subexpr(expr, non_SVA_operator);
136136
}
137+
138+
bool has_SVA_operator(const exprt &expr)
139+
{
140+
return has_subexpr(expr, is_SVA_operator);
141+
}

src/temporal-logic/temporal_logic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ bool is_SVA_sequence(const exprt &);
5959
/// Returns true iff the given expression is an SVA temporal operator
6060
bool is_SVA_operator(const exprt &);
6161

62+
/// Returns true iff the given expression has an SVA temporal operator
63+
bool has_SVA_operator(const exprt &);
64+
6265
/// Returns true iff the given expression is an SVA expression
6366
bool is_SVA(const exprt &);
6467

0 commit comments

Comments
 (0)