diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 6fb3bc8c5..fb763aa9e 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -198,6 +198,16 @@ class PremitVisitor final : public VNVisitor { void visit(AstNodeAssign* nodep) override { START_STATEMENT_OR_RETURN(nodep); + if (AstCvtArrayToPacked* const packedp = VN_CAST(nodep->lhsp(), CvtArrayToPacked)) { + // AstCvtArrayToPacked is converted to VL_PACK, which returns rvalue, + // so it shouldn't be on the LHS. It is now replaced with unpacking of RHS. + AstNodeExpr* const exprLhsp = packedp->fromp()->unlinkFrBack(); + packedp->replaceWith(exprLhsp); + VL_DO_DANGLING(pushDeletep(packedp), packedp); + AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); + nodep->rhsp(new AstCvtPackedToArray{rhsp->fileline(), rhsp, exprLhsp->dtypep()}); + nodep->dtypeFrom(exprLhsp); + } // Direct assignment to a simple variable if (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())) { AstNode* const rhsp = nodep->rhsp(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 46f8e43d8..eb1873b26 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -223,6 +223,7 @@ class WidthVisitor final : public VNVisitor { const AstNodeExpr* m_randomizeFromp = nullptr; // Current randomize method call fromp const bool m_paramsOnly; // Computing parameter value; limit operation const bool m_doGenerate; // Do errors later inside generate statement + bool m_streamConcat = false; // True if visiting arguments of stream concatenation int m_dtTables = 0; // Number of created data type tables TableMap m_tableMap; // Created tables so can remove duplicates std::map @@ -238,6 +239,18 @@ class WidthVisitor final : public VNVisitor { EXTEND_OFF // No extension }; + static void packIfUnpacked(AstNodeExpr* const nodep) { + if (AstUnpackArrayDType* const unpackDTypep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) { + const int elementsNum = unpackDTypep->arrayUnpackedElements(); + const int unpackMinBits = elementsNum * unpackDTypep->subDTypep()->widthMin(); + const int unpackBits = elementsNum * unpackDTypep->subDTypep()->width(); + VNRelinker relinker; + nodep->unlinkFrBack(&relinker); + relinker.relink(new AstCvtArrayToPacked{ + nodep->fileline(), nodep, + nodep->findLogicDType(unpackBits, unpackMinBits, VSigning::UNSIGNED)}); + } + } // VISITORS // Naming: width_O{outputtype}_L{lhstype}_R{rhstype}_W{widthing}_S{signing} // Where type: @@ -612,6 +625,11 @@ class WidthVisitor final : public VNVisitor { } else { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); + + if (m_streamConcat) { + packIfUnpacked(nodep->lhsp()); + packIfUnpacked(nodep->rhsp()); + } nodep->dtypeSetLogicUnsized(nodep->lhsp()->width() + nodep->rhsp()->width(), nodep->lhsp()->widthMin() + nodep->rhsp()->widthMin(), VSigning::UNSIGNED); @@ -877,8 +895,11 @@ class WidthVisitor final : public VNVisitor { } } void visit(AstNodeStream* nodep) override { + VL_RESTORER(m_streamConcat); if (m_vup->prelim()) { + m_streamConcat = true; iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); + m_streamConcat = false; iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change if (const AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) { diff --git a/test_regress/t/t_stream_unpack.v b/test_regress/t/t_stream_unpack.v index 0e20d4db2..0e3a7bde9 100644 --- a/test_regress/t/t_stream_unpack.v +++ b/test_regress/t/t_stream_unpack.v @@ -21,6 +21,12 @@ module t (/*AUTOARG*/); bit [5:0] bit6 = 6'b111000; bit [5:0] ans; enum_t ans_enum; + logic [1:0] a [3] = {1, 0, 3}; + logic [1:0] b [3] = {1, 2, 0}; + logic c [4] = {1, 1, 0, 0}; + logic [15:0] d; + logic [3:0] e [2]; + logic f [8]; { >> bit {arr}} = bit6; `checkp(arr, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); @@ -76,6 +82,20 @@ module t (/*AUTOARG*/); ans_enum = enum_t'({ << bit[5:0] {arr6} }); `checkh(ans_enum, bit6); + d = { >> {a, b, c}}; + `checkh(d, 16'b0100110110001100); + + { >> {e, f}} = d; + `checkp(e, "'{'h4, 'hd} "); + `checkp(f, "'{'h1, 'h0, 'h0, 'h0, 'h1, 'h1, 'h0, 'h0} "); + + d = { << 4 {a, b, c}}; + `checkh(d, 16'b1100100011010100); + + { << 2 {e, f}} = d; + `checkp(e, "'{'h1, 'h7} "); + `checkp(f, "'{'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h1, 'h1} "); + $write("*-* All Finished *-*\n"); $finish; end