mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support unpacked unions.
This commit is contained in:
parent
a39c7f7dac
commit
93517b8378
2
Changes
2
Changes
@ -13,6 +13,8 @@ Verilator 5.007 devel
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Support unpacked unions.
|
||||
|
||||
|
||||
Verilator 5.006 2022-01-22
|
||||
==========================
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)) {
|
||||
|
@ -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");
|
||||
|
@ -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()));
|
||||
|
@ -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) {
|
||||
|
@ -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 += "%@";
|
||||
|
@ -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);
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user