Skip to content

Commit bc9b8e6

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 4f26892 commit bc9b8e6

File tree

7 files changed

+185
-1
lines changed

7 files changed

+185
-1
lines changed

src/ebmc/Makefile

+1
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

+5
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

+1-1
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

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

src/ebmc/sva_monitor.h

+17
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

+5
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

+3
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)