Support unpacked unions.

This commit is contained in:
Wilson Snyder 2023-01-27 22:41:12 -05:00
parent a39c7f7dac
commit 93517b8378
16 changed files with 53 additions and 58 deletions

View File

@ -13,6 +13,8 @@ Verilator 5.007 devel
**Minor:**
* Support unpacked unions.
Verilator 5.006 2022-01-22
==========================

View File

@ -200,6 +200,7 @@ private:
using MemberNameMap = std::map<const std::string, AstMemberDType*>;
// MEMBERS
string m_name; // Name from upper typedef, if any
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
MemberNameMap m_members;
const int m_uniqueNum;
bool m_packed;
@ -255,6 +256,8 @@ public:
static int lo() { return 0; }
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
};
// === Concrete node types =====================================================
@ -1319,15 +1322,12 @@ public:
// === AstNodeUOrStructDType ===
class AstStructDType final : public AstNodeUOrStructDType {
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
public:
// VSigning below is mispurposed to indicate if packed or not
AstStructDType(FileLine* fl, VSigning numericUnpack)
: ASTGEN_SUPER_StructDType(fl, numericUnpack) {}
ASTGEN_MEMBERS_AstStructDType;
string verilogKwd() const override { return "struct"; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
};
class AstUnionDType final : public AstNodeUOrStructDType {
public:

View File

@ -737,8 +737,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
info.m_type = "VlUnpacked<" + sub.m_type;
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
info.m_type += ">";
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, StructDType);
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep);
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,

View File

@ -75,7 +75,7 @@ class CUseVisitor final : public VNVisitor {
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
// Add a CUse for every struct that requires a declaration
AstStructDType* const stypep = VN_CAST(nodep->skipRefp(), StructDType);
AstNodeUOrStructDType* const stypep = VN_CAST(nodep->skipRefp(), NodeUOrStructDType);
if (stypep && stypep->classOrPackagep()) {
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
iterateChildren(stypep);

View File

@ -171,24 +171,25 @@ private:
}
}
void setStructModulep(AstStructDType* const dtypep) {
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
// Give it a pointer to its package and a final name
dtypep->classOrPackagep(m_modp);
dtypep->name(dtypep->name() + "__struct" + cvtToStr(dtypep->uniqueNum()));
dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct")
+ cvtToStr(dtypep->uniqueNum()));
for (const AstMemberDType* itemp = dtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstStructDType* const subp = VN_CAST(itemp->skipRefp(), StructDType);
AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
// Recurse only into anonymous unpacked structs inside this definition,
// other unpacked structs will be reached from another typedefs
if (subp && !subp->packed() && subp->name().empty()) { setStructModulep(subp); }
if (subp && !subp->packed() && subp->name().empty()) setStructModulep(subp);
}
}
void visit(AstTypedef* nodep) override {
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
AstStructDType* const dtypep = VN_CAST(nodep->dtypep(), StructDType);
AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType);
if (dtypep && !dtypep->packed()) {
dtypep->name(nodep->name());
setStructModulep(dtypep);

View File

@ -97,9 +97,9 @@ private:
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) {
} else {
const AstStructDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), StructDType);
if (!dtypep || dtypep->packed()) { setCppWidth(nodep); }
const AstNodeUOrStructDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
if (!dtypep || dtypep->packed()) setCppWidth(nodep);
}
}
}

View File

