diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index acca96c0d..4d7c136a9 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -36,6 +36,7 @@ Julien Margetts Kaleb Barrett Kanad Kanhere Kevin Kiningham +Krzysztof Bieganski Kuba Ober Ludwig Rogiers Lukasz Dalek diff --git a/src/V3Class.cpp b/src/V3Class.cpp index df895f107..ebde82354 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -35,6 +35,8 @@ private: AstUser1InUse m_inuser1; string m_prefix; // String prefix to add to name based on hier AstScope* m_classScopep = nullptr; // Package moving scopes into + AstScope* m_packageScopep = nullptr; // Class package scope + AstNodeFTask* m_ftaskp = nullptr; // Current task typedef std::vector> MoveVector; MoveVector m_moves; @@ -76,12 +78,14 @@ private: packagep->addStmtp(scopep); // Iterate VL_RESTORER(m_prefix); + VL_RESTORER(m_classScopep); + VL_RESTORER(m_packageScopep); { m_classScopep = classScopep; + m_packageScopep = scopep; m_prefix = nodep->name() + "__02e"; // . iterateChildren(nodep); } - m_classScopep = nullptr; } virtual void visit(AstPackage* nodep) override { VL_RESTORER(m_prefix); @@ -94,11 +98,28 @@ private: virtual void visit(AstVar* nodep) override { iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class - // TODO move class statics only - // if (m_classScopep) { - // m_moves.push_back(make_pair(nodep, m_classScopep)); - //} + // TODO move class statics too + if (m_ftaskp && m_ftaskp->lifetime().isStatic()) { + m_moves.push_back(make_pair(nodep, m_packageScopep)); + } } + + virtual void visit(AstVarScope* nodep) override { + iterateChildren(nodep); + nodep->varp()->user1p(nodep); + } + + virtual void visit(AstNodeFTask* nodep) override { + VL_RESTORER(m_ftaskp); + { + m_ftaskp = nodep; + iterateChildren(nodep); + if (nodep->lifetime().isStatic()) { + m_moves.push_back(make_pair(nodep, m_packageScopep)); + } + } + } + virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class @@ -116,8 +137,13 @@ public: // CONSTRUCTORS explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~ClassVisitor() override { - for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) { - it->second->addVarp(it->first->unlinkFrBack()); + for (auto moved : m_moves) { + if (VN_IS(moved.first, NodeFTask)) { + moved.second->addActivep(moved.first->unlinkFrBack()); + } else if (VN_IS(moved.first, Var)) { + AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope); + moved.second->addVarp(scopep->unlinkFrBack()); + } } } }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3ee315a8a..2356c30a5 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1004,7 +1004,12 @@ class LinkDotFindVisitor : public AstNVisitor { } // Create symbol table for the task's vars string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name(); - m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_packagep); + auto pkgp = m_packagep; + // Set the class as package for static class methods + if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) { + pkgp = VN_CAST(m_curSymp->nodep(), Class); + } + m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp); m_curSymp->fallbackp(oldCurSymp); // Convert the func's range to the output variable // This should probably be done in the Parser instead, as then we could @@ -2114,12 +2119,7 @@ private: "Bad package link"); AstClassOrPackageRef* cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); - packagep = cpackagerefp->packagep(); - if (!packagep && cpackagerefp->classOrPackagep()) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Class '::' references: " - << AstNode::prettyNameQ(cpackagerefp->name())); - } + packagep = cpackagerefp->classOrPackagep(); UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); m_ds.m_dotSymp = m_statep->getNodeSym(packagep); m_ds.m_dotPos = DP_SCOPE; @@ -2485,9 +2485,8 @@ private: if (cpackagerefp->paramsp()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); } - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), - m_ds.m_dotp->lhsp(), "Bad package link"); - nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); + UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); + nodep->packagep(cpackagerefp->classOrPackagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { @@ -2694,9 +2693,6 @@ private: virtual void visit(AstNodeFTask* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); - if (nodep->classMethod() && nodep->lifetime().isStatic()) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method"); - } if (nodep->isExternDef()) { if (!m_curSymp->findIdFallback("extern " + nodep->name())) { nodep->v3error("extern not found that declares " + nodep->prettyNameQ()); @@ -2802,7 +2798,7 @@ private: if (cpackagerefp->packagep()) { nodep->packagep(cpackagerefp->packagep()); } else { - cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference"); + nodep->packagep(cpackagerefp->classOrPackagep()); // if (cpackagerefp->paramsp()) { // nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); // } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index ebdc38cac..14cc8d494 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -181,7 +181,7 @@ private: virtual void visit(AstVar* nodep) override { cleanFileline(nodep); if (nodep->lifetime().isNone()) { - if (nodep->isFuncLocal() && nodep->isIO()) { + if (m_ftaskp) { nodep->lifetime(VLifetime::AUTOMATIC); } else { nodep->lifetime(m_lifetime); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a56889287..f4a49629d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2845,9 +2845,24 @@ private: for (AstClass* classp = first_classp; classp;) { if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { userIterate(ftaskp, nullptr); - nodep->taskp(ftaskp); - nodep->dtypeFrom(ftaskp); - if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + if (ftaskp->lifetime().isStatic()) { + AstNode* argsp = nullptr; + if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext(); + AstNodeFTaskRef* newp = nullptr; + if (VN_IS(ftaskp, Task)) { + newp = new AstTaskRef(nodep->fileline(), ftaskp->name(), argsp); + } else { + newp = new AstFuncRef(nodep->fileline(), ftaskp->name(), argsp); + } + newp->taskp(ftaskp); + newp->packagep(classp); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { + nodep->taskp(ftaskp); + nodep->dtypeFrom(ftaskp); + if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + } return; } classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr; diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out deleted file mode 100644 index 25f82f892..000000000 --- a/test_regress/t/t_class2.out +++ /dev/null @@ -1,7 +0,0 @@ -%Error-UNSUPPORTED: t/t_class2.v:35:16: Unsupported: Class '::' references: 'Cls' - 35 | if (Cls::ENUM_VAL != 22) $stop; - | ^~~~~~~~ -%Error: Internal Error: t/t_class2.v:35:11: ../V3LinkDot.cpp:#: Bad package link - 35 | if (Cls::ENUM_VAL != 22) $stop; - | ^~~ - ... See the manual and https://verilator.org for more assistance. diff --git a/test_regress/t/t_class2.pl b/test_regress/t/t_class2.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class2.pl +++ b/test_regress/t/t_class2.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_class2.v b/test_regress/t/t_class2.v index 774e95344..f78b1da05 100644 --- a/test_regress/t/t_class2.v +++ b/test_regress/t/t_class2.v @@ -18,11 +18,14 @@ endclass : Cls Cls c; Cls d; + Cls::enum_t e; + initial begin // Alternate between two versions to make sure we don't // constant propagate between them. c = new; d = new; + e = Cls::ENUM_VAL; c.imembera = 10; d.imembera = 11; c.imemberb = 20; @@ -34,6 +37,8 @@ endclass : Cls if (Pkg::ENUMP_VAL != 33) $stop; if (Cls::ENUM_VAL != 22) $stop; if (c.ENUM_VAL != 22) $stop; + if (e != Cls::ENUM_VAL) $stop; + if (e != 22) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_name.out b/test_regress/t/t_class_name.out deleted file mode 100644 index 8f5e19daa..000000000 --- a/test_regress/t/t_class_name.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_name.v:12:16: Unsupported: 'static' class method - : ... In instance t - 12 | static task static_name; - | ^~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_name.pl b/test_regress/t/t_class_name.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class_name.pl +++ b/test_regress/t/t_class_name.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_class_static_method.pl b/test_regress/t/t_class_static_method.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_static_method.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_method.v b/test_regress/t/t_class_static_method.v new file mode 100644 index 000000000..1d408aaef --- /dev/null +++ b/test_regress/t/t_class_static_method.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + + static task static_task(int x); + $write("Called static task: %d\n", x); + if (x != 16) $stop; + endtask + + static function int static_function(int x); + $write("Called static function: %d\n", x); + if (x != 23) $stop; + return 42; + endfunction + +endclass : Cls + +module t (/*AUTOARG*/); + + initial begin + int x; + Cls::static_task(16); + x = Cls::static_function(23); + $write("Static function result: %d\n", x); + if (x != 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_class_typedef.out b/test_regress/t/t_class_typedef.out deleted file mode 100644 index 4979a037a..000000000 --- a/test_regress/t/t_class_typedef.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_typedef.v:12:4: Unsupported: Class '::' reference - 12 | uvm_resource_types::rsrc_q_t rtab [string]; - | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_class_typedef.v:12:24: Can't find typedef: 'rsrc_q_t' - 12 | uvm_resource_types::rsrc_q_t rtab [string]; - | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_class_typedef.v:14:4: Unsupported: Class '::' reference - 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_class_typedef.v:14:32: Can't find typedef: 'rsrc_q_t' - 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_typedef.pl b/test_regress/t/t_class_typedef.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class_typedef.pl +++ b/test_regress/t/t_class_typedef.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_module_class_static_method.pl b/test_regress/t/t_module_class_static_method.pl new file mode 100644 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_module_class_static_method.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_module_class_static_method.v b/test_regress/t/t_module_class_static_method.v new file mode 100644 index 000000000..393c0e541 --- /dev/null +++ b/test_regress/t/t_module_class_static_method.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 +// + +module t (/*AUTOARG*/); + + class Cls; + + static function int static_task(); + return 42; + endfunction + + endclass : Cls + + initial begin + if (Cls::static_task() != 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_var_static.out b/test_regress/t/t_var_static.out index 982ff5970..f6d7a524e 100644 --- a/test_regress/t/t_var_static.out +++ b/test_regress/t/t_var_static.out @@ -2,10 +2,6 @@ : ... In instance t 20 | static int st = 2; st++; return st; | ^~ -%Error-UNSUPPORTED: t/t_var_static.v:27:11: Unsupported: 'static' function/task variables - : ... In instance t - 27 | int st = 2; st++; return st; - | ^~ %Error-UNSUPPORTED: t/t_var_static.v:30:18: Unsupported: 'static' function/task variables : ... In instance t 30 | static int st = 2; st++; return st;