diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 4ecb8d429..a853690fe 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2353,6 +2353,9 @@ class LinkDotResolveVisitor final : public VNVisitor { std::map m_usedPins; // Pin used in this cell, map to duplicate std::map m_modulesToRevisit; // Modules to revisit a second time AstNode* m_lastDeferredp = nullptr; // Last node which requested a revisit of its module + bool m_maybePackedArray + = false; // Array select parse trees may actually be packed array datatypes + AstNodeDType* m_packedArrayDtp = nullptr; // Datatype reference for packed array struct DotStates final { DotPosition m_dotPos; // Scope part of dotted resolution @@ -3401,8 +3404,12 @@ class LinkDotResolveVisitor final : public VNVisitor { if (ok) { AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()}; refp->typedefp(defp); - replaceWithCheckBreak(nodep, refp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); + if (m_maybePackedArray) { + m_packedArrayDtp = refp; + } else { + replaceWithCheckBreak(nodep, refp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } } } else if (AstParamTypeDType* const defp = VN_CAST(foundp->nodep(), ParamTypeDType)) { ok = (m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE); @@ -4048,22 +4055,48 @@ class LinkDotResolveVisitor final : public VNVisitor { m_ds.m_dotErr = true; return; } - iterateAndNextNull(nodep->fromp()); - symIterateNull(nodep->rhsp(), m_curSymp); - symIterateNull(nodep->thsp(), m_curSymp); + AstNodeDType* packedArrayDtp = nullptr; // Datatype reference for packed array + { + VL_RESTORER(m_packedArrayDtp); + { + VL_RESTORER(m_maybePackedArray); + m_maybePackedArray = true; + iterateAndNextNull(nodep->fromp()); + } + symIterateNull(nodep->rhsp(), m_curSymp); + symIterateNull(nodep->thsp(), m_curSymp); - if (nodep->attrp()) { - AstNode* const attrp = nodep->attrp()->unlinkFrBack(); - VL_DO_DANGLING(attrp->deleteTree(), attrp); - } - AstNode* const basefromp = AstArraySel::baseFromp(nodep, false); - if (VN_IS(basefromp, Replicate)) { - // From {...}[...] syntax in IEEE 2017 - if (basefromp) UINFO(9, indent() << " Related node: " << basefromp); - } else { - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, - basefromp->cloneTree(false)}); + if (m_packedArrayDtp) { + AstRange* const newRangep + = new AstRange(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), + nodep->thsp()->unlinkFrBack()); + AstPackArrayDType* newArrayTypep + = new AstPackArrayDType(nodep->fileline(), m_packedArrayDtp, newRangep); + newArrayTypep->childDTypep(m_packedArrayDtp); + newArrayTypep->refDTypep(nullptr); + if (m_maybePackedArray) { + packedArrayDtp = newArrayTypep; + } else { + replaceWithCheckBreak(nodep, newArrayTypep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + } else { + if (nodep->attrp()) { + AstNode* const attrp = nodep->attrp()->unlinkFrBack(); + VL_DO_DANGLING(attrp->deleteTree(), attrp); + } + AstNode* const basefromp = AstArraySel::baseFromp(nodep, false); + if (VN_IS(basefromp, Replicate)) { + // From {...}[...] syntax in IEEE 2017 + if (basefromp) UINFO(9, indent() << " Related node: " << basefromp); + } else { + nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, + basefromp->cloneTree(false)}); + } + } } + + if (packedArrayDtp) { m_packedArrayDtp = packedArrayDtp; } } void visit(AstMemberSel* nodep) override { // checkNoDot not appropriate, can be under a dot diff --git a/test_regress/t/t_type_param.v b/test_regress/t/t_type_param.v index 891f7da2a..1bb4f7f9f 100644 --- a/test_regress/t/t_type_param.v +++ b/test_regress/t/t_type_param.v @@ -40,6 +40,20 @@ module t(); foo #(.bar (logic [ $bits(qux3) - 1 : 0])) foo_inst3 (.bar_size (bar_size3)); + typedef struct packed { + logic foo; + logic bar; + } some_struct_t; + int bar_size4; + + foo #(.bar (some_struct_t [7:0])) + foo_inst4 (.bar_size (bar_size4)); + + int bar_size5; + + foo #(.bar (some_struct_t [2:0] [5:0])) + foo_inst5 (.bar_size (bar_size5)); + localparam bar_bits = 13; int bar_size_wrapper; @@ -82,6 +96,16 @@ module t(); bar_size3, $bits(qux3)); $stop(); end + if (bar_size4 != $bits(some_struct_t)*8) begin + $display("%m: bar_size4 != bits of some_struct_t * 8 (%0d, %0d)", + bar_size4, $bits(some_struct_t) * 8); + $stop(); + end + if (bar_size5 != $bits(some_struct_t)*3*6) begin + $display("%m: bar_size5 != bits of some_struct_t * 3 * 6 (%0d, %0d)", + bar_size5, $bits(some_struct_t) * 3 * 6); + $stop(); + end if (bar_size_wrapper != bar_bits) begin $display("%m: bar_size_wrapper != bar_bits (%0d, %0d)", bar_size_wrapper, bar_bits);