Skip to content

Commit 09f5af1

Browse files
authored
Merge pull request #1096 from diffblue/bdd-sva-via-ltl
BDD engine: transform SVA to LTL, then LTL to CTL
2 parents 11ae20a + 17fdbb0 commit 09f5af1

24 files changed

+129
-75
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
followed-by1.sv
3+
--bdd
4+
^\[main\.p0\] main\.x == 0 #=# \(main\.x == 1 #=# main\.x == 2\): PROVED$
5+
^\[main\.p1\] main\.x == 0 #-# \(\(##1 main\.x == 1\) #-# \(##1 main\.x == 2\)\): PROVED$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
followed-by2.sv
3+
--bdd
4+
^\[main\.p0\] always \(\(main\.a #-# main\.b\) iff \(not \(main\.a |-> \(not main\.b\)\)\)\): PROVED$
5+
^\[main\.p1\] always \(\(main\.a #=# main\.b\) iff \(not \(main\.a |=> \(not main\.b\)\)\)\): FAILURE: property not supported by BDD engine$
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
followed-by4.sv
3+
--bdd
4+
^\[main\.p1\] always \(main\.x == 0 #-# 1\): REFUTED$
5+
^\[main\.p2\] \(1 or \(##2 1\)\) #-# main\.x == 2: FAILURE: property not supported by BDD engine$
6+
^\[main\.p3\] \(1 or \(##2 1\)\) #-# main\.x == 0: FAILURE: property not supported by BDD engine$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
initial1.sv
3+
--bdd
4+
^\[main\.p0\] main\.counter == 0: PROVED$
5+
^\[main\.p1\] main\.counter == 100: REFUTED$
6+
^\[main\.p2\] ##1 main\.counter == 1: PROVED$
7+
^\[main\.p3\] ##1 main\.counter == 100: REFUTED$
8+
^\[main\.p4\] s_nexttime main\.counter == 1: PROVED$
9+
^\[main\.p5\] always \[1:1\] main\.counter == 1: PROVED$
10+
^EXIT=10$
11+
^SIGNAL=0$
12+
--
13+
^warning: ignoring
14+
--
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
nexttime1.sv
3+
--bdd
4+
^\[main\.p1\] s_nexttime\[0\] main\.counter == 0: PROVED$
5+
^\[main\.p2\] s_nexttime\[1\] main\.counter == 1: PROVED$
6+
^\[main\.p3\] nexttime\[8\] main\.counter == 8: PROVED$
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
restrict1.sv
3+
--bdd
4+
^\[main\.p0\] always main\.x != 5: ASSUMED$
5+
^\[main\.p1\] always main\.x != 6: PROVED$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
s_eventually1.sv
3+
--bdd
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
sequence4.sv
3+
--bdd
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
sequence_and1.sv
3+
--bdd
4+
^\[main\.p0\] main\.x == 0 and main\.x == 1: REFUTED$
5+
^\[main\.p1\] strong\(main\.x == 0 and main\.x == 1\): REFUTED$
6+
^\[main\.p2\] main\.x == 0 and \(nexttime main\.x == 1\): PROVED$
7+
^\[main\.p3\] \(nexttime main\.x == 1\) and main\.x == 0: PROVED$
8+
^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED$
9+
^EXIT=10$
10+
^SIGNAL=0$
11+
--
12+
^warning: ignoring
13+
--

regression/verilog/SVA/sequence_repetition1.sv

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
module main(input clk);
22

3-
reg [31:0] x = 0;
3+
reg [7:0] x = 0;
44

55
// 0 1 2 3 4 ...
66
always_ff @(posedge clk)
77
x<=x+1;
88

99
// 0 0 1 1 2 2 3 3 ...
10-
wire [31:0] half_x = x/2;
10+
wire [7:0] half_x = x/2;
1111

1212
// should pass
1313
initial p0: assert property (half_x==0[*2]);

regression/verilog/SVA/sequence_repetition2.sv

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
module main(input clk);
22

3-
reg [31:0] x = 0;
3+
reg [7:0] x = 0;
44

55
// 0 1 2 3 4 ...
66
always_ff @(posedge clk)
77
x<=x+1;
88

99
// 0 0 1 1 2 2 3 3 ...
10-
wire [31:0] half_x = x/2;
10+
wire [7:0] half_x = x/2;
1111

1212
// should pass
1313
initial p0: assert property (x==0[*]);

regression/verilog/SVA/sequence_repetition3.sv

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
module main(input clk);
22

3-
reg [31:0] x = 0;
3+
reg [7:0] x = 0;
44

55
// 0 1 2 3 4 ...
66
always_ff @(posedge clk)
77
x<=x+1;
88

99
// 0 0 1 1 2 2 3 3 ...
10-
wire [31:0] half_x = x/2;
10+
wire [7:0] half_x = x/2;
1111

1212
// should pass
1313
initial p0: assert property (x==0[*1] #=# x==1[*1]);
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
CORE
22
past1.sv
33
--bdd
4-
^\[main\.p0\] ##0 \$past\(main\.counter, 0\) == 0: FAILURE: property not supported by BDD engine$
5-
^EXIT=10$
4+
^EXIT=0$
65
^SIGNAL=0$
76
--

regression/verilog/system-functions/past1.sv

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module main(input clk);
22

3-
reg [31:0] counter = 0;
3+
reg [7:0] counter = 0;
44

55
always @(posedge clk)
66
counter++;

src/ebmc/bdd_engine.cpp

+26-66
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ Author: Daniel Kroening, [email protected]
2323
#include <trans-netlist/instantiate_netlist.h>
2424
#include <trans-netlist/trans_trace_netlist.h>
2525
#include <trans-netlist/unwind_netlist.h>
26-
#include <verilog/sva_expr.h>
2726

2827
#include "netlist.h"
2928

@@ -66,7 +65,7 @@ class bdd_enginet
6665
const namespacet ns;
6766
netlistt netlist;
6867

69-
static bool property_supported(const exprt &);
68+
static std::optional<exprt> property_supported(const exprt &);
7069

7170
// the Manager must appear before any BDDs
7271
// to do the cleanup in the right order
@@ -199,9 +198,20 @@ property_checker_resultt bdd_enginet::operator()()
199198
<< ", nodes: " << netlist.number_of_nodes()
200199
<< messaget::eom;
201200

202-
for(const auto &property : properties.properties)
203-
if(property_supported(property.normalized_expr))
204-
get_atomic_propositions(property.normalized_expr);
201+
for(auto &property : properties.properties)
202+
{
203+
if(!property.is_disabled() && !property.is_assumed())
204+
{
205+
auto converted_opt = property_supported(property.normalized_expr);
206+
if(converted_opt.has_value())
207+
{
208+
property.normalized_expr = *converted_opt;
209+
get_atomic_propositions(*converted_opt);
210+
}
211+
else
212+
property.failure("property not supported by BDD engine");
213+
}
214+
}
205215

206216
message.status() << "Building BDD for netlist" << messaget::eom;
207217

@@ -449,40 +459,29 @@ Function: bdd_enginet::property_supported
449459
450460
\*******************************************************************/
451461

452-
bool bdd_enginet::property_supported(const exprt &expr)
462+
std::optional<exprt> bdd_enginet::property_supported(const exprt &expr)
453463
{
454464
// Our engine knows all of CTL.
455465
if(is_CTL(expr))
456-
return true;
466+
return expr;
457467

458468
if(is_LTL(expr))
459469
{
460470
// We can map selected path properties to CTL.
461-
return LTL_to_CTL(expr).has_value();
471+
return LTL_to_CTL(expr);
462472
}
463473

464474
if(is_SVA(expr))
465475
{
466-
if(
467-
expr.id() == ID_sva_always &&
468-
!has_temporal_operator(to_sva_always_expr(expr).op()))
469-
{
470-
// always p
471-
return true;
472-
}
473-
474-
if(
475-
expr.id() == ID_sva_always &&
476-
to_sva_always_expr(expr).op().id() == ID_sva_s_eventually &&
477-
!has_temporal_operator(
478-
to_sva_s_eventually_expr(to_sva_always_expr(expr).op()).op()))
479-
{
480-
// always s_eventually p
481-
return true;
482-
}
476+
// We can map some SVA to LTL. In turn, some of that can be mapped to CTL.
477+
auto ltl_opt = SVA_to_LTL(expr);
478+
if(ltl_opt.has_value())
479+
return property_supported(ltl_opt.value());
480+
else
481+
return {};
483482
}
484483

485-
return false;
484+
return {};
486485
}
487486

488487
/*******************************************************************\
@@ -505,51 +504,12 @@ void bdd_enginet::check_property(propertyt &property)
505504
if(property.is_assumed())
506505
return;
507506

508-
if(!property_supported(property.normalized_expr))
509-
{
510-
property.failure("property not supported by BDD engine");
507+
if(property.is_failure())
511508
return;
512-
}
513509

514510
message.status() << "Checking " << property.name << messaget::eom;
515511
property.status=propertyt::statust::UNKNOWN;
516512

517-
if(
518-
property.normalized_expr.id() == ID_sva_always &&
519-
to_sva_always_expr(property.normalized_expr).op().id() ==
520-
ID_sva_s_eventually &&
521-
!has_temporal_operator(to_sva_s_eventually_expr(
522-
to_sva_always_expr(property.normalized_expr).op())
523-
.op()))
524-
{
525-
// always s_eventually p --> AG AF p
526-
auto p = to_sva_s_eventually_expr(
527-
to_sva_always_expr(property.normalized_expr).op())
528-
.op();
529-
property.normalized_expr = AG_exprt{AF_exprt{p}};
530-
}
531-
532-
if(
533-
property.normalized_expr.id() == ID_sva_always &&
534-
!has_temporal_operator(to_sva_always_expr(property.normalized_expr).op()))
535-
{
536-
// always p --> AG p
537-
auto p = to_sva_always_expr(property.normalized_expr).op();
538-
property.normalized_expr = AG_exprt{p};
539-
}
540-
541-
// Our engine knows CTL only.
542-
// We map selected path properties to CTL.
543-
if(
544-
has_temporal_operator(property.normalized_expr) &&
545-
is_LTL(property.normalized_expr))
546-
{
547-
auto CTL_opt = LTL_to_CTL(property.normalized_expr);
548-
CHECK_RETURN(CTL_opt.has_value());
549-
property.normalized_expr = CTL_opt.value();
550-
CHECK_RETURN(is_CTL(property.normalized_expr));
551-
}
552-
553513
if(is_AGp(property.normalized_expr))
554514
{
555515
check_AGp(property);

0 commit comments

Comments
 (0)