forked from github/verilator
Support static function variables (#3830)
This commit is contained in:
parent
8a85cedaf5
commit
b56e7f6910
@ -19,6 +19,7 @@
|
||||
// Look for BEGINs
|
||||
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||
// FOR -> WHILEs
|
||||
// Move static function variables and their AstInitialStatic blocks before a function
|
||||
//
|
||||
// There are two scopes; named BEGINs change %m and variable scopes.
|
||||
// Unnamed BEGINs change only variable, not $display("%m") scope.
|
||||
@ -64,13 +65,14 @@ private:
|
||||
// STATE
|
||||
BeginState* const m_statep; // Current global state
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
|
||||
string m_displayScope; // Name of %m in $display/AstScopeName
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth = 0; // Current if depth
|
||||
bool m_keepBegins = false; // True if begins should not be inlined
|
||||
std::set<AstVar*> m_staticFuncVars; // Static variables from m_ftaskp
|
||||
|
||||
// METHODS
|
||||
|
||||
@ -121,6 +123,25 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void renameAndStaticsRecurse(AstNode* const nodep) {
|
||||
// Rename references and move InitialStatic items
|
||||
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
|
||||
const auto it = m_staticFuncVars.find(varrefp->varp());
|
||||
if (it != m_staticFuncVars.end()) varrefp->name((*it)->name());
|
||||
}
|
||||
|
||||
if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p());
|
||||
if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p());
|
||||
if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p());
|
||||
if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p());
|
||||
if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp());
|
||||
|
||||
if (VN_IS(nodep, InitialStatic)) {
|
||||
nodep->unlinkFrBack();
|
||||
m_ftaskp->addHereThisAsNext(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstFork* nodep) override {
|
||||
// Keep this begin to group its statements together
|
||||
@ -165,6 +186,7 @@ private:
|
||||
m_ftaskp = nodep;
|
||||
m_liftedp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
renameAndStaticsRecurse(nodep);
|
||||
if (m_liftedp) {
|
||||
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
|
||||
if (AstNode* const stmtsp = nodep->stmtsp()) {
|
||||
@ -174,6 +196,7 @@ private:
|
||||
nodep->addStmtsp(m_liftedp);
|
||||
m_liftedp = nullptr;
|
||||
}
|
||||
m_staticFuncVars.clear();
|
||||
m_ftaskp = nullptr;
|
||||
}
|
||||
}
|
||||
@ -210,7 +233,15 @@ private:
|
||||
}
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
if (m_unnamedScope != "") {
|
||||
// If static variable, move it outside a function.
|
||||
if (nodep->lifetime().isStatic() && m_ftaskp) {
|
||||
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
|
||||
nodep->name(newName);
|
||||
nodep->unlinkFrBack();
|
||||
m_ftaskp->addHereThisAsNext(nodep);
|
||||
m_staticFuncVars.insert(nodep);
|
||||
nodep->funcLocal(false);
|
||||
} else if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||
m_statep->userMarkChanged(nodep);
|
||||
|
@ -1176,9 +1176,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
// Var: Remember its name for later resolution
|
||||
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables");
|
||||
}
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
// Find under either a task or the module's vars
|
||||
const VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
||||
|
@ -148,8 +148,8 @@ private:
|
||||
if (classPkgRefp && VN_IS(classPkgRefp->classOrPackageNodep(), Class)) {
|
||||
// Class methods are automatic by default
|
||||
m_lifetime = VLifetime::AUTOMATIC;
|
||||
} else if (nodep->dpiImport()) {
|
||||
// DPI-imported function don't have lifetime specifiers
|
||||
} else if (nodep->dpiImport() || VN_IS(nodep, Property)) {
|
||||
// DPI-imported functions and properties don't have lifetime specifiers
|
||||
m_lifetime = VLifetime::NONE;
|
||||
}
|
||||
if (m_lifetime.isStatic() && hasStaticDeclAssignments(nodep)) {
|
||||
@ -222,12 +222,8 @@ private:
|
||||
|
||||
void visit(AstVar* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
if (nodep->lifetime().isNone()) {
|
||||
if (m_ftaskp) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
} else {
|
||||
nodep->lifetime(m_lifetime);
|
||||
}
|
||||
if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) {
|
||||
nodep->lifetime(m_lifetime);
|
||||
}
|
||||
if (nodep->isParam() && !nodep->valuep()
|
||||
&& nodep->fileline()->language() < V3LangCode::L1800_2009) {
|
||||
|
@ -503,6 +503,15 @@ private:
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstInitialStatic* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
UINFO(5, " IF " << nodep << endl);
|
||||
|
@ -3788,12 +3788,16 @@ for_initializationItem<nodep>: // IEEE: variable_assignment + for_varia
|
||||
// // IEEE: for_variable_declaration
|
||||
data_type idAny/*new*/ '=' expr
|
||||
{ VARRESET_NONLIST(VAR); VARDTYPE($1);
|
||||
$$ = VARDONEA($<fl>2, *$2, nullptr, nullptr);
|
||||
AstVar* const varp = VARDONEA($<fl>2, *$2, nullptr, nullptr);
|
||||
varp->lifetime(VLifetime::AUTOMATIC);
|
||||
$$ = varp;
|
||||
$$->addNext(new AstAssign{$3, new AstVarRef{$<fl>2, *$2, VAccess::WRITE}, $4}); }
|
||||
// // IEEE-2012:
|
||||
| yVAR data_type idAny/*new*/ '=' expr
|
||||
{ VARRESET_NONLIST(VAR); VARDTYPE($2);
|
||||
$$ = VARDONEA($<fl>3, *$3, nullptr, nullptr);
|
||||
AstVar* const varp = VARDONEA($<fl>3, *$3, nullptr, nullptr);
|
||||
varp->lifetime(VLifetime::AUTOMATIC);
|
||||
$$ = varp;
|
||||
$$->addNext(new AstAssign{$4, new AstVarRef{$<fl>3, *$3, VAccess::WRITE}, $5}); }
|
||||
// // IEEE: variable_assignment
|
||||
// // UNSUP variable_lvalue below
|
||||
|
@ -2066,7 +2066,7 @@ module t_case_write1_tasks ();
|
||||
endcase
|
||||
end
|
||||
endtask
|
||||
task ozonef3;
|
||||
task automatic ozonef3;
|
||||
input [ 31:0] foo;
|
||||
inout [STRLEN*8: 1] foobar;
|
||||
reg nacho;
|
||||
@ -2475,7 +2475,7 @@ module t_case_write1_tasks ();
|
||||
endcase
|
||||
end
|
||||
endtask
|
||||
task dude;
|
||||
task automatic dude;
|
||||
inout [STRLEN*8: 1] foobar;
|
||||
reg [ 7:0] temp;
|
||||
integer i;
|
||||
@ -2497,7 +2497,7 @@ module t_case_write1_tasks ();
|
||||
end
|
||||
endtask
|
||||
|
||||
task big_case;
|
||||
task automatic big_case;
|
||||
input [ 31:0] fd;
|
||||
input [ 31:0] foo;
|
||||
reg [STRLEN*8: 1] foobar;
|
||||
|
@ -2067,7 +2067,7 @@ module t_case_write2_tasks ();
|
||||
endcase
|
||||
end
|
||||
endtask
|
||||
task ozonef3;
|
||||
task automatic ozonef3;
|
||||
input [ 31:0] foo;
|
||||
input [`FD_BITS] fd;
|
||||
reg nacho;
|
||||
@ -2482,7 +2482,7 @@ module t_case_write2_tasks ();
|
||||
$fwrite(fd," dude");
|
||||
endtask
|
||||
|
||||
task big_case;
|
||||
task automatic big_case;
|
||||
input [ `FD_BITS] fd;
|
||||
input [ 31:0] foo;
|
||||
// verilator no_inline_task
|
||||
|
@ -1,6 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_class_static.v:25:18: Unsupported: 'static' function/task variables
|
||||
: ... In instance t
|
||||
25 | static int st = 2; st++; return st;
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -76,7 +76,7 @@ module Test (/*AUTOARG*/
|
||||
input [31:0] inp;
|
||||
output [31:0] outp;
|
||||
|
||||
function [31:0] no_inline_function;
|
||||
function automatic [31:0] no_inline_function;
|
||||
input [31:0] var1;
|
||||
input [31:0] var2;
|
||||
/*verilator no_inline_task*/
|
||||
|
@ -39,7 +39,7 @@ endmodule : mod_inner
|
||||
|
||||
module mod_a_mon;
|
||||
bit y;
|
||||
function void accessor;
|
||||
function automatic void accessor;
|
||||
begin : accessor_block
|
||||
bit read_x = mod_a.u_inner.x;
|
||||
y = read_x;
|
||||
|
@ -18,12 +18,18 @@ module t;
|
||||
endfunction
|
||||
|
||||
parameter int SUMS[3:0] = calc_sums();
|
||||
parameter int SUMS1[3:0] = calc_sums();
|
||||
|
||||
initial begin
|
||||
if (SUMS[0] != 4) $stop;
|
||||
if (SUMS[1] != 4+3) $stop;
|
||||
if (SUMS[2] != 4+3+2) $stop;
|
||||
if (SUMS[3] != 4+3+2+1) $stop;
|
||||
// According to section 13.4.3 of IEEE Std 1800-2017,
|
||||
// execution at elaboration has no effect on the initial values
|
||||
// of the variables used either at simulation time or among
|
||||
// multiple invocations of a function at elaboration time
|
||||
if (SUMS1 != SUMS) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
module t;
|
||||
|
||||
task t;
|
||||
task automatic t;
|
||||
// verilator no_inline_task
|
||||
string trace;
|
||||
|
||||
|
@ -67,7 +67,7 @@ module t (/*AUTOARG*/
|
||||
$finish;
|
||||
end
|
||||
|
||||
task tsk;
|
||||
task automatic tsk;
|
||||
integer t1;
|
||||
$display("t1 {mod}.tsk %m");
|
||||
begin
|
||||
|
@ -1,14 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_var_static.v:20:18: Unsupported: 'static' function/task variables
|
||||
: ... In instance t
|
||||
20 | static int st = 2; st++; return st;
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%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;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_var_static.v:40:18: Unsupported: 'static' function/task variables
|
||||
: ... In instance t
|
||||
40 | static int st = 2; st++; return st;
|
||||
| ^~
|
||||
%Error: Exiting due to
|
@ -12,13 +12,11 @@ scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['-Wno-IMPLICITSTATIC'],
|
||||
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -6,6 +6,16 @@
|
||||
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||
|
||||
function automatic int f_au_st_global ();
|
||||
static int st = 0; st++; return st;
|
||||
endfunction
|
||||
|
||||
package my_pkg;
|
||||
function int f_no_st_pkg ();
|
||||
static int st = 0; st++; return st;
|
||||
endfunction
|
||||
endpackage
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
@ -67,6 +77,11 @@ module t (/*AUTOARG*/
|
||||
v = f_au_au(); `checkh(v, 3);
|
||||
v = f_au_au(); `checkh(v, 3);
|
||||
//
|
||||
v = f_au_st_global(); `checkh(v, 1);
|
||||
v = f_au_st_global(); `checkh(v, 2);
|
||||
v = my_pkg::f_no_st_pkg(); `checkh(v, 1);
|
||||
v = my_pkg::f_no_st_pkg(); `checkh(v, 2);
|
||||
//
|
||||
end
|
||||
|
||||
int cyc = 0;
|
||||
|
@ -1,6 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_var_static_param.v:33:18: Unsupported: 'static' function/task variables
|
||||
: ... In instance t.subb
|
||||
33 | static int st = 2; st += P; return st;
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user