Skip to content

Commit 17fdbb0

Browse files
committed
BDD engine: transform SVA to LTL, then LTL to CTL
The BDD engine now transforms SVA to LTL, when possible, which in turn is transformed to CTL, when possible. This is strictly more general than the current direct mapping.
1 parent f20c412 commit 17fdbb0

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)