Skip to content

Commit 2199fdd

Browse files
authored
Merge pull request #582 from diffblue/bit-extract5
Verilog: fix for index on packed arrays that are lsb first
2 parents 9db8244 + 07c9194 commit 2199fdd

File tree

6 files changed

+113
-46
lines changed

6 files changed

+113
-46
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
bit-extract5.sv
3+
--module main --bound 0
4+
^\[main\.p0\] always main\.w1\[0\] && !main\.w1\[31\]: PROVED up to bound 0$
5+
^\[main\.p1\] always main\.w2\[0\] && !main\.w2\[31\]: PROVED up to bound 0$
6+
^\[main\.p2\] always main\.w3\[0\] && !main\.w3\[31\]: PROVED up to bound 0$
7+
^\[main\.p3\] always main\.w4\[0\] && !main\.w4\[31\]: PROVED up to bound 0$
8+
^EXIT=0$
9+
^SIGNAL=0$
10+
--
11+
^warning: ignoring
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module main;
2+
3+
wire [31:0] w1 = 'b1;
4+
wire [32:1] w2 = 'b1;
5+
wire [0:31] w3 = 'b1;
6+
wire [1:32] w4 = 'b1;
7+
8+
p0: assert property (w1[0] and !w1[31]);
9+
p1: assert property (w2[1] and !w2[32]);
10+
p2: assert property (w3[31] and !w3[0]);
11+
p3: assert property (w4[32] and !w4[1]);
12+
13+
endmodule
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
bit-extract6.sv
3+
--module main --bound 0
4+
^\[main\.p0\] always \(main\.index == 8 |-> main\.vector\[7 - main\.index - 1\] == 1\): PROVED up to bound 0$
5+
^\[main\.p1\] always \(main\.index >= 1 \&\& main\.index <= 7 |-> main\.vector\[7 - main\.index - 1\] == 0\): PROVED up to bound 0$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module main;
2+
3+
wire [1:8] vector = 1;
4+
wire [7:0] index;
5+
6+
// Non-constant index.
7+
// Note that index 8 is the least significant bit.
8+
p0: assert property (index == 8 |-> vector[index] == 1);
9+
10+
// Verilog guarantees that any out-of-bounds access is zero.
11+
p1: assert property (index >= 1 && index <= 7 |-> vector[index] == 0);
12+
13+
endmodule

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,26 +1635,46 @@ bool verilog_typecheck_exprt::is_constant_expression(
16351635
exprt tmp(expr);
16361636

16371637
convert_expr(tmp);
1638-
ns.follow_macros(tmp);
1639-
1640-
simplify(tmp, ns);
16411638

1642-
if(tmp.is_true())
1643-
{
1644-
value=1;
1645-
return true;
1646-
}
1647-
else if(tmp.is_false())
1648-
{
1649-
value=0;
1650-
return true;
1651-
}
1652-
else if(!to_integer_non_constant(tmp, value))
1639+
auto integer_opt = is_constant_integer_post_convert(tmp);
1640+
if(integer_opt.has_value())
16531641
{
1642+
value = integer_opt.value();
16541643
return true;
16551644
}
1645+
else
1646+
return false;
1647+
}
1648+
1649+
/*******************************************************************\
1650+
1651+
Function: verilog_typecheck_exprt::is_constant_integer_post_convert
1652+
1653+
Inputs:
16561654
1657-
return false;
1655+
Outputs:
1656+
1657+
Purpose:
1658+
1659+
\*******************************************************************/
1660+
1661+
std::optional<mp_integer>
1662+
verilog_typecheck_exprt::is_constant_integer_post_convert(const exprt &expr)
1663+
{
1664+
exprt tmp = expr;
1665+
1666+
ns.follow_macros(tmp);
1667+
tmp = simplify_expr(tmp, ns);
1668+
1669+
if(!tmp.is_constant())
1670+
return {};
1671+
1672+
if(tmp.is_true())
1673+
return 1;
1674+
else if(tmp.is_false())
1675+
return 0;
1676+
else
1677+
return numeric_cast<mp_integer>(to_constant_expr(tmp));
16581678
}
16591679

