Support soft unions (#5912) (#5932)

This commit is contained in:
Robin Heinemann 2025-04-12 13:35:37 +02:00 committed by GitHub
parent 7336b9ebfc
commit 10c3320c6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 109 additions and 31 deletions

View File

@ -196,6 +196,7 @@ Ricardo Barbedo
Richard Myers Richard Myers
Risto Pejašinović Risto Pejašinović
Robert Balas Robert Balas
Robin Heinemann
Rupert Swarbrick Rupert Swarbrick
Ryan Ziegler Ryan Ziegler
Ryszard Rozak Ryszard Rozak

View File

@ -1388,13 +1388,20 @@ public:
string verilogKwd() const override { return "struct"; } string verilogKwd() const override { return "struct"; }
}; };
class AstUnionDType final : public AstNodeUOrStructDType { class AstUnionDType final : public AstNodeUOrStructDType {
bool m_isSoft; // Is a "union soft"
public: public:
// UNSUP: bool isTagged; // UNSUP: bool isTagged;
// VSigning below is mispurposed to indicate if packed or not // VSigning below is mispurposed to indicate if packed or not
AstUnionDType(FileLine* fl, VSigning numericUnpack) // isSoft implies packed
: ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} AstUnionDType(FileLine* fl, bool isSoft, VSigning numericUnpack)
: ASTGEN_SUPER_UnionDType(fl, numericUnpack)
, m_isSoft(isSoft) {
packed(packed() | m_isSoft);
}
ASTGEN_MEMBERS_AstUnionDType; ASTGEN_MEMBERS_AstUnionDType;
string verilogKwd() const override { return "union"; } string verilogKwd() const override { return "union"; }
bool isSoft() const { return m_isSoft; }
}; };
#endif // Guard #endif // Guard

View File

@ -2882,10 +2882,14 @@ class WidthVisitor final : public VNVisitor {
pushDeletep(itemp->valuep()->unlinkFrBack()); pushDeletep(itemp->valuep()->unlinkFrBack());
} }
} }
const bool isHardPackedUnion
= nodep->packed() && VN_IS(nodep, UnionDType) && !VN_CAST(nodep, UnionDType)->isSoft();
// Determine bit assignments and width // Determine bit assignments and width
if (VN_IS(nodep, UnionDType) || nodep->packed()) { if (VN_IS(nodep, UnionDType) || nodep->packed()) {
int lsb = 0; int lsb = 0;
int width = 0; int width = 0;
bool first = true;
// Report errors on first member first // Report errors on first member first
AstMemberDType* itemp; AstMemberDType* itemp;
// MSB is first, so loop backwards // MSB is first, so loop backwards
@ -2895,11 +2899,17 @@ class WidthVisitor final : public VNVisitor {
if (itemp->isFourstate()) nodep->isFourstate(true); if (itemp->isFourstate()) nodep->isFourstate(true);
itemp->lsb(lsb); itemp->lsb(lsb);
if (VN_IS(nodep, UnionDType)) { if (VN_IS(nodep, UnionDType)) {
width = std::max(width, itemp->width()); const int itemWidth = itemp->width();
if (!first && isHardPackedUnion && itemWidth != width) {
itemp->v3error("Hard packed union members must have equal size "
"(IEEE 1800-2023 7.3.1)");
}
width = std::max(width, itemWidth);
} else { } else {
lsb += itemp->width(); lsb += itemp->width();
width += itemp->width(); width += itemp->width();
} }
first = false;
} }
nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration
} else { } else {

View File

@ -2304,7 +2304,7 @@ struct_unionDecl<nodeUOrStructDTypep>: // IEEE: part of data_type
/*cont*/ struct_union_memberListEnd /*cont*/ struct_union_memberListEnd
{ $$ = $<nodeUOrStructDTypep>4; $$->addMembersp($5); SYMP->popScope($$); } { $$ = $<nodeUOrStructDTypep>4; $$->addMembersp($5); SYMP->popScope($$); }
| yUNION taggedSoftE packedSigningE '{' | yUNION taggedSoftE packedSigningE '{'
/*mid*/ { $<nodeUOrStructDTypep>$ = new AstUnionDType{$1, $3}; SYMP->pushNew($<nodeUOrStructDTypep>$); } /*mid*/ { $<nodeUOrStructDTypep>$ = new AstUnionDType{$1, $2, $3}; SYMP->pushNew($<nodeUOrStructDTypep>$); }
/*cont*/ struct_union_memberListEnd /*cont*/ struct_union_memberListEnd
{ $$ = $<nodeUOrStructDTypep>5; $$->addMembersp($6); SYMP->popScope($$); } { $$ = $<nodeUOrStructDTypep>5; $$->addMembersp($6); SYMP->popScope($$); }
; ;
@ -2440,9 +2440,9 @@ random_qualifier<qualifiers>: // ==IEEE: random_qualifier
| yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; } | yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; }
; ;
taggedSoftE: taggedSoftE<cbool>:
/*empty*/ { } /*empty*/ { $$ = false; }
| ySOFT { BBUNSUP($<fl>1, "Unsupported: 'union soft'"); } | ySOFT { $$ = true; }
//UNSUP yTAGGED { UNSUP } //UNSUP yTAGGED { UNSUP }
; ;

View File