@ -61,7 +61,7 @@ static void makeVlToString(AstIface* nodep) {
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);
}
static void makeVlToString(AstStructDType* nodep) {
static void makeVlToString(AstNodeUOrStructDType* nodep) {
AstNodeModule* const modp = nodep->classOrPackagep();
AstCFunc* const funcp
= new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"};
@ -168,7 +168,7 @@ void V3Common::commonAll() {
}
for (AstNode* nodep = v3Global.rootp()->typeTablep()->typesp(); nodep;
nodep = nodep->nextp()) {
if (AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
if (AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) {
if (!dtypep->packed()) makeVlToString(dtypep);
}
}

View File

@ -324,7 +324,7 @@ private:
}
}
bool shouldDeleteTypedef(AstTypedef* typedefp) {
if (auto* structp = VN_CAST(typedefp->subDTypep(), StructDType)) {
if (auto* const structp = VN_CAST(typedefp->subDTypep(), NodeUOrStructDType)) {
if (structp->user1() && !structp->packed()) return false;
}
return m_elimCells && !typedefp->attrPublic();

View File

@ -673,8 +673,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
depth + 1, suffix + "[" + ivar + "]");
const string post = "}\n";
return below.empty() ? "" : pre + below + post;
} else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, StructDType);
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
string literal;
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {

View File

@ -208,13 +208,13 @@ class EmitCHeader final : public EmitCConstInit {
}
}
}
void emitStructDecl(const AstNodeModule* modp, AstStructDType* sdtypep,
std::set<AstStructDType*>& emitted) {
void emitStructDecl(const AstNodeModule* modp, AstNodeUOrStructDType* sdtypep,
std::set<AstNodeUOrStructDType*>& emitted) {
if (emitted.count(sdtypep) > 0) return;
emitted.insert(sdtypep);
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstStructDType* subp = VN_CAST(itemp->skipRefp(), StructDType);
AstNodeUOrStructDType* subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType);
if (subp && !subp->packed()) {
// Recurse if it belongs to the current module
if (subp->classOrPackagep() == modp) {
@ -223,7 +223,8 @@ class EmitCHeader final : public EmitCConstInit {
}
}
}
puts("struct " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n");
puts(sdtypep->verilogKwd()); // "struct"/"union"
puts(" " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n");
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false));
@ -234,12 +235,12 @@ class EmitCHeader final : public EmitCConstInit {
void emitStructs(const AstNodeModule* modp) {
bool first = true;
// Track structs that've been emitted already
std::set<AstStructDType*> emitted;
std::set<AstNodeUOrStructDType*> emitted;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
const AstTypedef* const tdefp = VN_CAST(nodep, Typedef);
if (!tdefp) continue;
AstStructDType* const sdtypep
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), StructDType);
AstNodeUOrStructDType* const sdtypep
= VN_CAST(tdefp->dtypep()->skipRefToEnump(), NodeUOrStructDType);
if (!sdtypep) continue;
if (sdtypep->packed()) continue;
decorateFirst(first, "\n// UNPACKED STRUCT TYPES\n");

View File

@ -50,7 +50,8 @@ class EmitCGatherDependencies final : VNVisitor {
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
m_dependencies.insert(
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
} else if (const AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) {
} else if (const AstNodeUOrStructDType* const dtypep
= VN_CAST(nodep, NodeUOrStructDType)) {
if (!dtypep->packed()) {
m_dependencies.insert(
EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep()));

View File

@ -122,7 +122,7 @@ private:
if (AstRefDType* const refdtypep = VN_CAST(dtypep, RefDType)) { //
dtypep = refdtypep->skipRefp();
}
if (AstStructDType* const stp = VN_CAST(dtypep, StructDType)) {
if (AstNodeUOrStructDType* const stp = VN_CAST(dtypep, NodeUOrStructDType)) {
if (stp->packed()) {
std::ostringstream out;
out << "'{";
@ -418,7 +418,7 @@ private:
if (!VN_IS(nodep->varp()->dtypeSkipRefp(), BasicDType)
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), PackArrayDType)
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType)
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType))
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), NodeUOrStructDType))
clearOptimizable(nodep, "Array references/not basic");
if (nodep->access().isWriteOrRW()) {
if (m_inDlyAssign) {

View File

@ -2478,13 +2478,7 @@ private:
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5, " NODECLASS " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree("- class-in: ");
if (!nodep->packed()) {
if (VN_IS(nodep, UnionDType)) {
nodep->v3warn(UNPACKED, "Unsupported: Unpacked union");
} else if (v3Global.opt.structsPacked()) {
nodep->packed(true);
}
}
if (!nodep->packed() && v3Global.opt.structsPacked()) { nodep->packed(true); }
userIterateChildren(nodep, nullptr); // First size all members
nodep->repairMemberCache();
nodep->dtypep(nodep);
@ -4594,7 +4588,7 @@ private:
|| VN_IS(dtypep, DynArrayDType) //
|| VN_IS(dtypep, UnpackArrayDType) //
|| VN_IS(dtypep, QueueDType)
|| (VN_IS(dtypep, StructDType)
|| (VN_IS(dtypep, NodeUOrStructDType)
&& !VN_AS(dtypep, StructDType)->packed())) {
added = true;
newFormat += "%@";

View File

@ -2,17 +2,19 @@
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# Copyright 2023 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
scenarios(linter => 1);
scenarios(simulator => 1);
lint(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
compile(
);
execute(
check_finished => 1,
);
ok(1);

View File

@ -1,21 +1,22 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2009 by Wilson Snyder.
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module x;
module t(/*AUTOARG*/);
typedef union {
int a;
} union_t;
union_t b;
union {
bit [7:0] val1;
bit [3:0] val2;
} u;
initial begin
b = 1;
if (b != 1) $stop;
u.val1 = 8'h7c;
if (u.val1 != 8'h7c) $stop;
if (u.val2 != 4'hc) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,7 +0,0 @@
%Warning-UNPACKED: t/t_union_unpacked_bad.v:9:12: Unsupported: Unpacked union
: ... In instance x
9 | typedef union {
| ^~~~~
... For warning description see https://verilator.org/warn/UNPACKED?v=latest
... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message.
%Error: Exiting due to