16601680
/*******************************************************************\
@@ -2189,65 +2209,65 @@ exprt verilog_typecheck_exprt::convert_bit_select_expr(binary_exprt expr)
21892209
// Verilog's bit select expression may map onto an extractbit
21902210
// or an array index expression, depending on the type of the first
21912211
// operand.
2192-
exprt &op0 = expr.op0();
2212+
exprt &op0 = expr.op0(), &op1 = expr.op1();
21932213
convert_expr(op0);
2214+
convert_expr(op1);
21942215

21952216
if(op0.type().id() == ID_verilog_real)
21962217
{
21972218
throw errort().with_location(op0.source_location())
21982219
<< "bit-select of real is not allowed";
21992220
}
22002221

2201-
if(op0.type().id()==ID_array)
2222+
if(op1.type().id() == ID_verilog_real)
22022223
{
2203-
exprt &op1 = expr.op1();
2204-
convert_expr(op1);
2205-
if(op1.type().id() == ID_verilog_real)
2206-
{
2207-
throw errort().with_location(op1.source_location())
2208-
<< "real number index is not allowed";
2209-
}
2224+
throw errort().with_location(op1.source_location())
2225+
<< "real number index is not allowed";
2226+
}
22102227

2228+
if(op0.type().id() == ID_array)
2229+
{
22112230
typet _index_type = index_type(to_array_type(op0.type()));
2212-
2213-
if(_index_type!=op1.type())
2214-
{
2215-
mp_integer i;
2216-
if(!to_integer_non_constant(op1, i))
2217-
op1=from_integer(i, _index_type);
2218-
else if(op1.is_true() || op1.is_false())
2219-
op1=from_integer(op1.is_true()?1:0, _index_type);
2220-
else
2221-
op1 = typecast_exprt{op1, _index_type};
2222-
}
2231+
op1 = typecast_exprt{op1, _index_type};
22232232

22242233
expr.type() = to_array_type(op0.type()).element_type();
22252234
expr.id(ID_index);
22262235
}
22272236
else
22282237
{
22292238
auto width = get_width(op0.type());
2230-
auto offset = atoi(op0.type().get(ID_C_offset).c_str());
2239+
auto offset = op0.type().get_int(ID_C_offset);
22312240

2232-
mp_integer op1;
2241+
auto op1_opt = is_constant_integer_post_convert(op1);
22332242

2234-
if(is_constant_expression(expr.op1(), op1))
2243+
if(op1_opt.has_value()) // constant index
22352244
{
22362245
// 1800-2017 sec 11.5.1: out-of-bounds bit-select is
22372246
// x for 4-state and 0 for 2-state values.
2238-
if(op1 < offset || op1 >= width + offset)
2247+
auto op1_int = op1_opt.value();
2248+
2249+
if(op1_int < offset || op1_int >= width + offset)
22392250
return false_exprt().with_source_location(expr);
22402251

2241-
op1 -= offset;
2242-
expr.op1() = from_integer(op1, natural_typet());
2252+
op1_int -= offset;
2253+
2254+
if(op0.type().get_bool(ID_C_big_endian))
2255+
op1_int = width - op1_int - 1;
2256+
2257+
expr.op1() = from_integer(op1_int, natural_typet());
22432258
}
2244-
else
2259+
else // non-constant index
22452260
{
2246-
convert_expr(expr.op1());
2247-
if(expr.op1().type().id() == ID_verilog_real)
2261+
if(offset != 0)
2262+
{
2263+
expr.op1() =
2264+
minus_exprt{expr.op1(), from_integer(offset, expr.op1().type())};
2265+
}
2266+
2267+
if(op0.type().get_bool(ID_C_big_endian))
22482268
{
2249-
throw errort().with_location(expr.op1().source_location())
2250-
<< "real number index is not allowed";
2269+
expr.op1() =
2270+
minus_exprt{from_integer(width - 1, expr.op1().type()), expr.op1()};
22512271
}
22522272
}
22532273

src/verilog/verilog_typecheck_expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset
104104

105105
// elaboration (expansion and folding) of constant expressions and functions
106106
bool is_constant_expression(const exprt &, mp_integer &value);
107+
std::optional<mp_integer> is_constant_integer_post_convert(const exprt &);
107108
exprt elaborate_constant_expression(exprt);
108109

109110
// To be overridden, requires a Verilog interpreter.

0 commit comments

Comments
 (0)