From 62ffe43a82c667c4acc67954c3c653cf552d9e24 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 30 Mar 2026 19:06:02 -0400 Subject: [PATCH] Fix port assignment to large arrays (#6904). Fixes #6904. --- Changes | 1 + src/V3EmitCBase.cpp | 4 +++- src/V3EmitCFunc.h | 14 +++++++++----- test_regress/t/t_var_pins_array_assign.py | 18 ++++++++++++++++++ test_regress/t/t_var_pins_array_assign.v | 15 +++++++++++++++ 5 files changed, 46 insertions(+), 6 deletions(-) create mode 100755 test_regress/t/t_var_pins_array_assign.py create mode 100644 test_regress/t/t_var_pins_array_assign.v diff --git a/Changes b/Changes index 73b88b1f9..939ed5694 100644 --- a/Changes +++ b/Changes @@ -74,6 +74,7 @@ Verilator 5.047 devel * Fix super constructor calls with local variables (#6214) (#6933). [Igor Zaworski, Antmicro Ltd.] * Fix `local::` false error in randomize() with on parameterized class (#6680) (#7293). [Yilou Wang] * Fix false recursive definition error (#6769) (#7118). [Alex Zhou] +* Fix port assignment to large arrays (#6904). * Fix interface localparam dependencies and arbitrary nesting (#6936) (#7128) (#7188) (#7190). [em2machine] * Fix errant integer promotion (#7012). [Todd Strader] * Fix randc solver hang with wide variables (#7068) (#7248). [Yilou Wang] diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 64d4b4cdd..71e92bc16 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -207,7 +207,9 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { if (asRef && refNeedParens) puts(")"); emitDeclArrayBrackets(nodep); puts(";\n"); - } else if (nodep->isPrimaryIO() && basicp && !basicp->isOpaque()) { + } else if (nodep->isPrimaryIO() && basicp && !basicp->isOpaque() + && !nodep->dtypep()->skipRefp()->isCompound() + && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) { if (nodep->isInout()) { putns(nodep, "VL_INOUT"); } else if (nodep->isWritable()) { diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 3f77aaef2..ec06cb0ba 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -511,6 +511,8 @@ public: bool decind = false; bool rhs = true; bool reverseUnpack = false; // Set for descending CvtPackedToArray + const AstUnpackArrayDType* const unpackDtp + = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) { UASSERT_OBJ(selp->widthMin() == selp->widthConst(), selp, "Width mismatch"); if (selp->widthMin() == 1) { @@ -580,10 +582,7 @@ public: rhs = false; iterateAndNextConstNull(castp->fromp()); // Descending unpacked dest: reverse after unpack - if (const AstUnpackArrayDType* const unpackDtp - = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType)) { - if (!unpackDtp->declRange().ascending()) reverseUnpack = true; - } + if (unpackDtp && !unpackDtp->declRange().ascending()) reverseUnpack = true; } else if (const AstCvtArrayToArray* const castp = VN_CAST(nodep->rhsp(), CvtArrayToArray)) { if (castp->reverse()) { @@ -608,6 +607,7 @@ public: // and means using '=' and bypasses using emitConstantW. // Whuch we don't want to do as slows compiler down. && !VN_IS(nodep->rhsp(), VarRef) // + && !VN_IS(nodep->rhsp(), InitArray) // && !VN_IS(nodep->rhsp(), AssocSel) // && !VN_IS(nodep->rhsp(), MemberSel) // && !VN_IS(nodep->rhsp(), StructSel) // @@ -616,7 +616,7 @@ public: // Wide functions assign into the array directly, don't need separate assign statement m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); paren = false; - } else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) + } else if (nodep->isWide() && !unpackDtp && !VN_IS(nodep->rhsp(), Const)) { putnbs(nodep, "VL_ASSIGN_W("); puts(cvtToStr(nodep->widthMin()) + ", "); @@ -630,6 +630,10 @@ public: decind = true; if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak(); putns(nodep, "= "); + if (unpackDtp && VN_IS(nodep->rhsp(), InitArray)) { + // Emit "VlUnpacked{{...InitArray...}}" + puts(unpackDtp->cType("", false, false, false)); + } } if (rhs) iterateAndNextConstNull(nodep->rhsp()); if (paren) puts(")"); diff --git a/test_regress/t/t_var_pins_array_assign.py b/test_regress/t/t_var_pins_array_assign.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_var_pins_array_assign.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_var_pins_array_assign.v b/test_regress/t/t_var_pins_array_assign.v new file mode 100644 index 000000000..69772fe30 --- /dev/null +++ b/test_regress/t/t_var_pins_array_assign.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +module t ( + output logic [64:0] output_vec[257] +); + + assign output_vec = '{default: 1}; + + initial $finish; + +endmodule