Merge pull request #1365 from larsclausen/soft-unions
Support soft packed unions
This commit is contained in:
commit
0f75156d37
12
elab_type.cc
12
elab_type.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -220,11 +220,13 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
|||
|
||||
res->set_line(*this);
|
||||
|
||||
res->packed(packed_flag);
|
||||
bool is_packed = packed_flag || (union_flag && soft_flag);
|
||||
res->packed(is_packed);
|
||||
res->set_signed(signed_flag);
|
||||
|
||||
if (union_flag)
|
||||
res->union_flag(true);
|
||||
if (union_flag) {
|
||||
res->union_flag(true, soft_flag);
|
||||
}
|
||||
|
||||
for (list<struct_member_t*>::iterator cur = members->begin()
|
||||
; cur != members->end() ; ++ cur) {
|
||||
|
|
@ -242,7 +244,7 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
|||
; cur_name != curp->names->end() ; ++ cur_name) {
|
||||
decl_assignment_t*namep = *cur_name;
|
||||
|
||||
if (packed_flag && namep->expr) {
|
||||
if (is_packed && namep->expr) {
|
||||
cerr << namep->expr->get_fileline() << " error: "
|
||||
<< "Packed structs must not have default member values."
|
||||
<< endl;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
// Check that soft packed unions can have members with different widths.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
typedef union soft packed {
|
||||
logic [31:0] w;
|
||||
logic [15:0] h;
|
||||
logic [7:0] b;
|
||||
} data_t;
|
||||
|
||||
typedef union soft {
|
||||
logic [31:0] w;
|
||||
logic [7:0] b;
|
||||
} implicit_packed_t;
|
||||
|
||||
typedef union soft packed {
|
||||
logic [15:0] w;
|
||||
union soft {
|
||||
logic [7:0] b;
|
||||
logic [3:0] n;
|
||||
} part;
|
||||
} nested_t;
|
||||
|
||||
data_t data;
|
||||
implicit_packed_t implicit_packed;
|
||||
nested_t nested;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0h, got %0h", `__LINE__, \
|
||||
`"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
initial begin
|
||||
data.w = 32'h12345678;
|
||||
`check($bits(data), 32);
|
||||
`check($bits(data_t), 32);
|
||||
`check(data.w, 32'h12345678);
|
||||
`check(data.h, 16'h5678);
|
||||
`check(data.b, 8'h78);
|
||||
|
||||
data.h = 16'habcd;
|
||||
`check(data.w, 32'h1234abcd);
|
||||
`check(data.h, 16'habcd);
|
||||
`check(data.b, 8'hcd);
|
||||
|
||||
data.b = 8'hef;
|
||||
`check(data.w, 32'h1234abef);
|
||||
`check(data.h, 16'habef);
|
||||
`check(data.b, 8'hef);
|
||||
|
||||
implicit_packed.w = 32'hf0e1d2c3;
|
||||
`check($bits(implicit_packed_t), 32);
|
||||
`check(implicit_packed.b, 8'hc3);
|
||||
|
||||
implicit_packed.b = 8'h34;
|
||||
`check(implicit_packed.w, 32'hf0e1d234);
|
||||
|
||||
nested.w = 16'hbeef;
|
||||
`check($bits(nested_t), 16);
|
||||
`check($bits(nested.part), 8);
|
||||
`check(nested.part.b, 8'hef);
|
||||
`check(nested.part.n, 4'hf);
|
||||
|
||||
nested.part.n = 4'ha;
|
||||
`check(nested.w, 16'hbeea);
|
||||
`check(nested.part.b, 8'hea);
|
||||
|
||||
nested.part.b = 8'h55;
|
||||
`check(nested.w, 16'hbe55);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Check that soft packed unions can not have default member values.
|
||||
|
||||
module test;
|
||||
|
||||
typedef union soft {
|
||||
logic [31:0] w = 32'h1;
|
||||
logic [7:0] b;
|
||||
} data_t;
|
||||
|
||||
data_t data;
|
||||
|
||||
endmodule
|
||||
|
|
@ -339,6 +339,8 @@ sv_package_lifetime vvp_tests/sv_package_lifetime.json
|
|||
sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json
|
||||
sv_parameter_type vvp_tests/sv_parameter_type.json
|
||||
sv_queue_assign_op vvp_tests/sv_queue_assign_op.json
|
||||
sv_soft_packed_union vvp_tests/sv_soft_packed_union.json
|
||||
sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json
|
||||
sv_super_member_fail vvp_tests/sv_super_member_fail.json
|
||||
sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json
|
||||
sdf_header vvp_tests/sdf_header.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_soft_packed_union.v",
|
||||
"iverilog-args" : [ "-g2023" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_soft_packed_union_fail1.v",
|
||||
"iverilog-args" : [ "-g2023" ]
|
||||
}
|
||||
26
netstruct.cc
26
netstruct.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011-2022 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -26,22 +26,19 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
netstruct_t::netstruct_t()
|
||||
: union_(false), packed_(false), signed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
netstruct_t::~netstruct_t()
|
||||
{
|
||||
}
|
||||
|
||||
void netstruct_t::union_flag(bool flag)
|
||||
void netstruct_t::union_flag(bool flag, bool soft)
|
||||
{
|
||||
// This MUST be called before any members are pushed into the
|
||||
// definition. This is because the append relies on this flag
|
||||
// being accurate.
|
||||
ivl_assert(*this, members_.empty());
|
||||
ivl_assert(*this, flag || !soft);
|
||||
union_ = flag;
|
||||
soft_union_ = soft;
|
||||
}
|
||||
|
||||
void netstruct_t::packed(bool flag)
|
||||
|
|
@ -64,7 +61,7 @@ void netstruct_t::append_member(Design*des, const netstruct_t::member_t&val)
|
|||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
if (union_ && packed_ && members_.size() > 1) {
|
||||
if (union_ && packed_ && !soft_union_ && members_.size() > 1) {
|
||||
unsigned long expect_wid = members_.front().net_type->packed_width();
|
||||
unsigned long got_wid = members_.back().net_type->packed_width();
|
||||
if (expect_wid != got_wid) {
|
||||
|
|
@ -104,9 +101,20 @@ long netstruct_t::packed_width(void) const
|
|||
// If this is a packed union, then all the members are the
|
||||
// same width, so it is sufficient to return the width of any
|
||||
// single member.
|
||||
if (union_)
|
||||
if (union_ && !soft_union_)
|
||||
return members_.front().net_type->packed_width();
|
||||
|
||||
// A soft packed union uses the largest member width.
|
||||
if (union_ && soft_union_) {
|
||||
long res = 0;
|
||||
for (size_t idx = 0 ; idx < members_.size() ; idx += 1) {
|
||||
long wid = members_[idx].net_type->packed_width();
|
||||
if (wid > res)
|
||||
res = wid;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// The width of a packed struct is the sum of member widths.
|
||||
long res = 0;
|
||||
for (size_t idx = 0 ; idx < members_.size() ; idx += 1)
|
||||
|
|
|
|||
15
netstruct.h
15
netstruct.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_netstruct_H
|
||||
#define IVL_netstruct_H
|
||||
/*
|
||||
* Copyright (c) 2011-2025 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -39,14 +39,15 @@ class netstruct_t : public LineInfo, public ivl_type_s {
|
|||
};
|
||||
|
||||
public:
|
||||
netstruct_t();
|
||||
netstruct_t() = default;
|
||||
~netstruct_t() override;
|
||||
|
||||
// If this is a union (instead of struct) then this flag is
|
||||
// set. We handle union and struct together because they are
|
||||
// so similar.
|
||||
void union_flag(bool);
|
||||
void union_flag(bool, bool soft = false);
|
||||
bool union_flag(void) const;
|
||||
bool soft_union(void) const;
|
||||
|
||||
void packed(bool flag);
|
||||
bool packed(void) const override;
|
||||
|
|
@ -81,13 +82,15 @@ class netstruct_t : public LineInfo, public ivl_type_s {
|
|||
bool test_equivalence(ivl_type_t that) const override;
|
||||
|
||||
private:
|
||||
bool union_;
|
||||
bool packed_;
|
||||
bool signed_;
|
||||
bool union_ = false;
|
||||
bool soft_union_ = false;
|
||||
bool packed_ = false;
|
||||
bool signed_ = false;
|
||||
std::vector<member_t>members_;
|
||||
};
|
||||
|
||||
inline bool netstruct_t::union_flag(void) const { return union_; }
|
||||
inline bool netstruct_t::soft_union(void) const { return soft_union_; }
|
||||
inline bool netstruct_t::packed(void) const { return packed_; }
|
||||
|
||||
#endif /* IVL_netstruct_H */
|
||||
|
|
|
|||
39
parse.y
39
parse.y
|
|
@ -706,7 +706,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <flag> from_exclude block_item_decls_opt
|
||||
%type <number> number pos_neg_number
|
||||
%type <flag> signing unsigned_signed_opt signed_unsigned_opt
|
||||
%type <flag> import_export
|
||||
%type <flag> import_export union_soft_opt
|
||||
%type <flag> K_genvar_opt K_static_opt K_virtual_opt K_const_opt
|
||||
%type <flag> udp_reg_opt edge_operator
|
||||
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
|
||||
|
|
@ -1356,7 +1356,7 @@ packed_array_data_type /* IEEE1800-2005: A.2.2.1 */
|
|||
: enum_data_type
|
||||
{ $$ = $1; }
|
||||
| struct_data_type
|
||||
{ if (!$1->packed_flag) {
|
||||
{ if (!$1->packed_flag && !($1->union_flag && $1->soft_flag)) {
|
||||
yyerror(@1, "sorry: Unpacked structs not supported.");
|
||||
}
|
||||
$$ = $1;
|
||||
|
|
@ -3013,6 +3013,13 @@ packed_signing /* IEEE 1800-2012 A.2.2.1 */
|
|||
}
|
||||
;
|
||||
|
||||
union_soft_opt
|
||||
: K_soft
|
||||
{ $$ = true; }
|
||||
|
|
||||
{ $$ = false; }
|
||||
;
|
||||
|
||||
struct_data_type /* IEEE 1800-2012 A.2.2.1 */
|
||||
: K_struct packed_signing '{' struct_union_member_list '}'
|
||||
{ struct_type_t*tmp = new struct_type_t;
|
||||
|
|
@ -3020,16 +3027,20 @@ struct_data_type /* IEEE 1800-2012 A.2.2.1 */
|
|||
tmp->packed_flag = $2.packed_flag;
|
||||
tmp->signed_flag = $2.signed_flag;
|
||||
tmp->union_flag = false;
|
||||
tmp->members .reset($4);
|
||||
tmp->soft_flag = false;
|
||||
tmp->members.reset($4);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_union packed_signing '{' struct_union_member_list '}'
|
||||
{ struct_type_t*tmp = new struct_type_t;
|
||||
| K_union union_soft_opt packed_signing '{' struct_union_member_list '}'
|
||||
{ if ($2 && generation_flag < GN_VER2023)
|
||||
yyerror(@1, "error: Soft packed unions require SystemVerilog 2023 or later.");
|
||||
struct_type_t*tmp = new struct_type_t;
|
||||
FILE_NAME(tmp, @1);
|
||||
tmp->packed_flag = $2.packed_flag;
|
||||
tmp->signed_flag = $2.signed_flag;
|
||||
tmp->packed_flag = $3.packed_flag;
|
||||
tmp->signed_flag = $3.signed_flag;
|
||||
tmp->union_flag = true;
|
||||
tmp->members .reset($4);
|
||||
tmp->soft_flag = $2;
|
||||
tmp->members.reset($5);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_struct packed_signing '{' error '}'
|
||||
|
|
@ -3040,16 +3051,20 @@ struct_data_type /* IEEE 1800-2012 A.2.2.1 */
|
|||
tmp->packed_flag = $2.packed_flag;
|
||||
tmp->signed_flag = $2.signed_flag;
|
||||
tmp->union_flag = false;
|
||||
tmp->soft_flag = false;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_union packed_signing '{' error '}'
|
||||
{ yyerror(@3, "error: Errors in union member list.");
|
||||
| K_union union_soft_opt packed_signing '{' error '}'
|
||||
{ if ($2 && generation_flag < GN_VER2023)
|
||||
yyerror(@1, "error: Soft packed unions require SystemVerilog 2023 or later.");
|
||||
yyerror(@4, "error: Errors in union member list.");
|
||||
yyerrok;
|
||||
struct_type_t*tmp = new struct_type_t;
|
||||
FILE_NAME(tmp, @1);
|
||||
tmp->packed_flag = $2.packed_flag;
|
||||
tmp->signed_flag = $2.signed_flag;
|
||||
tmp->packed_flag = $3.packed_flag;
|
||||
tmp->signed_flag = $3.signed_flag;
|
||||
tmp->union_flag = true;
|
||||
tmp->soft_flag = $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ struct struct_type_t : public data_type_t {
|
|||
|
||||
bool packed_flag;
|
||||
bool union_flag;
|
||||
bool soft_flag;
|
||||
bool signed_flag;
|
||||
std::unique_ptr< std::list<struct_member_t*> > members;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue