mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Fix pattern assignment to unpacked structs (#3510).
This commit is contained in:
parent
4208db7811
commit
6a7dfb7696
1
Changes
1
Changes
@ -17,6 +17,7 @@ Verilator 5.007 devel
|
||||
* Support interface classes and class implements.
|
||||
* Support global clocking and $global_clock.
|
||||
* Fix real parameters of infinity and NaN.
|
||||
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
|
||||
|
||||
|
||||
Verilator 5.006 2022-01-22
|
||||
|
@ -865,6 +865,7 @@ public:
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_AstMemberDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
|
@ -790,6 +790,51 @@ public:
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsPackMember final : public AstNodeExpr {
|
||||
// Construct a packed array single emement [member1: value1]
|
||||
// Don't need the member we are constructing, as the dtypep can get us to it
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
public:
|
||||
explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_ConsPackMember(fl) {
|
||||
this->dtypep(dtypep);
|
||||
this->rhsp(rhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConsPackMember;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType));
|
||||
return nullptr;
|
||||
}
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsPackUOrStruct final : public AstNodeExpr {
|
||||
// Construct a packed struct and return object, '{member1: value1, member2: value2}
|
||||
// Don't need the class we are constructing, as the dtypep can get us to it
|
||||
// @astgen op1 := membersp : List[AstConsPackMember]
|
||||
public:
|
||||
explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep,
|
||||
AstConsPackMember* membersp = nullptr)
|
||||
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
|
||||
this->dtypep(dtypep);
|
||||
this->addMembersp(membersp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConsPackUOrStruct;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType));
|
||||
return nullptr;
|
||||
}
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstConsQueue final : public AstNodeExpr {
|
||||
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
|
||||
// @astgen op1 := lhsp : Optional[AstNode]
|
||||
|
@ -1646,6 +1646,10 @@ void AstLogOr::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (sideEffect()) str << " [SIDE]";
|
||||
}
|
||||
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "member";
|
||||
}
|
||||
void AstMemberSel::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
str << " -> ";
|
||||
|
@ -87,7 +87,8 @@ private:
|
||||
}
|
||||
void computeCppWidth(AstNode* nodep) {
|
||||
if (!nodep->user2() && nodep->hasDType()) {
|
||||
if (VN_IS(nodep, Var)
|
||||
if (VN_IS(nodep, Var) //
|
||||
|| VN_IS(nodep, ConsPackMember) //
|
||||
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)
|
||||
|
@ -1262,6 +1262,21 @@ public:
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void visit(AstConsPackUOrStruct* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
puts("{");
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
iterate(memberp);
|
||||
if (memberp->nextp()) { puts(", "); }
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
void visit(AstConsPackMember* nodep) override {
|
||||
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
|
||||
putbs(vdtypep->name());
|
||||
puts(": ");
|
||||
iterate(nodep->rhsp());
|
||||
}
|
||||
void visit(AstConsQueue* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
if (!nodep->lhsp()) {
|
||||
|
@ -2320,6 +2320,18 @@ private:
|
||||
EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
void visit(AstConsPackUOrStruct* nodep) override {
|
||||
// Type was computed when constructed in V3Width earlier
|
||||
auto* const vdtypep = VN_AS(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
|
||||
UASSERT_OBJ(vdtypep, nodep, "ConsPackUOrStruct requires packed array parent data type");
|
||||
userIterateChildren(nodep, WidthVP{vdtypep, BOTH}.p());
|
||||
}
|
||||
void visit(AstConsPackMember* nodep) override {
|
||||
// Type was computed when constructed in V3Width earlier
|
||||
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
|
||||
UASSERT_OBJ(vdtypep, nodep, "ConsPackMember requires member data type");
|
||||
if (m_vup->prelim()) userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, BOTH}.p());
|
||||
}
|
||||
void visit(AstConsDynArray* nodep) override {
|
||||
// Type computed when constructed here
|
||||
AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType);
|
||||
@ -3835,26 +3847,45 @@ private:
|
||||
}
|
||||
}
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (AstMemberDType* memp = vdtypep->membersp(); memp;
|
||||
memp = VN_AS(memp->nextp(), MemberDType)) {
|
||||
const auto it = patmap.find(memp);
|
||||
AstPatMember* patp = nullptr;
|
||||
if (it == patmap.end()) {
|
||||
// default or default_type assignment
|
||||
if (AstNodeUOrStructDType* const memp_nested_vdtypep
|
||||
= VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) {
|
||||
newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp, newp,
|
||||
nodep, dtypemap);
|
||||
} else {
|
||||
patp = Defaultpatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp,
|
||||
dtypemap);
|
||||
if (vdtypep->packed()) {
|
||||
for (AstMemberDType* memp = vdtypep->membersp(); memp;
|
||||
memp = VN_AS(memp->nextp(), MemberDType)) {
|
||||
const auto it = patmap.find(memp);
|
||||
AstPatMember* patp = nullptr;
|
||||
if (it == patmap.end()) { // default or default_type assignment
|
||||
if (AstNodeUOrStructDType* const memp_nested_vdtypep
|
||||
= VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) {
|
||||
newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp,
|
||||
newp, nodep, dtypemap);
|
||||
} else {
|
||||
patp = defaultPatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp,
|
||||
dtypemap);
|
||||
newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep);
|
||||
}
|
||||
} else { // member assignment
|
||||
patp = it->second;
|
||||
newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep);
|
||||
}
|
||||
} else {
|
||||
// member assignment
|
||||
patp = it->second;
|
||||
newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep);
|
||||
}
|
||||
} else { // Unpacked
|
||||
AstConsPackMember* membersp = nullptr;
|
||||
for (AstMemberDType* memp = vdtypep->membersp(); memp;
|
||||
memp = VN_AS(memp->nextp(), MemberDType)) {
|
||||
const auto it = patmap.find(memp);
|
||||
AstPatMember* patp = nullptr;
|
||||
if (it == patmap.end()) { // Default or default_type assignment
|
||||
patp = defaultPatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp,
|
||||
dtypemap);
|
||||
} else {
|
||||
patp = it->second; // Member assignment
|
||||
}
|
||||
patp->dtypep(memp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
AstConsPackMember* const cpmp
|
||||
= new AstConsPackMember{patp->fileline(), memp, valuep};
|
||||
membersp = membersp ? membersp->addNext(cpmp) : cpmp;
|
||||
}
|
||||
newp = new AstConsPackUOrStruct{nodep->fileline(), vdtypep, membersp};
|
||||
}
|
||||
if (newp) {
|
||||
nodep->replaceWith(newp);
|
||||
@ -3877,7 +3908,7 @@ private:
|
||||
newp = nestedvalueConcat_patternUOrStruct(memp_multinested_vdtypep, defaultp, newp,
|
||||
nodep, dtypemap);
|
||||
} else {
|
||||
patp = Defaultpatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep,
|
||||
patp = defaultPatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep,
|
||||
defaultp, dtypemap);
|
||||
newp = valueConcat_patternUOrStruct(patp, newp, memp_nested, nodep);
|
||||
}
|
||||
@ -3885,7 +3916,7 @@ private:
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstPatMember* Defaultpatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp,
|
||||
AstPatMember* defaultPatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp,
|
||||
AstPatMember* patp,
|
||||
AstNodeUOrStructDType* memp_vdtypep,
|
||||
AstPatMember* defaultp, const DTypeMap& dtypemap) {
|
||||
|
@ -1,9 +1,12 @@
|
||||
// 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, 2009-2023 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module x;
|
||||
typedef struct {
|
||||
int a, b;
|
||||
@ -15,14 +18,31 @@ module x;
|
||||
embedded_t tab [3:0];
|
||||
} notembedded_t;
|
||||
|
||||
typedef struct {
|
||||
logic [15:0] m_i;
|
||||
string m_s;
|
||||
} istr_t;
|
||||
|
||||
notembedded_t p;
|
||||
embedded_t t [1:0];
|
||||
istr_t istr;
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
t[1].a = 2;
|
||||
p.b.a = 1;
|
||||
if (t[1].a != 2) $stop;
|
||||
if (p.b.a != 1) $stop;
|
||||
|
||||
istr.m_i = 12;
|
||||
istr.m_s = "str1";
|
||||
s = $sformatf("%p", istr);
|
||||
`checks(s, "'{m_i:'hc, m_s:\"str1\"}");
|
||||
|
||||
istr = '{m_i: '1, m_s: "str2"};
|
||||
s = $sformatf("%p", istr);
|
||||
`checks(s, "'{m_i:'hffff, m_s:\"str2\"}");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user