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
Risto Pejašinović
Robert Balas
Robin Heinemann
Rupert Swarbrick
Ryan Ziegler
Ryszard Rozak

View File

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

View File

@ -2882,10 +2882,14 @@ class WidthVisitor final : public VNVisitor {
pushDeletep(itemp->valuep()->unlinkFrBack());
}
}
const bool isHardPackedUnion
= nodep->packed() && VN_IS(nodep, UnionDType) && !VN_CAST(nodep, UnionDType)->isSoft();
// Determine bit assignments and width
if (VN_IS(nodep, UnionDType) || nodep->packed()) {
int lsb = 0;
int width = 0;
bool first = true;
// Report errors on first member first
AstMemberDType* itemp;
// MSB is first, so loop backwards
@ -2895,11 +2899,17 @@ class WidthVisitor final : public VNVisitor {
if (itemp->isFourstate()) nodep->isFourstate(true);
itemp->lsb(lsb);
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 {
lsb += itemp->width();
width += itemp->width();
}
first = false;
}
nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration
} else {

View File

@ -2304,7 +2304,7 @@ struct_unionDecl<nodeUOrStructDTypep>: // IEEE: part of data_type
/*cont*/ struct_union_memberListEnd
{ $$ = $<nodeUOrStructDTypep>4; $$->addMembersp($5); SYMP->popScope($$); }
| 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
{ $$ = $<nodeUOrStructDTypep>5; $$->addMembersp($6); SYMP->popScope($$); }
;
@ -2440,9 +2440,9 @@ random_qualifier<qualifiers>: // ==IEEE: random_qualifier
| yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; }
;
taggedSoftE:
/*empty*/ { }
| ySOFT { BBUNSUP($<fl>1, "Unsupported: 'union soft'"); }
taggedSoftE<cbool>:
/*empty*/ { $$ = false; }
| ySOFT { $$ = true; }
//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;
// 2-state packed unions of width > 32
typedef union packed { bit [ 32:0] x; bit y; } union_2_state_33;
typedef union packed { bit [ 63:0] x; bit y; } union_2_state_64;
typedef union packed { bit [ 64:0] x; bit y; } union_2_state_65;
typedef union packed { bit [127:0] x; bit y; } union_2_state_128;
typedef union packed { bit [ 32:0] x; bit [ 32:0] y; } union_2_state_33;
typedef union packed { bit [ 63:0] x; bit [ 63:0] y; } union_2_state_64;
typedef union packed { bit [ 64:0] x; bit [ 64:0] y; } union_2_state_65;
typedef union packed { bit [127:0] x; bit [127:0] y; } union_2_state_128;
// 4-state packed arrays of any size
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;
// 4-state packed unions of any size
typedef union packed { logic [ 0:0] x; bit y; } union_4_state_1;
typedef union packed { logic [ 1:0] x; bit y; } union_4_state_2;
typedef union packed { logic [ 7:0] x; bit y; } union_4_state_8;
typedef union packed { logic [ 8:0] x; bit y; } union_4_state_9;
typedef union packed { logic [ 15:0] x; bit y; } union_4_state_16;
typedef union packed { logic [ 16:0] x; bit y; } union_4_state_17;
typedef union packed { logic [ 31:0] x; bit y; } union_4_state_32;
typedef union packed { logic [ 32:0] x; bit y; } union_4_state_33;
typedef union packed { logic [ 63:0] x; bit y; } union_4_state_64;
typedef union packed { logic [ 64:0] x; bit y; } union_4_state_65;
typedef union packed { logic [127:0] x; bit y; } union_4_state_128;
typedef union packed { logic [ 0:0] x; bit [ 0:0] y; } union_4_state_1;
typedef union packed { logic [ 1:0] x; bit [ 1:0] y; } union_4_state_2;
typedef union packed { logic [ 7:0] x; bit [ 7:0] y; } union_4_state_8;
typedef union packed { logic [ 8:0] x; bit [ 8:0] y; } union_4_state_9;
typedef union packed { logic [ 15:0] x; bit [ 15:0] y; } union_4_state_16;
typedef union packed { logic [ 16:0] x; bit [ 16:0] y; } union_4_state_17;
typedef union packed { logic [ 31:0] x; bit [ 31:0] y; } union_4_state_32;
typedef union packed { logic [ 32:0] x; bit [ 32:0] y; } union_4_state_33;
typedef union packed { logic [ 63:0] x; bit [ 63:0] y; } union_4_state_64;
typedef union packed { logic [ 64:0] x; bit [ 64:0] y; } union_4_state_65;
typedef union packed { logic [127:0] x; bit [127:0] y; } union_4_state_128;
//======================================================================
// Imports

View File

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

View File

@ -6,10 +6,10 @@
// Packed struct in package
package TEST_TYPES;
typedef union packed {
logic [64:0] a;
logic [2:0] b;
} sub_t;
typedef union soft packed {
logic [64 : 0] a;
logic [2 : 0] b;
} sub_t;
typedef struct packed {
struct packed { // Anonymous packed struct
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.lint(fails=True, expect_filename=test.golden_filename)
test.compile()
test.execute()
test.passes()

View File

@ -11,13 +11,24 @@ module t(/*AUTOARG*/);
bit [3:0] val2;
} u;
union soft packed {
bit [7 : 0] val1;
bit [3 : 0] val2;
} u2;
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.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");
$finish;
end