Skip to content

Commit 07c9194

Browse files
committed
Verilog: fix for index on packed arrays that are lsb first
Verilog allows packed arrays (vectors) to arrange the bits in the vector in order of decreasing significance. As we internally always use increasing significance, we need to flip the index around in this case.
1 parent 2a28a48 commit 07c9194

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)