diff --git a/regression/verilog/SVA/always_with_range1.desc b/regression/verilog/SVA/always_with_range1.desc index e96c12721..0db55e248 100644 --- a/regression/verilog/SVA/always_with_range1.desc +++ b/regression/verilog/SVA/always_with_range1.desc @@ -4,6 +4,7 @@ always_with_range1.sv ^\[main\.p0\] always \[0:9\] main\.x < 10: PROVED up to bound 20$ ^\[main\.p1\] always \[0:\$\] main\.x < 10: REFUTED$ ^\[main\.p2\] s_always \[0:9\] main\.x < 10: PROVED up to bound 20$ +^\[main\.p3\] always \(main\.x == 1 implies \(always \[1:1\] main\.x == 2\)\): PROVED up to bound 20$ ^EXIT=10$ ^SIGNAL=0$ -- diff --git a/regression/verilog/SVA/always_with_range1.sv b/regression/verilog/SVA/always_with_range1.sv index 7f806401e..1083f2501 100644 --- a/regression/verilog/SVA/always_with_range1.sv +++ b/regression/verilog/SVA/always_with_range1.sv @@ -17,4 +17,7 @@ module main; // strong variant initial p2: assert property (s_always [0:9] x<10); + // nested + p3: assert property (always (x==1 implies always [1:1] x==2)); + endmodule diff --git a/src/trans-word-level/instantiate_word_level.cpp b/src/trans-word-level/instantiate_word_level.cpp index 49f580104..7e5aeb85b 100644 --- a/src/trans-word-level/instantiate_word_level.cpp +++ b/src/trans-word-level/instantiate_word_level.cpp @@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include @@ -350,6 +351,47 @@ wl_instantiatet::instantiate_rec(exprt expr, const mp_integer &t) const DATA_INVARIANT(no_timeframes != 0, "must have timeframe"); return {no_timeframes - 1, conjunction(conjuncts)}; } + else if(expr.id() == ID_sva_ranged_always || expr.id() == ID_sva_s_always) + { + auto &phi = expr.id() == ID_sva_ranged_always + ? to_sva_ranged_always_expr(expr).op() + : to_sva_s_always_expr(expr).op(); + auto &lower = expr.id() == ID_sva_ranged_always + ? to_sva_ranged_always_expr(expr).lower() + : to_sva_s_always_expr(expr).lower(); + auto &upper = expr.id() == ID_sva_ranged_always + ? to_sva_ranged_always_expr(expr).upper() + : to_sva_s_always_expr(expr).upper(); + + auto from_opt = numeric_cast(lower); + if(!from_opt.has_value()) + throw ebmc_errort() << "failed to convert SVA always from index"; + + auto from = t + std::max(mp_integer{0}, *from_opt); + + mp_integer to; + + if(upper.id() == ID_infinity) + { + to = no_timeframes - 1; + } + else + { + auto to_opt = numeric_cast(upper); + if(!to_opt.has_value()) + throw ebmc_errort() << "failed to convert SVA always to index"; + to = std::min(t + *to_opt, no_timeframes - 1); + } + + exprt::operandst conjuncts; + + for(mp_integer c = from; c <= to; ++c) + { + conjuncts.push_back(instantiate_rec(phi, c).second); + } + + return {to, conjunction(conjuncts)}; + } else if(expr.id() == ID_X) { const auto next = t + 1;