diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 766eaabbd..1a8956a43 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -62,6 +62,7 @@ class LinkParseVisitor final : public VNVisitor { int m_beginDepth = 0; // How many begin blocks above current node within current AstNodeModule VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime bool m_insideLoop = false; // True if the node is inside a loop + bool m_lifetimeAllowed = false; // True to allow lifetime settings VDouble0 m_statModules; // Number of modules seen // METHODS @@ -185,6 +186,8 @@ class LinkParseVisitor final : public VNVisitor { VL_RESTORER(m_ftaskp); VL_RESTORER(m_lifetime); m_ftaskp = nodep; + VL_RESTORER(m_lifetimeAllowed); + m_lifetimeAllowed = true; if (!nodep->lifetime().isNone()) { m_lifetime = nodep->lifetime(); } else { @@ -290,7 +293,13 @@ class LinkParseVisitor final : public VNVisitor { "loop converted to automatic"); } if (nodep->varType() != VVarType::PORT) { - if (nodep->lifetime().isNone()) nodep->lifetime(m_lifetime); + if (nodep->lifetime().isNone()) { + if (m_lifetimeAllowed) { + nodep->lifetime(m_lifetime); + } else { // Module's always static per IEEE 1800-2023 6.21 + nodep->lifetime(VLifetime::STATIC); + } + } } else if (m_ftaskp) { nodep->lifetime(VLifetime::AUTOMATIC); } else if (nodep->lifetime() @@ -612,6 +621,7 @@ class LinkParseVisitor final : public VNVisitor { VL_RESTORER(m_genblkNum); VL_RESTORER(m_beginDepth); VL_RESTORER(m_lifetime); + VL_RESTORER(m_lifetimeAllowed); { // Module: Create sim table for entire module and iterate cleanFileline(nodep); @@ -624,6 +634,7 @@ class LinkParseVisitor final : public VNVisitor { m_beginDepth = 0; m_valueModp = nodep; m_lifetime = nodep->lifetime(); + m_lifetimeAllowed = VN_IS(nodep, Class); if (m_lifetime.isNone()) { m_lifetime = VN_IS(nodep, Class) ? VLifetime::AUTOMATIC : VLifetime::STATIC; } @@ -643,10 +654,16 @@ class LinkParseVisitor final : public VNVisitor { m_valueModp = nullptr; iterateChildren(nodep); } - void visit(AstNodeProcedure* nodep) override { visitIterateNoValueMod(nodep); } + void visit(AstNodeProcedure* nodep) override { + VL_RESTORER(m_lifetimeAllowed); + m_lifetimeAllowed = true; + visitIterateNoValueMod(nodep); + } void visit(AstAlways* nodep) override { VL_RESTORER(m_inAlways); m_inAlways = true; + VL_RESTORER(m_lifetimeAllowed); + m_lifetimeAllowed = true; visitIterateNoValueMod(nodep); } void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); } diff --git a/test_regress/t/t_mod_automatic.py b/test_regress/t/t_mod_automatic.py new file mode 100755 index 000000000..d4f986441 --- /dev/null +++ b/test_regress/t/t_mod_automatic.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. 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-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_mod_automatic.v b/test_regress/t/t_mod_automatic.v new file mode 100644 index 000000000..c3ffb868a --- /dev/null +++ b/test_regress/t/t_mod_automatic.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module automatic t(/*AUTOARG*/); + + task static accum_s(input integer value, output integer result); + static int acc = 1; + acc = acc + value; + result = acc; + endtask + + task accum_a(input integer value, output integer result); + int acc = 1; // automatic + acc = acc + value; + result = acc; + endtask + + integer value; + + reg failed = 0; // Static + + initial begin + accum_s(2, value); + $display("%d", value); + if (value !== 3) failed = 1; + + accum_s(3, value); + $display("%d", value); + if (value !== 6) failed = 1; + + accum_a(2, value); + $display("%d", value); + if (value !== 3) failed = 1; + + accum_a(3, value); + $display("%d", value); + if (value !== 4) failed = 1; + + if (failed) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule