Skip to content

Commit 8ee5500

Browse files
committed
Verilog: assignment pattern expressions
This adds support for struct and array literals to the SystemVerilog frontend by implementing the assignment_pattern_expression production rules.
1 parent f48e9b2 commit 8ee5500

File tree

9 files changed

+135
-0
lines changed

9 files changed

+135
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
array_literal1.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module main;
2+
3+
reg [7:0] my_array[10] = '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
4+
5+
initial p0: assert property (my_array[0] == 1);
6+
initial p1: assert property (my_array[9] == 10);
7+
8+
endmodule
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
array_literal2.sv
3+
4+
^file array_literal2\.sv line 3: number of expressions does not match number of array elements$
5+
^CONVERSION ERROR$
6+
^EXIT=2$
7+
^SIGNAL=0$
8+
--
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module main;
2+
3+
reg [7:0] my_array[10] = '{1, 2, 3, 4}; // too short
4+
5+
endmodule
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
structs5.sv
3+
--bound 0
4+
^\[main\.p1\] always main\.s\.field1 == 1: PROVED up to bound 0$
5+
^\[main\.p2\] always main\.s\.field2 == 0: PROVED up to bound 0$
6+
^\[main\.p3\] always main\.s\.field3 == 115: PROVED up to bound 0$
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module main;
2+
3+
struct packed {
4+
bit field1, field2;
5+
bit [6:0] field3;
6+
} s = '{ 1, 0, 'b1110011 };
7+
8+
// Expected to pass.
9+
p1: assert property (s.field1 == 1);
10+
p2: assert property (s.field2 == 0);
11+
p3: assert property (s.field3 == 'b1110011);
12+
13+
endmodule

src/hw_cbmc_irep_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ IREP_ID_TWO(C_little_endian, #little_endian)
5050
IREP_ID_ONE(ports)
5151
IREP_ID_ONE(inst)
5252
IREP_ID_ONE(Verilog)
53+
IREP_ID_ONE(verilog_assignment_pattern)
5354
IREP_ID_ONE(verilog_explicit_cast)
5455
IREP_ID_ONE(verilog_size_cast)
5556
IREP_ID_ONE(verilog_implicit_typecast)

src/verilog/parser.y

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,18 @@ case_item:
30093009
mto($$, $2); }
30103010
;
30113011

3012+
// System Verilog standard 1800-2017
3013+
// A.6.7.1 Patterns
3014+
3015+
assignment_pattern:
3016+
'\'' '{' expression_brace '}'
3017+
{ init($$, ID_verilog_assignment_pattern); swapop($$, $3); }
3018+
;
3019+
3020+
assignment_pattern_expression:
3021+
assignment_pattern
3022+
;
3023+
30123024
// System Verilog standard 1800-2017
30133025
// A.6.8 Looping statements
30143026
@@ -3331,6 +3343,7 @@ primary: primary_literal
33313343
| '(' mintypmax_expression ')'
33323344
{ $$ = $2; }
33333345
| cast
3346+
| assignment_pattern_expression
33343347
| TOK_NULL { init($$, ID_NULL); }
33353348
;
33363349

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,20 @@ exprt verilog_typecheck_exprt::convert_expr_rec(exprt expr)
318318
{
319319
return convert_expr_function_call(to_function_call_expr(expr));
320320
}
321+
else if(expr.id() == ID_verilog_assignment_pattern)
322+
{
323+
// multi-ary -- may become a struct or array, depending
324+
// on context.
325+
for(auto &op : expr.operands())
326+
convert_expr(op);
327+
328+
// Typechecking can only be completed once we know the type
329+
// from the usage context. We record "verilog_assignment_pattern"
330+
// to signal that.
331+
expr.type() = typet(ID_verilog_assignment_pattern);
332+
333+
return expr;
334+
}
321335
else
322336
{
323337
std::size_t no_op;
@@ -1614,6 +1628,64 @@ void verilog_typecheck_exprt::implicit_typecast(
16141628
return;
16151629
}
16161630
}
1631+
else if(src_type.id() == ID_verilog_assignment_pattern)
1632+
{
1633+
DATA_INVARIANT(
1634+
expr.id() == ID_verilog_assignment_pattern,
1635+
"verilog_assignment_pattern expression expected");
1636+
if(dest_type.id() == ID_struct)
1637+
{
1638+
auto &struct_type = to_struct_type(dest_type);
1639+
auto &components = struct_type.components();
1640+
1641+
if(expr.operands().size() != components.size())
1642+
{
1643+
throw errort().with_location(expr.source_location())
1644+
<< "number of expressions does not match number of struct members";
1645+
}
1646+
1647+
for(std::size_t i = 0; i < components.size(); i++)
1648+
{
1649+
// rec. call
1650+
implicit_typecast(expr.operands()[i], components[i].type());
1651+
}
1652+
1653+
// turn into struct expression
1654+
expr.id(ID_struct);
1655+
expr.type() = dest_type;
1656+
return;
1657+
}
1658+
else if(dest_type.id() == ID_array)
1659+
{
1660+
auto &array_type = to_array_type(dest_type);
1661+
auto &element_type = array_type.element_type();
1662+
auto array_size =
1663+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
1664+
1665+
if(array_size != expr.operands().size())
1666+
{
1667+
throw errort().with_location(expr.source_location())
1668+
<< "number of expressions does not match number of array elements";
1669+
}
1670+
1671+
for(std::size_t i = 0; i < array_size; i++)
1672+
{
1673+
// rec. call
1674+
implicit_typecast(expr.operands()[i], element_type);
1675+
}
1676+
1677+
// turn into array expression
1678+
expr.id(ID_array);
1679+
expr.type() = dest_type;
1680+
return;
1681+
}
1682+
else
1683+
{
1684+
throw errort().with_location(expr.source_location())
1685+
<< "cannot convert assignment pattern to '" << to_string(dest_type)
1686+
<< '\'';
1687+
}
1688+
}
16171689

16181690
throw errort().with_location(expr.source_location())
16191691
<< "failed to convert `" << to_string(src_type) << "' to `"

0 commit comments

Comments
 (0)