Support recursive constant functions.

This commit is contained in:
Wilson Snyder 2025-08-30 07:45:35 -04:00
parent 712ff95a48
commit b6ecffeb60
7 changed files with 342 additions and 68 deletions

View File

@ -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 `}`.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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