@ -27,10 +27,10 @@ module t_dpi_result_type_bad;
typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128; typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128;
// 2-state packed unions of width > 32 // 2-state packed unions of width > 32
typedef union packed { bit [ 32:0] x; bit y; } union_2_state_33; typedef union packed { bit [ 32:0] x; bit [ 32:0] y; } union_2_state_33;
typedef union packed { bit [ 63:0] x; bit y; } union_2_state_64; typedef union packed { bit [ 63:0] x; bit [ 63:0] y; } union_2_state_64;
typedef union packed { bit [ 64:0] x; bit y; } union_2_state_65; typedef union packed { bit [ 64:0] x; bit [ 64:0] y; } union_2_state_65;
typedef union packed { bit [127:0] x; bit y; } union_2_state_128; typedef union packed { bit [127:0] x; bit [127:0] y; } union_2_state_128;
// 4-state packed arrays of any size // 4-state packed arrays of any size
typedef logic [ 0:0] array_4_state_1_t; typedef logic [ 0:0] array_4_state_1_t;
@ -59,17 +59,17 @@ module t_dpi_result_type_bad;
typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128; typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128;
// 4-state packed unions of any size // 4-state packed unions of any size
typedef union packed { logic [ 0:0] x; bit y; } union_4_state_1; typedef union packed { logic [ 0:0] x; bit [ 0:0] y; } union_4_state_1;
typedef union packed { logic [ 1:0] x; bit y; } union_4_state_2; typedef union packed { logic [ 1:0] x; bit [ 1:0] y; } union_4_state_2;
typedef union packed { logic [ 7:0] x; bit y; } union_4_state_8; typedef union packed { logic [ 7:0] x; bit [ 7:0] y; } union_4_state_8;
typedef union packed { logic [ 8:0] x; bit y; } union_4_state_9; typedef union packed { logic [ 8:0] x; bit [ 8:0] y; } union_4_state_9;
typedef union packed { logic [ 15:0] x; bit y; } union_4_state_16; typedef union packed { logic [ 15:0] x; bit [ 15:0] y; } union_4_state_16;
typedef union packed { logic [ 16:0] x; bit y; } union_4_state_17; typedef union packed { logic [ 16:0] x; bit [ 16:0] y; } union_4_state_17;
typedef union packed { logic [ 31:0] x; bit y; } union_4_state_32; typedef union packed { logic [ 31:0] x; bit [ 31:0] y; } union_4_state_32;
typedef union packed { logic [ 32:0] x; bit y; } union_4_state_33; typedef union packed { logic [ 32:0] x; bit [ 32:0] y; } union_4_state_33;
typedef union packed { logic [ 63:0] x; bit y; } union_4_state_64; typedef union packed { logic [ 63:0] x; bit [ 63:0] y; } union_4_state_64;
typedef union packed { logic [ 64:0] x; bit y; } union_4_state_65; typedef union packed { logic [ 64:0] x; bit [ 64:0] y; } union_4_state_65;
typedef union packed { logic [127:0] x; bit y; } union_4_state_128; typedef union packed { logic [127:0] x; bit [127:0] y; } union_4_state_128;
//====================================================================== //======================================================================
// Imports // Imports

View File

@ -6,9 +6,9 @@
typedef logic [5:0] udata6_t; typedef logic [5:0] udata6_t;
typedef union packed { typedef union soft packed {
udata6_t a; udata6_t a;
logic [2:0] b; logic [2 : 0] b;
} sub_t; } sub_t;
typedef struct packed { typedef struct packed {

View File

@ -6,10 +6,10 @@
// Packed struct in package // Packed struct in package
package TEST_TYPES; package TEST_TYPES;
typedef union packed { typedef union soft packed {
logic [64:0] a; logic [64 : 0] a;
logic [2:0] b; logic [2 : 0] b;
} sub_t; } sub_t;
typedef struct packed { typedef struct packed {
struct packed { // Anonymous packed struct struct packed { // Anonymous packed struct
logic a; logic a;

View File

@ -0,0 +1,6 @@
%Error: t/t_union_hard_bad.v:11:21: Hard packed union members must have equal size (IEEE 1800-2023 7.3.1)
: ... note: In instance 't'
11 | bit [7 : 0] val1;
| ^~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,25 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t
(/*AUTOARG*/);
union packed {
bit [7 : 0] val1;
bit [3 : 0] val2;
} u;
initial begin
u.val1 = 8'h7c;
if(u.val1 != 8'h7c) $stop;
u.val2 = 4'h6;
if(u.val2 != 4'h6) $stop;
$display("%p", u);
if(u.val1 != 8'h76) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -11,6 +11,8 @@ import vltest_bootstrap
test.scenarios('vlt') test.scenarios('vlt')
test.lint(fails=True, expect_filename=test.golden_filename) test.compile()
test.execute()
test.passes() test.passes()

View File

@ -11,13 +11,24 @@ module t(/*AUTOARG*/);
bit [3:0] val2; bit [3:0] val2;
} u; } u;
union soft packed {
bit [7 : 0] val1;
bit [3 : 0] val2;
} u2;
initial begin initial begin
u.val1 = 8'h7c; u.val1 = 8'h7c;
if (u.val1 != 8'h7c) $stop; if (u.val1 != 8'h7c) $stop;
u.val2 = 4'h6; u.val2 = 4'h6;
if (u.val2 != 4'h6) $stop; if (u.val2 != 4'h6) $stop;
$display("%p", u); $display("%p", u);
if (u.ual1 != 8'h76) $stop; if(u.val1 != 8'h76) $stop;
u2.val1 = 8'h7c;
if(u2.val1 != 8'h7c) $stop;
u2.val2 = 4'h6;
if(u2.val2 != 4'h6) $stop;
$display("%p", u2);
if(u2.val1 != 8'h76) $stop;
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end