Skip to content

Commit c5c0b42

Browse files
committed
SystemVerilog: structs
This adds support for SystemVerilog struct types.
1 parent 3fc2299 commit c5c0b42

14 files changed

+316
-71
lines changed
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
KNOWNBUG
2+
structs1.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
--
8+
cast bitvector to struct missing
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module main;
2+
3+
// The first field is the most-significant bit.
4+
struct packed {
5+
bit field1, field2;
6+
bit [6:0] field3;
7+
} s;
8+
9+
// bit-vectors can be converted without cast to packed structs
10+
initial s = 8'b1011111;
11+
12+
// Expected to pass.
13+
p0: assert property ($bits(s) == 9);
14+
p1: assert property (s.field1 == 1);
15+
p2: assert property (s.field2 == 0);
16+
p3: assert property (s.field3 == 'b111111);
17+
18+
endmodule
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
structs2.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module main;
2+
3+
// The first field is the most-significant bit.
4+
struct packed {
5+
bit field1, field2;
6+
bit [6:0] field3;
7+
} s;
8+
9+
initial begin
10+
s.field1 = 1;
11+
s.field2 = 0;
12+
s.field3 = 127;
13+
end
14+
15+
// Expected to pass.
16+
p1: assert property (s.field1 == 1);
17+
p2: assert property (s.field2 == 0);
18+
p3: assert property (s.field3 == 'b1111111);
19+
20+
endmodule
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
structs3.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module main;
2+
3+
struct packed {
4+
// a struct inside a struct
5+
struct packed {
6+
bit [7:0] field1;
7+
} field1;
8+
} s;
9+
10+
initial begin
11+
s.field1.field1 = 123;
12+
end
13+
14+
// Expected to pass.
15+
p1: assert property (s.field1.field1 == 123);
16+
17+
endmodule

src/verilog/expr2verilog.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,14 @@ std::string expr2verilogt::convert(const typet &type)
12511251
{
12521252
return "enum";
12531253
}
1254+
else if(type.id() == ID_struct)
1255+
{
1256+
return "struct";
1257+
}
1258+
else if(type.id() == ID_union)
1259+
{
1260+
return "union";
1261+
}
12541262
else if(type.id() == ID_verilog_type_reference)
12551263
{
12561264
auto &type_reference = to_verilog_type_reference(type);

src/verilog/parser.y

+22-3
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,11 @@ property_qualifier:
978978
| class_item_qualifier
979979
;
980980

981+
random_qualifier_opt:
982+
/* Optional */
983+
| random_qualifier
984+
;
985+
981986
random_qualifier:
982987
TOK_RAND
983988
| TOK_RANDC
@@ -1250,8 +1255,9 @@ data_type:
12501255
}
12511256
| non_integer_type
12521257
| struct_union packed_opt signing_opt
1253-
'{' struct_union_member_list '}' packed_dimension_brace
1254-
{ /* todo */ }
1258+
'{' struct_union_member_brace '}' packed_dimension_brace
1259+
{ $$=$1;
1260+
addswap($$, ID_declaration_list, $5); }
12551261
| TOK_ENUM enum_base_type_opt '{' enum_name_declaration_list '}'
12561262
{ // Like in C, these do _not_ create a scope.
12571263
// The enum names go into the current scope.
@@ -1330,7 +1336,20 @@ integer_atom_type:
13301336
class_type: class_identifier
13311337
;
13321338

1333-
struct_union_member_list:
1339+
struct_union_member_brace:
1340+
/* Not optional! No empty structs. */
1341+
struct_union_member
1342+
{ init($$); mts($$, $1); }
1343+
| struct_union_member_brace struct_union_member
1344+
{ $$=$1; mts($$, $2); }
1345+
;
1346+
1347+
struct_union_member:
1348+
attribute_instance_brace
1349+
random_qualifier_opt
1350+
data_type_or_void
1351+
list_of_variable_decl_assignments ';'
1352+
{ $$=$4; stack_expr($$).id(ID_decl); addswap($$, ID_type, $3); }
13341353
;
13351354

13361355
enum_base_type_opt:

src/verilog/verilog_expr.h

+45-41
Original file line numberDiff line numberDiff line change
@@ -402,55 +402,59 @@ inline verilog_set_genvarst &to_verilog_set_genvars(exprt &expr)
402402
return static_cast<verilog_set_genvarst &>(expr);
403403
}
404404

405-
class verilog_parameter_declt : public verilog_module_itemt
405+
// This class is used for all declarators in the parse tree
406+
class verilog_declaratort : public exprt
406407
{
407408
public:
408-
inline verilog_parameter_declt() : verilog_module_itemt(ID_parameter_decl)
409+
const irep_idt &identifier() const
409410
{
411+
return get(ID_identifier);
410412
}
411413

412-
class declaratort : public exprt
414+
void identifier(irep_idt _identifier)
413415
{
414-
public:
415-
const irep_idt &identifier() const
416-
{
417-
return get(ID_identifier);
418-
}
416+
set(ID_identifier, _identifier);
417+
}
419418

420-
void identifier(irep_idt _identifier)
421-
{
422-
set(ID_identifier, _identifier);
423-
}
419+
const irep_idt &base_name() const
420+
{
421+
return get(ID_base_name);
422+
}
424423

425-
const irep_idt &base_name() const
426-
{
427-
return get(ID_base_name);
428-
}
424+
const exprt &value() const
425+
{
426+
return static_cast<const exprt &>(find(ID_value));
427+
}
429428

430-
const exprt &value() const
431-
{
432-
return static_cast<const exprt &>(find(ID_value));
433-
}
429+
exprt &value()
430+
{
431+
return static_cast<exprt &>(add(ID_value));
432+
}
434433

435-
exprt &value()
436-
{
437-
return static_cast<exprt &>(add(ID_value));
438-
}
434+
bool has_value() const
435+
{
436+
return find(ID_value).is_not_nil();
437+
}
439438

440-
bool has_value() const
441-
{
442-
return find(ID_value).is_not_nil();
443-
}
439+
// helper to generate a symbol expression
440+
symbol_exprt symbol_expr() const
441+
{
442+
return symbol_exprt(identifier(), type())
443+
.with_source_location<symbol_exprt>(*this);
444+
}
445+
};
444446

445-
// helper to generate a symbol expression
446-
symbol_exprt symbol_expr() const
447-
{
448-
return symbol_exprt(identifier(), type())
449-
.with_source_location<symbol_exprt>(*this);
450-
}
451-
};
447+
using verilog_declaratorst = std::vector<verilog_declaratort>;
448+
449+
class verilog_parameter_declt : public verilog_module_itemt
450+
{
451+
public:
452+
inline verilog_parameter_declt() : verilog_module_itemt(ID_parameter_decl)
453+
{
454+
}
452455

453-
using declaratorst = std::vector<declaratort>;
456+
using declaratort = verilog_declaratort;
457+
using declaratorst = verilog_declaratorst;
454458

455459
const declaratorst &declarations() const
456460
{
@@ -484,8 +488,8 @@ class verilog_local_parameter_declt : public verilog_module_itemt
484488
{
485489
}
486490

487-
using declaratort = verilog_parameter_declt::declaratort;
488-
using declaratorst = std::vector<declaratort>;
491+
using declaratort = verilog_declaratort;
492+
using declaratorst = verilog_declaratorst;
489493

490494
const declaratorst &declarations() const
491495
{
@@ -516,7 +520,7 @@ class verilog_lett : public verilog_module_itemt
516520
{
517521
public:
518522
// These have a single declarator.
519-
using declaratort = verilog_parameter_declt::declaratort;
523+
using declaratort = verilog_declaratort;
520524

521525
const declaratort &declarator() const
522526
{
@@ -700,8 +704,8 @@ class verilog_declt:public verilog_statementt
700704
}
701705

702706
// When it's not a function or task, there are declarators.
703-
using declaratort = verilog_parameter_declt::declaratort;
704-
using declaratorst = verilog_parameter_declt::declaratorst;
707+
using declaratort = verilog_declaratort;
708+
using declaratorst = verilog_declaratorst;
705709

706710
declaratorst &declarators()
707711
{

src/verilog/verilog_synthesis.cpp

+35-1
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,31 @@ void verilog_synthesist::assignment_rec(
564564

565565
new_value.swap(last_value);
566566
}
567+
else if(lhs.id() == ID_member)
568+
{
569+
const auto &member_expr = to_member_expr(lhs);
570+
const exprt &lhs_compound = member_expr.struct_op();
571+
auto component_name = member_expr.get_component_name();
572+
573+
if(lhs_compound.type().id() == ID_struct)
574+
{
575+
// turn
576+
// s.m=e
577+
// into
578+
// s'==s WITH [m:=e]
579+
auto synth_compound = synth_expr(lhs_compound, symbol_statet::FINAL);
580+
581+
with_exprt new_rhs{
582+
synth_compound, member_designatort{component_name}, rhs};
583+
584+
// recursive call
585+
assignment_rec(lhs_compound, new_rhs, new_value); // recursive call
586+
}
587+
else
588+
{
589+
throw errort() << "unexpected member lhs: " << lhs_compound.type().id();
590+
}
591+
}
567592
else
568593
{
569594
throw errort() << "unexpected lhs: " << lhs.id();
@@ -723,6 +748,10 @@ void verilog_synthesist::assignment_member_rec(
723748

724749
member.pop_back();
725750
}
751+
else if(lhs.id() == ID_member)
752+
{
753+
add_assignment_member(lhs, member, data);
754+
}
726755
else
727756
{
728757
throw errort() << "unexpected lhs: " << lhs.id();
@@ -854,9 +883,14 @@ const symbolt &verilog_synthesist::assignment_symbol(const exprt &lhs)
854883

855884
return it->second;
856885
}
886+
else if(e->id() == ID_member)
887+
{
888+
e = &to_member_expr(*e).struct_op();
889+
}
857890
else
858891
{
859-
throw errort() << "synthesis: failed to get identifier";
892+
throw errort().with_location(e->source_location())
893+
<< "synthesis: failed to get identifier";
860894
}
861895
}
862896
}

src/verilog/verilog_typecheck.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,10 @@ void verilog_typecheckt::check_lhs(
805805
break;
806806
}
807807
}
808+
else if(lhs.id() == ID_member)
809+
{
810+
check_lhs(to_member_expr(lhs).struct_op(), vassign);
811+
}
808812
else
809813
{
810814
throw errort() << "typechecking: failed to get identifier on LHS "

src/verilog/verilog_typecheck_base.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ std::size_t verilog_typecheck_baset::get_width(const typet &type)
182182
return (array_size(to_array_type(type)) * element_width).to_ulong();
183183
}
184184

185+
if(type.id() == ID_struct)
186+
{
187+
// add them up
188+
mp_integer sum = 0;
189+
for(auto &component : to_struct_type(type).components())
190+
sum += get_width(component.type());
191+
return sum.to_ulong();
192+
}
193+
185194
if(type.id() == ID_verilog_shortint)
186195
return 16;
187196
else if(type.id() == ID_verilog_int)

0 commit comments

Comments
 (0)