Skip to content

Commit d4525b6

Browse files
authored
Merge pull request #738 from diffblue/union4
SystemVerilog: conversion from/to packed union
2 parents ea914df + 820a299 commit d4525b6

File tree

6 files changed

+87
-4
lines changed

6 files changed

+87
-4
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
KNOWNBUG
1+
CORE
22
unions1.sv
33
--bound 0
44
^EXIT=0$
55
^SIGNAL=0$
66
--
77
--
8-
cast bitvector to union missing
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
unions4.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
--

regression/verilog/unions/unions4.sv

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module main;
2+
3+
union packed {
4+
bit [6:0] field1;
5+
bit [6:0] field2;
6+
} u;
7+
8+
initial u.field1 = 7'b1010101;
9+
10+
// Packed unions can be treated like bit-vectors.
11+
// Expected to pass.
12+
p0: assert property ($bits(u) == 7);
13+
p1: assert property (u == 7'b1010101);
14+
p2: assert property (u[1] == 0);
15+
16+
endmodule

src/verilog/verilog_synthesis.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include <util/bitvector_expr.h>
1313
#include <util/bitvector_types.h>
14+
#include <util/c_types.h>
1415
#include <util/ebmc_util.h>
1516
#include <util/expr_util.h>
1617
#include <util/identifier.h>
@@ -113,6 +114,21 @@ exprt verilog_synthesist::from_bitvector(
113114

114115
return struct_exprt{std::move(field_values), struct_type};
115116
}
117+
else if(dest.id() == ID_union)
118+
{
119+
// We use the first field of the union.
120+
// All fields of a SystemVerilog packed union must have the same width.
121+
const auto &union_type = to_union_type(dest);
122+
DATA_INVARIANT(
123+
!union_type.components().empty(),
124+
"union type must have at least one field");
125+
auto &field = union_type.components().front();
126+
127+
// rec. call
128+
auto field_value = from_bitvector(src, offset, field.type());
129+
130+
return union_exprt{field.get_name(), std::move(field_value), union_type};
131+
}
116132
else
117133
{
118134
return extract(src, offset, dest);
@@ -152,6 +168,16 @@ exprt verilog_synthesist::to_bitvector(const exprt &src)
152168
auto width_int = numeric_cast_v<std::size_t>(get_width(src));
153169
return concatenation_exprt{std::move(field_values), bv_typet{width_int}};
154170
}
171+
else if(src_type.id() == ID_union)
172+
{
173+
const auto &union_type = to_union_type(src_type);
174+
DATA_INVARIANT(
175+
!union_type.components().empty(),
176+
"union type must have at least one field");
177+
auto &field = union_type.components().front();
178+
auto member = member_exprt{src, field};
179+
return to_bitvector(member); // rec. call
180+
}
155181
else
156182
{
157183
return src;
@@ -302,13 +328,13 @@ exprt verilog_synthesist::synth_expr(exprt expr, symbol_statet symbol_state)
302328
auto aval_bval_type = lower_to_aval_bval(dest_type);
303329
return aval_bval_conversion(typecast_expr.op(), aval_bval_type);
304330
}
305-
else if(dest_type.id() == ID_struct)
331+
else if(dest_type.id() == ID_struct || dest_type.id() == ID_union)
306332
{
307333
return from_bitvector(typecast_expr.op(), 0, dest_type);
308334
}
309335
else
310336
{
311-
if(src_type.id() == ID_struct)
337+
if(src_type.id() == ID_struct || src_type.id() == ID_union)
312338
{
313339
return extract(to_bitvector(typecast_expr.op()), 0, dest_type);
314340
}

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,34 @@ typet verilog_typecheck_exprt::enum_decay(const typet &type)
21442144

21452145
/*******************************************************************\
21462146
2147+
Function: verilog_typecheck_exprt::union_decay
2148+
2149+
Inputs:
2150+
2151+
Outputs:
2152+
2153+
Purpose:
2154+
2155+
\*******************************************************************/
2156+
2157+
void verilog_typecheck_exprt::union_decay(exprt &expr) const
2158+
{
2159+
// 1800-2017 7.3.1
2160+
// Verilog union types decay to a vector type [$bits(t)-1:0] when
2161+
// used in relational or arithmetic expressions.
2162+
auto &type = expr.type();
2163+
if(type.id() == ID_union)
2164+
{
2165+
auto new_type =
2166+
unsignedbv_typet{numeric_cast_v<std::size_t>(get_width(type))};
2167+
// The synthesis stage turns these typecasts into a member
2168+
// expression.
2169+
expr = typecast_exprt{expr, new_type};
2170+
}
2171+
}
2172+
2173+
/*******************************************************************\
2174+
21472175
Function: verilog_typecheck_exprt::tc_binary_expr
21482176
21492177
Inputs:
@@ -2158,6 +2186,9 @@ void verilog_typecheck_exprt::tc_binary_expr(
21582186
const exprt &expr,
21592187
exprt &op0, exprt &op1)
21602188
{
2189+
union_decay(op0);
2190+
union_decay(op1);
2191+
21612192
// follows 1800-2017 11.8.2
21622193
const typet new_type =
21632194
max_type(enum_decay(op0.type()), enum_decay(op1.type()));
@@ -2223,6 +2254,9 @@ void verilog_typecheck_exprt::typecheck_relation(binary_exprt &expr)
22232254
auto &lhs = expr.lhs();
22242255
auto &rhs = expr.rhs();
22252256

2257+
union_decay(lhs);
2258+
union_decay(rhs);
2259+
22262260
// Relations are special-cased in 1800-2017 11.8.2.
22272261
const typet new_type =
22282262
max_type(enum_decay(lhs.type()), enum_decay(rhs.type()));

src/verilog/verilog_typecheck_expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset
136136
}
137137

138138
static typet enum_decay(const typet &);
139+
void union_decay(exprt &) const;
139140
typet max_type(const typet &t1, const typet &t2);
140141

141142
// named blocks

0 commit comments

Comments
 (0)