diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index bf5ba0ae6..bbaa9c1ec 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -574,6 +574,7 @@ public: || m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64 || m_e == TIME); } + bool isBit() const { return m_e == BIT; } bool isBitLogic() const { // Bit/logic vector types; can form a packed array return (m_e == LOGIC || m_e == BIT); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 928402b2b..608ab7e1b 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -459,6 +459,7 @@ public: return m.m_keyword; } bool isBitLogic() const { return keyword().isBitLogic(); } + bool isBit() const { return keyword().isBit(); } bool isCHandle() const VL_MT_STABLE { return keyword().isCHandle(); } bool isDouble() const VL_MT_STABLE { return keyword().isDouble(); } bool isEvent() const VL_MT_STABLE { return keyword() == VBasicDTypeKwd::EVENT; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index eef1c05e5..29ee46408 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1778,6 +1778,15 @@ public: addAttrsp(attrsp); dtypep(nullptr); // V3Width will resolve } + AstTypedef(FileLine* fl, const string& name, AstNodeDType* dtp, bool underClass) + : ASTGEN_SUPER_Typedef(fl) + , m_name{name} + , m_declTokenNum{fl->tokenNum()} + , m_isHideLocal{false} + , m_isHideProtected{false} + , m_isUnderClass{underClass} { + dtypep(dtp); + } ASTGEN_MEMBERS_AstTypedef; void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; diff --git a/src/V3Force.cpp b/src/V3Force.cpp index edbd0fb20..4772d3d14 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -241,6 +241,7 @@ public: private: // NODE STATE + // AstNodeDType::user1p -> AstNodeDType*, dtype created for __En variables // AstVar::user1p -> ForceComponentsVar* instance (via m_forceComponentsVar) // AstVarScope::user1p -> ForceComponentsVarScope* instance (via m_forceComponentsVarScope) // AstVarRef::user2 -> Flag indicating not to replace reference @@ -264,7 +265,7 @@ private: if (const AstUnpackArrayDType* const udtp = VN_CAST(dtp, UnpackArrayDType)) { const size_t elemsInSubDType = checkIfDTypeSupportedRecurse(udtp->subDTypep(), varp); return udtp->elementsConst() * elemsInSubDType; - } else if (const AstNodeUOrStructDType* const sdtp = VN_CAST(dtp, NodeUOrStructDType)) { + } else if (const AstStructDType* const sdtp = VN_CAST(dtp, StructDType)) { size_t elemCount = 0; for (const AstMemberDType* mdtp = sdtp->membersp(); mdtp; mdtp = VN_AS(mdtp->nextp(), MemberDType)) { @@ -287,26 +288,117 @@ private: return 1; } } - static AstNodeDType* getEnVarpDTypep(const AstVar* const varp) { + static AstNodeDType* getEnVarpDTypep(AstVar* const varp) { AstNodeDType* const origDTypep = varp->dtypep()->skipRefp(); + if (origDTypep->user1p()) return VN_AS(origDTypep->user1p(), NodeDType); const size_t unpackElemNum = checkIfDTypeSupportedRecurse(origDTypep, varp); if (unpackElemNum > ELEMENTS_MAX) { varp->v3warn(E_UNSUPPORTED, "Unsupported: Force of variable with " ">= " << ELEMENTS_MAX << " unpacked elements"); - } - if (VN_IS(origDTypep, UnpackArrayDType)) { - return origDTypep; - } else if (VN_IS(origDTypep, BasicDType)) { - return isRangedDType(varp) ? origDTypep : varp->findBitDType(); - } else if (VN_IS(origDTypep, PackArrayDType)) { - return origDTypep; - } else if (VN_IS(origDTypep, NodeUOrStructDType)) { - return origDTypep; - } else { - varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type"); return origDTypep; } + return getEnVarpDTypeRecursep(varp, origDTypep); + } + static AstNodeDType* getEnVarpDTypeRecursep(AstVar* const varp, AstNodeDType* const dtypep) { + if (dtypep->user1p()) return VN_AS(dtypep->user1p(), NodeDType); + if (AstNodeArrayDType* const arrp = VN_CAST(dtypep, NodeArrayDType)) { + AstNodeDType* const subDTypep = arrp->subDTypep()->skipRefp(); + AstNodeDType* const enSubDTypep = getEnVarpDTypeRecursep(varp, subDTypep); + if (subDTypep != enSubDTypep) { + AstNodeArrayDType* enArrp; + if (VN_IS(arrp, UnpackArrayDType)) { + enArrp = new AstUnpackArrayDType{arrp->fileline(), enSubDTypep, + arrp->rangep()->cloneTree(false)}; + } else if (VN_IS(arrp, PackArrayDType)) { + enArrp = new AstPackArrayDType{arrp->fileline(), enSubDTypep, + arrp->rangep()->cloneTree(false)}; + } else { + varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type"); + return dtypep; + } + dtypep->user1p(enArrp); + v3Global.rootp()->typeTablep()->addTypesp(enArrp); + return enArrp; + } else { + dtypep->user1p(dtypep); + return dtypep; + } + } else if (AstBasicDType* const basicp = VN_CAST(dtypep, BasicDType)) { + if (basicp->isBit()) { + dtypep->user1p(dtypep); + return dtypep; + } else { + AstNodeDType* const bitDtp = varp->findBitRangeDType( + basicp->declRange(), basicp->elements(), VSigning::UNSIGNED); + dtypep->user1p(bitDtp); + return bitDtp; + } + } else if (AstNodeUOrStructDType* const structp = VN_CAST(dtypep, NodeUOrStructDType)) { + std::vector enMemberDTypes; + bool changed = false; + for (AstMemberDType* mdtp = structp->membersp(); mdtp; + mdtp = VN_AS(mdtp->nextp(), MemberDType)) { + AstNodeDType* const subMdtp = mdtp->subDTypep()->skipRefp(); + AstNodeDType* const enSubMdtp = getEnVarpDTypeRecursep(varp, subMdtp); + if (subMdtp != enSubMdtp) { + changed = true; + AstMemberDType* const enMdtp + = new AstMemberDType{mdtp->fileline(), mdtp->name(), enSubMdtp}; + enMdtp->dtypep(enSubMdtp); + enMemberDTypes.push_back(enMdtp); + } else { + enMemberDTypes.push_back(mdtp->cloneTreePure(false)); + } + } + if (changed) { + const bool packed = structp->packed(); + AstNodeUOrStructDType* enStructp; + if (VN_IS(structp, StructDType)) { + enStructp = new AstStructDType{structp->fileline(), + packed ? VSigning::SIGNED : VSigning::NOSIGN}; + } else if (VN_IS(structp, UnionDType) && packed) { + const AstUnionDType* const unionp = VN_AS(structp, UnionDType); + enStructp = new AstUnionDType{unionp->fileline(), unionp->isSoft(), + unionp->isTagged(), VSigning::SIGNED}; + } else { + varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type"); + return dtypep; + } + int width = 0; + if (packed) { + for (const auto& memberp : enMemberDTypes) { + enStructp->addMembersp(memberp); + const int memberWidth = memberp->width(); + if (VN_IS(structp, StructDType)) { + width += memberWidth; + } else { + width = std::max(width, memberWidth); + } + } + } else { + for (const auto& memberp : enMemberDTypes) enStructp->addMembersp(memberp); + width = 1; + } + v3Global.rootp()->typeTablep()->addTypesp(enStructp); + enStructp->name(structp->name() + "__VforceEn_t"); + enStructp->dtypep(enStructp); + enStructp->widthForce(width, width); + enStructp->classOrPackagep(structp->classOrPackagep()); + dtypep->user1p(enStructp); + AstTypedef* const typedefp + = new AstTypedef{enStructp->fileline(), enStructp->name(), enStructp, + VN_IS(enStructp->classOrPackagep(), Class)}; + varp->addNextHere(typedefp); + return enStructp; + } else { + for (const auto& memberp : enMemberDTypes) memberp->deleteTree(); + dtypep->user1p(dtypep); + return dtypep; + } + } + varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type"); + return dtypep; } public: diff --git a/test_regress/t/t_force_unpacked.v b/test_regress/t/t_force_unpacked.v index 8335035e5..193c02e63 100644 --- a/test_regress/t/t_force_unpacked.v +++ b/test_regress/t/t_force_unpacked.v @@ -25,6 +25,7 @@ module t ( int int_arr[-1:2][1][3]; bit [5:0] bit_arr[5]; union_t union_arr[4]; + real real_arr[2][1][3]; assign bit_arr[2][3] = 1; @@ -35,18 +36,21 @@ module t ( logic_arr[0][2][-4] <= 1; int_arr[0][0][2] <= 1; union_arr[1].x <= 1; + real_arr[0][0][1] <= 1; end else if (cyc == 1) begin `checkh(logic_arr[0][2][-4], 1); `checkh(int_arr[0][0][2], 1); `checkh(bit_arr[2][3], 1); `checkh(union_arr[1].x, 1); + `checkr(real_arr[0][0][1], 1); end else if (cyc == 2) begin force logic_arr[0][2][-4] = 0; force int_arr[0][0][2] = 0; force bit_arr[2][3] = 0; force union_arr[1].y = 2; + force real_arr[0][0][1] = 0; end else if (cyc == 3) begin `checkh(logic_arr[0][2][-4], 0); @@ -56,11 +60,14 @@ module t ( `checkh(bit_arr[2][3], 0); `checkh(union_arr[1].x, 2); union_arr[1].x <= 3; + `checkr(real_arr[0][0][1], 0); + real_arr[0][0][1] <= 2; end else if (cyc == 4) begin `checkh(logic_arr[0][2][-4], 0); `checkh(int_arr[0][0][2], 0); `checkh(union_arr[1].y, 2); + `checkr(real_arr[0][0][1], 0); end else if (cyc == 5) begin release logic_arr[0][2][-4]; @@ -68,6 +75,7 @@ module t ( release bit_arr[2][3]; `checkh(bit_arr[2][3], 1); release union_arr[1].x; + release real_arr[0][0][1]; end else if (cyc == 6) begin `checkh(logic_arr[0][2][-4], 0); @@ -77,11 +85,14 @@ module t ( `checkh(bit_arr[2][3], 1); `checkh(union_arr[1].x, 2); union_arr[1].y <= 4; + `checkr(real_arr[0][0][1], 0); + real_arr[0][0][1] <= 3; end else if (cyc == 7) begin `checkh(logic_arr[0][2][-4], 1); `checkh(int_arr[0][0][2], 1); `checkh(union_arr[1].x, 4); + `checkr(real_arr[0][0][1], 3); end else if (cyc == 8) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_force_unpacked_struct.v b/test_regress/t/t_force_unpacked_struct.v index 5aa2b28be..8c1aae3da 100644 --- a/test_regress/t/t_force_unpacked_struct.v +++ b/test_regress/t/t_force_unpacked_struct.v @@ -16,10 +16,16 @@ module t ( integer cyc = 0; + typedef struct packed { + bit a; + bit b; + } packed_t; + typedef struct { int x; logic y; int arr[5]; + packed_t pt; } struct_t; struct_t s_array[3]; @@ -32,16 +38,19 @@ module t ( s_array[1].x = 1; s_array[1].arr[2] = 1; my_struct.x <= 1; + my_struct.pt.b <= 1; end else if (cyc == 1) begin `checkh(s_array[1].x, 1); `checkh(s_array[1].arr[2], 1); `checkh(my_struct.x, 1); + `checkh(my_struct.pt.b, 1); end else if (cyc == 2) begin force s_array[1].x = 0; force s_array[1].arr[2] = 2; force my_struct.x = 0; + force my_struct.pt.b = 0; end else if (cyc == 3) begin `checkh(s_array[1].x, 0); @@ -50,16 +59,20 @@ module t ( s_array[1].arr[2] = 3; `checkh(my_struct.x, 0); my_struct.x <= 1; + `checkh(my_struct.pt.b, 0); + my_struct.pt.b <= 1; end else if (cyc == 4) begin `checkh(s_array[1].x, 0); `checkh(s_array[1].arr[2], 2); `checkh(my_struct.x, 0); + `checkh(my_struct.pt.b, 0); end else if (cyc == 5) begin release s_array[1].x; release s_array[1].arr[2]; release my_struct.x; + release my_struct.pt.b; end else if (cyc == 6) begin `checkh(s_array[1].x, 0); @@ -68,11 +81,14 @@ module t ( s_array[1].arr[2] = 4; `checkh(my_struct.x, 0); my_struct.x <= 1; + `checkh(my_struct.pt.b, 0); + my_struct.pt.b <= 1; end else if (cyc == 7) begin `checkh(s_array[1].x, 1); `checkh(s_array[1].arr[2], 4); `checkh(my_struct.x, 1); + `checkh(my_struct.pt.b, 1); end else if (cyc == 8) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_force_unpacked_unsup.out b/test_regress/t/t_force_unpacked_unsup.out index 89b68ef55..3d07924aa 100644 --- a/test_regress/t/t_force_unpacked_unsup.out +++ b/test_regress/t/t_force_unpacked_unsup.out @@ -1,8 +1,14 @@ -%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:22:7: Unsupported: Force of variable with >= 1000 unpacked elements - 22 | bit big_array[40][40][40]; +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:26:7: Unsupported: Force of variable with >= 1000 unpacked elements + 26 | bit big_array[40][40][40]; | ^~~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:21:12: Unsupported: Force of variable with >= 1000 unpacked elements - 21 | struct_t s_array[3000]; +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:25:12: Unsupported: Force of variable with >= 1000 unpacked elements + 25 | struct_t s_array[3000]; | ^~~~~~~ -%Error: Exiting due to +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:27:11: Forcing variable of unsupported type: REFDTYPE 'union_t' + 27 | union_t my_union; + | ^~~~~~~~ +%Error: Internal Error: t/t_force_unpacked_unsup.v:27:11: ../V3Force.cpp:#: Unsupported: Force of variable of unhandled data type + 27 | union_t my_union; + | ^~~~~~~~ + ... This fatal error may be caused by the earlier error(s); resolve those first. diff --git a/test_regress/t/t_force_unpacked_unsup.v b/test_regress/t/t_force_unpacked_unsup.v index 27562ed45..225f2cb2d 100644 --- a/test_regress/t/t_force_unpacked_unsup.v +++ b/test_regress/t/t_force_unpacked_unsup.v @@ -17,59 +17,63 @@ module t ( integer cyc = 0; typedef struct {int x;} struct_t; + typedef union { + int x; + logic y; + } union_t; struct_t s_array[3000]; bit big_array[40][40][40]; - real r_array[2]; + union_t my_union; // Test loop always @(posedge clk) begin cyc <= cyc + 1; if (cyc == 0) begin - r_array[0] <= 1; big_array[1][2][3] <= 1; s_array[1].x <= 1; + my_union.x <= 1; end else if (cyc == 1) begin - `checkr(r_array[0], 1); `checkr(big_array[1][2][3], 1); `checkh(s_array[1].x, 1); + `checkh(my_union.x, 1); end else if (cyc == 2) begin - force r_array[0] = 0; force big_array[1][2][3] = 0; force s_array[1].x = 0; + force my_union.x = 0; end else if (cyc == 3) begin - `checkr(r_array[0], 0); `checkr(big_array[1][2][3], 0); - r_array[0] <= 1; big_array[1][2][3] <= 1; `checkh(s_array[1].x, 0); s_array[1].x <= 1; + `checkh(my_union.x, 0); + my_union.x <= 1; end else if (cyc == 4) begin - `checkr(r_array[0], 0); `checkr(big_array[1][2][3], 0); `checkh(s_array[1].x, 0); + `checkh(my_union.x, 0); end else if (cyc == 5) begin - release r_array[0]; release big_array[1][2][3]; release s_array[1].x; + release my_union.x; end else if (cyc == 6) begin - `checkr(r_array[0], 0); `checkr(big_array[1][2][3], 0); - r_array[0] <= 1; big_array[1][2][3] <= 1; `checkh(s_array[1].x, 0); s_array[1].x <= 1; + `checkh(my_union.x, 0); + my_union.x <= 1; end else if (cyc == 7) begin - `checkr(r_array[0], 1); `checkr(big_array[1][2][3], 1); `checkh(s_array[1].x, 1); + `checkh(my_union.x, 1); end else if (cyc == 8) begin $write("*-* All Finished *-*\n");