diff --git a/Changes b/Changes index 02029ac36..551cba559 100644 --- a/Changes +++ b/Changes @@ -43,6 +43,7 @@ Verilator 5.039 devel * Support disabling a fork from within that fork (#6314). [Ryszard Rozak, Antmicro Ltd.] * Support future sampled value functions. * Support simple disable within task (#6334). [Ryszard Rozak, Antmicro Ltd.] +* Support recursive constant functions. * Change control file `public_flat_*` and other signal attributes to support __ in names (#6140). * Change runtime to exit() instead of abort(), unless under +verilated+debug. * Change `$display("%p")` to remove space after `}`. diff --git a/src/V3Simulate.h b/src/V3Simulate.h index e3b1d0545..789905885 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -74,6 +74,10 @@ class SimulateVisitor VL_NOT_FINAL : public VNVisitorConst { // is missing, we will not apply the optimization, rather then bomb. private: + // CONSTANTS + static constexpr int CONST_FUNC_RECURSION_MAX = 1000; + static constexpr int CALL_STACK_MAX = 100; + // NODE STATE // Cleared on each always/assignw const VNUser1InUse m_inuser1; @@ -136,12 +140,13 @@ private: bool m_isCoverage; // Has coverage int m_instrCount; ///< Number of nodes int m_dataCount; ///< Bytes of data + int m_recurseCount = 0; // Now deep in current recursion AstJumpGo* m_jumpp = nullptr; ///< Jump label we're branching from // Simulating: // Allocators for constants of various data types std::unordered_map m_constps; size_t m_constGeneration = 0; - std::vector m_callStack; ///< Call stack for verbose error messages + std::vector m_callStack; // Call stack for verbose error messages // Cleanup // V3Numbers that represents strings are a bit special and the API for @@ -217,6 +222,7 @@ public: } // LCOV_EXCL_STOP m_whyNotOptimizable = why; std::ostringstream stack; + int n = 0; for (const auto& callstack : vlstd::reverse_view(m_callStack)) { const AstFuncRef* const funcp = callstack->m_funcp; stack << "\n " << funcp->fileline() << "... Called from '" @@ -232,6 +238,10 @@ public: << prettyNumber(&valp->num(), dtypep); } } + if (++n > CALL_STACK_MAX) { + stack << "\n ... stack truncated"; + break; + } } m_whyNotOptimizable += stack.str(); } @@ -444,6 +454,18 @@ private: return ""; } + void initVar(AstVar* nodep) { + if (const AstBasicDType* const basicp = nodep->dtypeSkipRefp()->basicp()) { + AstConst cnst{nodep->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), 0}; + if (basicp->isZeroInit()) { + cnst.num().setAllBits0(); + } else { + cnst.num().setAllBitsX(); + } + newValue(nodep, &cnst); + } + } + // VISITORS void visit(AstAlways* nodep) override { if (jumpingOver()) return; @@ -906,6 +928,8 @@ private: iterateAndNextConstNull(nodep->rhsp()); // Value to assign handleAssignRecurse(nodep, nodep->lhsp(), nodep->rhsp()); + // UINFO(9, "set " << fetchConst(nodep->rhsp())->num().ascii() << " for assign " + // << nodep->lhsp()->name()); } void visit(AstArraySel* nodep) override { checkNodeInfo(nodep); @@ -1143,17 +1167,49 @@ private: VL_DANGLING(funcp); // Make sure we've sized the function funcp = nodep->taskp(); UASSERT_OBJ(funcp, nodep, "Not linked"); + if (funcp->recursive()) { - // Because we attach values to nodes rather then making a stack, this is a mess - // When we do support this, we need a stack depth limit of 1K or something, - // and the t_func_recurse_param_bad.v test should check that limit's error message - clearOptimizable(funcp, "Unsupported: Recursive constant functions"); - return; + if (m_recurseCount >= CONST_FUNC_RECURSION_MAX) { + clearOptimizable(funcp, "Constant function recursed more than "s + + std::to_string(CONST_FUNC_RECURSION_MAX) + " times"); + return; + } + ++m_recurseCount; + } + + // Values from previous call, so can save to stack + // The "stack" is this visit function's local stack, as this visit is itself recursing + std::map oldValues; + + if (funcp->recursive() && !m_checkOnly) { + // Save local automatics + funcp->foreach([this, &oldValues](AstVar* varp) { + if (varp->lifetime().isAutomatic()) { // This also does function's I/O + if (AstNodeExpr* const valuep = fetchValueNull(varp)) { + AstNodeExpr* const nvaluep = newTrackedClone(valuep); + oldValues.emplace(varp, nvaluep); + } + } + }); + // Save every expression value, as might be in middle of expression + // that calls recursively back to this same function. + // This is much heavier-weight then likely is needed, in theory + // we could look at the visit stack to determine what nodes + // need save-restore, but that is difficult to get right, and + // recursion is rare. + funcp->foreach([this, &oldValues](AstNodeExpr* exprp) { + if (VN_IS(exprp, Const)) return; // Speed up as won't change + if (AstNodeExpr* const valuep = fetchValueNull(exprp)) { + AstNodeExpr* const nvaluep = newTrackedClone(valuep); + oldValues.emplace(exprp, nvaluep); + } + }); } // Apply function call values to function V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); // Must do this in two steps, eval all params, then apply them // Otherwise chained functions may have the wrong results + std::vector> portValues; for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* const portp = it->first; AstNode* const pinp = it->second->exprp(); @@ -1166,37 +1222,45 @@ private: } // Evaluate pin value iterateConst(pinp); + // Clone in case are recursing + portValues.push_back(std::make_pair(portp, newTrackedClone(fetchValue(pinp)))); } } - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* const portp = it->first; - AstNode* const pinp = it->second->exprp(); - if (pinp) { // Else too few arguments in function call - ignore it - // Apply value to the function - if (!m_checkOnly && optimizable()) newValue(portp, fetchValue(pinp)); + // Apply value to the function + if (!m_checkOnly && optimizable()) + for (auto& it : portValues) { + if (!m_checkOnly && optimizable()) newValue(it.first, it.second); } - } SimStackNode stackNode{nodep, &tconnects}; // cppcheck-suppress danglingLifetime m_callStack.push_back(&stackNode); - // Clear output variable - if (const auto* const basicp = VN_CAST(funcp->fvarp(), Var)->basicp()) { - AstConst cnst{funcp->fvarp()->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), - 0}; - if (basicp->isZeroInit()) { - cnst.num().setAllBits0(); - } else { - cnst.num().setAllBitsX(); - } - newValue(funcp->fvarp(), &cnst); + if (!m_checkOnly) { + // Clear output variable + initVar(VN_CAST(funcp->fvarp(), Var)); + // Clear other automatic variables + funcp->foreach([this, &oldValues](AstVar* varp) { + if (varp->lifetime().isAutomatic() && !varp->isIO()) initVar(varp); + }); } + // Evaluate the function iterateConst(funcp); m_callStack.pop_back(); + AstNodeExpr* returnp = nullptr; if (!m_checkOnly && optimizable()) { - // Grab return value from output variable (if it's a function) + // Grab return value from output variable UASSERT_OBJ(funcp->fvarp(), nodep, "Function reference points at non-function"); - newValue(nodep, fetchValue(funcp->fvarp())); + returnp = newTrackedClone(fetchValue(funcp->fvarp())); + UINFO(5, "func " << nodep->name() << " return = " << returnp); + } + // Restore local automatics (none unless recursed) + for (const auto& it : oldValues) { + if (it.second) newValue(it.first, it.second); + } + if (returnp) newValue(nodep, returnp); + if (funcp->recursive()) { + UASSERT_OBJ(m_recurseCount > 0, nodep, "recurse underflow"); + --m_recurseCount; } } diff --git a/test_regress/t/t_func_recurse_param.out b/test_regress/t/t_func_recurse_param.out deleted file mode 100644 index a7cc20861..000000000 --- a/test_regress/t/t_func_recurse_param.out +++ /dev/null @@ -1,12 +0,0 @@ -%Error: t/t_func_recurse_param.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' - : ... note: In instance 't' - t/t_func_recurse_param.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions - 15 | localparam int ZERO = recurse_self(0); - | ^~~~~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_func_recurse_param.v:16:28: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' - : ... note: In instance 't' - t/t_func_recurse_param.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions - 16 | localparam int ELEVEN = recurse_self(3); - | ^~~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_func_recurse_param.py b/test_regress/t/t_func_recurse_param.py index 966dc53da..d4f986441 100755 --- a/test_regress/t/t_func_recurse_param.py +++ b/test_regress/t/t_func_recurse_param.py @@ -11,9 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) +test.compile() -if not test.vlt_all: - test.execute() +test.execute() test.passes() diff --git a/test_regress/t/t_func_recurse_param.v b/test_regress/t/t_func_recurse_param.v index 0082b0f20..cf82c3993 100644 --- a/test_regress/t/t_func_recurse_param.v +++ b/test_regress/t/t_func_recurse_param.v @@ -4,22 +4,41 @@ // any use, without warranty, 2003 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + module t; - function automatic int recurse_self; - input int i; - if (i == 0) recurse_self = 0; - else recurse_self = i + recurse_self(i - 1) * 2; - endfunction + function automatic int recurse_self; + input int i; + int r1; + int r2; + // Simulator support for statics in constant functions get varying results, not testing + static int local_static = 10; + automatic int local_automatic; // check each function call resets to zero + if (i == 0) begin + local_static = 0; + recurse_self = 0; + end + else begin + local_static = local_static + 1; + local_automatic = local_automatic + 10; + recurse_self = i + recurse_self(i - 1) * 2 + recurse_self(i - 1) * 3 + local_automatic; + end + endfunction - localparam int ZERO = recurse_self(0); - localparam int ELEVEN = recurse_self(3); + localparam int F0 = recurse_self(0); + localparam int F3 = recurse_self(3); + localparam int F4 = recurse_self(4); - initial begin - if (ZERO != 0) $stop; - if (ELEVEN != 11) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end + initial begin + `checkd(F0, 0); + `checkd(F3, 348); + `checkd(F4, 1754); + $write("*-* All Finished *-*\n"); + $finish; + end endmodule diff --git a/test_regress/t/t_func_recurse_param_bad.out b/test_regress/t/t_func_recurse_param_bad.out index b32ab1b11..77e217bd6 100644 --- a/test_regress/t/t_func_recurse_param_bad.out +++ b/test_regress/t/t_func_recurse_param_bad.out @@ -1,7 +1,210 @@ -%Error: t/t_func_recurse_param_bad.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' +%Error: t/t_func_recurse_param_bad.v:15:25: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' : ... note: In instance 't' - t/t_func_recurse_param_bad.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions - 15 | localparam int HUGE = recurse_self(10000); - | ^~~~~~~~~~~~ + t/t_func_recurse_param_bad.v:9:26: ... Location of non-constant FUNC 'recurse_self': Constant function recursed more than 1000 times + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + t/t_func_recurse_param_bad.v:12:29: ... Called from 'recurse_self()' with parameters: + i = 32'h2329 + ... stack truncated + 15 | localparam int HUGE = recurse_self(10000); + | ^~~~~~~~~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to diff --git a/test_regress/t/t_func_recurse_param_bad.v b/test_regress/t/t_func_recurse_param_bad.v index eb7ff29b2..f3e88f9ba 100644 --- a/test_regress/t/t_func_recurse_param_bad.v +++ b/test_regress/t/t_func_recurse_param_bad.v @@ -6,18 +6,18 @@ module t; - function automatic int recurse_self; - input int i; - if (i == 0) recurse_self = 0; - else recurse_self = i + recurse_self(i - 1) * 2; - endfunction + function automatic int recurse_self; + input int i; + if (i == 0) recurse_self = 0; + else recurse_self = i + recurse_self(i - 1) * 2; + endfunction - localparam int HUGE = recurse_self(10000); // too much recursion + localparam int HUGE = recurse_self(10000); // too much recursion - initial begin - $display(HUGE); - $write("*-* All Finished *-*\n"); - $finish; - end + initial begin + $display(HUGE); + $write("*-* All Finished *-*\n"); + $finish; + end endmodule