Support recursive constant functions.
This commit is contained in:
parent
712ff95a48
commit
b6ecffeb60
1
Changes
1
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 `}`.
|
||||
|
|
|
|||
114
src/V3Simulate.h
114
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<const AstNodeDType*, ConstAllocator> m_constps;
|
||||
size_t m_constGeneration = 0;
|
||||
std::vector<SimStackNode*> m_callStack; ///< Call stack for verbose error messages
|
||||
std::vector<SimStackNode*> 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<AstNode*, AstNodeExpr*> 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<std::pair<AstVar*, AstNodeExpr*>> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue