diff --git a/Changes b/Changes index d56469b13..e7ddcc712 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,7 @@ Verilator 4.211 devel * Parameter values are now emitted as 'static constexpr' instead of enum. C++ direct references to parameters might require updating (#3077). [Geza Lore] * Refactored Verilated include files; include verilated.h not verilated_heavy.h. +* Add error when constant function under a generate (#3103). [Don Owen] * Fix -G to treat simple integer literals as signed (#3060). [Anikin1610] * Fix emitted string array initializers (#2895). [Iztok Jeras] * Fix bitop tree optimization dropping necessary & operator (#3096). [Flavien Solt] diff --git a/src/V3Ast.h b/src/V3Ast.h index 47b580c50..907f716f3 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2682,6 +2682,7 @@ private: bool m_isHideProtected : 1; // Verilog protected bool m_pure : 1; // DPI import pure (vs. virtual pure) bool m_pureVirtual : 1; // Pure virtual + bool m_underGenerate : 1; // Under generate (for warning) bool m_virtual : 1; // Virtual method in class VLifetime m_lifetime; // Lifetime protected: @@ -2704,6 +2705,7 @@ protected: , m_isHideProtected{false} , m_pure{false} , m_pureVirtual{false} + , m_underGenerate{false} , m_virtual{false} { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export @@ -2770,6 +2772,8 @@ public: bool pure() const { return m_pure; } void pureVirtual(bool flag) { m_pureVirtual = flag; } bool pureVirtual() const { return m_pureVirtual; } + void underGenerate(bool flag) { m_underGenerate = flag; } + bool underGenerate() const { return m_underGenerate; } void isVirtual(bool flag) { m_virtual = flag; } bool isVirtual() const { return m_virtual; } void lifetime(const VLifetime& flag) { m_lifetime = flag; } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 6c0b2c02a..70067cd79 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -52,6 +52,7 @@ private: AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion int m_senitemCvtNum = 0; // Temporary signal counter + bool m_underGenerate = false; // Under GenFor/GenIf // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -111,6 +112,7 @@ private: virtual void visit(AstNodeFTask* nodep) override { // NodeTask: Remember its name for later resolution + if (m_underGenerate) nodep->underGenerate(true); // Remember the existing symbol table scope if (m_classp) { if (nodep->name() == "pre_randomize" || nodep->name() == "post_randomize") { @@ -520,6 +522,17 @@ private: // virtual void visit(AstModport* nodep) override { ... } // We keep Modport's themselves around for XML dump purposes + virtual void visit(AstGenFor* nodep) override { + VL_RESTORER(m_underGenerate); + m_underGenerate = true; + iterateChildren(nodep); + } + virtual void visit(AstGenIf* nodep) override { + VL_RESTORER(m_underGenerate); + m_underGenerate = true; + iterateChildren(nodep); + } + virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 0ded54fe8..96967643a 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -484,8 +484,16 @@ private: return; } if (nodep->dpiImport()) { + if (m_params) { + nodep->v3error("Constant function may not be DPI import (IEEE 1800-2017 13.4.3)"); + } clearOptimizable(nodep, "DPI import functions aren't simulatable"); } + if (nodep->underGenerate()) { + nodep->v3error( + "Constant function may not be declared under generate (IEEE 1800-2017 13.4.3)"); + clearOptimizable(nodep, "Constant function called under generate"); + } checkNodeInfo(nodep); iterateChildren(nodep); } diff --git a/test_regress/t/t_lint_const_func_dpi_bad.out b/test_regress/t/t_lint_const_func_dpi_bad.out new file mode 100644 index 000000000..6ac7d0ab6 --- /dev/null +++ b/test_regress/t/t_lint_const_func_dpi_bad.out @@ -0,0 +1,11 @@ +%Error: t/t_lint_const_func_dpi_bad.v:8:32: Constant function may not be DPI import (IEEE 1800-2017 13.4.3) + : ... In instance t + 8 | import "DPI-C" function int dpiFunc(); + | ^~~~~~~ +%Error: t/t_lint_const_func_dpi_bad.v:9:23: Expecting expression to be constant, but can't determine constant for FUNCREF 'dpiFunc' + : ... In instance t + t/t_lint_const_func_dpi_bad.v:8:32: ... Location of non-constant FUNC 'dpiFunc': DPI import functions aren't simulatable + t/t_lint_const_func_dpi_bad.v:9:23: ... Called from dpiFunc() with parameters: + 9 | localparam PARAM = dpiFunc(); + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_const_func_dpi_bad.pl b/test_regress/t/t_lint_const_func_dpi_bad.pl new file mode 100755 index 000000000..b5861b2ab --- /dev/null +++ b/test_regress/t/t_lint_const_func_dpi_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_const_func_dpi_bad.v b/test_regress/t/t_lint_const_func_dpi_bad.v new file mode 100644 index 000000000..84632841b --- /dev/null +++ b/test_regress/t/t_lint_const_func_dpi_bad.v @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Donald Owen. +// SPDX-License-Identifier: CC0-1.0 + +module t (); + import "DPI-C" function int dpiFunc(); + localparam PARAM = dpiFunc(); +endmodule diff --git a/test_regress/t/t_lint_const_func_gen_bad.out b/test_regress/t/t_lint_const_func_gen_bad.out new file mode 100644 index 000000000..61bd870a8 --- /dev/null +++ b/test_regress/t/t_lint_const_func_gen_bad.out @@ -0,0 +1,11 @@ +%Error: t/t_lint_const_func_gen_bad.v:11:30: Constant function may not be declared under generate (IEEE 1800-2017 13.4.3) + : ... In instance t + 11 | function automatic bit constFunc(); + | ^~~~~~~~~ +%Error: t/t_lint_const_func_gen_bad.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'constFunc' + : ... In instance t + t/t_lint_const_func_gen_bad.v:11:30: ... Location of non-constant FUNC 'constFunc': Constant function called under generate + t/t_lint_const_func_gen_bad.v:15:26: ... Called from constFunc() with parameters: + 15 | localparam PARAM = constFunc(); + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_const_func_gen_bad.pl b/test_regress/t/t_lint_const_func_gen_bad.pl new file mode 100755 index 000000000..b5861b2ab --- /dev/null +++ b/test_regress/t/t_lint_const_func_gen_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_const_func_gen_bad.v b/test_regress/t/t_lint_const_func_gen_bad.v new file mode 100644 index 000000000..d2ac25a4d --- /dev/null +++ b/test_regress/t/t_lint_const_func_gen_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Donald Owen. +// SPDX-License-Identifier: CC0-1.0 + +module t (); + if (1) begin: GenConstFunc + // IEEE 1800-2017 13.4.3, constant functions shall not be declared inside a + //generate block + function automatic bit constFunc(); + constFunc = 1'b1; + endfunction + + localparam PARAM = constFunc(); + end +endmodule