forked from github/verilator
Support static methods and typedefs in classes (#2615)
This commit is contained in:
parent
1c2384cb3d
commit
7c4259bc0a
@ -36,6 +36,7 @@ Julien Margetts
|
||||
Kaleb Barrett
|
||||
Kanad Kanhere
|
||||
Kevin Kiningham
|
||||
Krzysztof Bieganski
|
||||
Kuba Ober
|
||||
Ludwig Rogiers
|
||||
Lukasz Dalek
|
||||
|
@ -35,6 +35,8 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
string m_prefix; // String prefix to add to name based on hier
|
||||
AstScope* m_classScopep = nullptr; // Package moving scopes into
|
||||
AstScope* m_packageScopep = nullptr; // Class package scope
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current task
|
||||
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
|
||||
MoveVector m_moves;
|
||||
|
||||
@ -76,12 +78,14 @@ private:
|
||||
packagep->addStmtp(scopep);
|
||||
// Iterate
|
||||
VL_RESTORER(m_prefix);
|
||||
VL_RESTORER(m_classScopep);
|
||||
VL_RESTORER(m_packageScopep);
|
||||
{
|
||||
m_classScopep = classScopep;
|
||||
m_packageScopep = scopep;
|
||||
m_prefix = nodep->name() + "__02e"; // .
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_classScopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstPackage* nodep) override {
|
||||
VL_RESTORER(m_prefix);
|
||||
@ -94,11 +98,28 @@ private:
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
// TODO move class statics only
|
||||
// if (m_classScopep) {
|
||||
// m_moves.push_back(make_pair(nodep, m_classScopep));
|
||||
//}
|
||||
// TODO move class statics too
|
||||
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
|
||||
m_moves.push_back(make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVarScope* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->varp()->user1p(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_ftaskp);
|
||||
{
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lifetime().isStatic()) {
|
||||
m_moves.push_back(make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Don't move now, or wouldn't keep interating the class
|
||||
@ -116,8 +137,13 @@ public:
|
||||
// CONSTRUCTORS
|
||||
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ClassVisitor() override {
|
||||
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
|
||||
it->second->addVarp(it->first->unlinkFrBack());
|
||||
for (auto moved : m_moves) {
|
||||
if (VN_IS(moved.first, NodeFTask)) {
|
||||
moved.second->addActivep(moved.first->unlinkFrBack());
|
||||
} else if (VN_IS(moved.first, Var)) {
|
||||
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
|
||||
moved.second->addVarp(scopep->unlinkFrBack());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1004,7 +1004,12 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
}
|
||||
// Create symbol table for the task's vars
|
||||
string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name();
|
||||
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_packagep);
|
||||
auto pkgp = m_packagep;
|
||||
// Set the class as package for static class methods
|
||||
if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) {
|
||||
pkgp = VN_CAST(m_curSymp->nodep(), Class);
|
||||
}
|
||||
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp);
|
||||
m_curSymp->fallbackp(oldCurSymp);
|
||||
// Convert the func's range to the output variable
|
||||
// This should probably be done in the Parser instead, as then we could
|
||||
@ -2114,12 +2119,7 @@ private:
|
||||
"Bad package link");
|
||||
AstClassOrPackageRef* cpackagerefp
|
||||
= VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
||||
packagep = cpackagerefp->packagep();
|
||||
if (!packagep && cpackagerefp->classOrPackagep()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Class '::' references: "
|
||||
<< AstNode::prettyNameQ(cpackagerefp->name()));
|
||||
}
|
||||
packagep = cpackagerefp->classOrPackagep();
|
||||
UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(packagep);
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
@ -2485,9 +2485,8 @@ private:
|
||||
if (cpackagerefp->paramsp()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
|
||||
}
|
||||
UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(),
|
||||
m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep());
|
||||
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
nodep->packagep(cpackagerefp->classOrPackagep());
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
m_ds.m_dotp = nullptr;
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
||||
@ -2694,9 +2693,6 @@ private:
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
UINFO(5, " " << nodep << endl);
|
||||
checkNoDot(nodep);
|
||||
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method");
|
||||
}
|
||||
if (nodep->isExternDef()) {
|
||||
if (!m_curSymp->findIdFallback("extern " + nodep->name())) {
|
||||
nodep->v3error("extern not found that declares " + nodep->prettyNameQ());
|
||||
@ -2802,7 +2798,7 @@ private:
|
||||
if (cpackagerefp->packagep()) {
|
||||
nodep->packagep(cpackagerefp->packagep());
|
||||
} else {
|
||||
cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference");
|
||||
nodep->packagep(cpackagerefp->classOrPackagep());
|
||||
// if (cpackagerefp->paramsp()) {
|
||||
// nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
|
||||
// }
|
||||
|
@ -181,7 +181,7 @@ private:
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
if (nodep->lifetime().isNone()) {
|
||||
if (nodep->isFuncLocal() && nodep->isIO()) {
|
||||
if (m_ftaskp) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
} else {
|
||||
nodep->lifetime(m_lifetime);
|
||||
|
@ -2845,9 +2845,24 @@ private:
|
||||
for (AstClass* classp = first_classp; classp;) {
|
||||
if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
|
||||
userIterate(ftaskp, nullptr);
|
||||
nodep->taskp(ftaskp);
|
||||
nodep->dtypeFrom(ftaskp);
|
||||
if (VN_IS(ftaskp, Task)) nodep->makeStatement();
|
||||
if (ftaskp->lifetime().isStatic()) {
|
||||
AstNode* argsp = nullptr;
|
||||
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
||||
AstNodeFTaskRef* newp = nullptr;
|
||||
if (VN_IS(ftaskp, Task)) {
|
||||
newp = new AstTaskRef(nodep->fileline(), ftaskp->name(), argsp);
|
||||
} else {
|
||||
newp = new AstFuncRef(nodep->fileline(), ftaskp->name(), argsp);
|
||||
}
|
||||
newp->taskp(ftaskp);
|
||||
newp->packagep(classp);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
nodep->taskp(ftaskp);
|
||||
nodep->dtypeFrom(ftaskp);
|
||||
if (VN_IS(ftaskp, Task)) nodep->makeStatement();
|
||||
}
|
||||
return;
|
||||
}
|
||||
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
|
||||
|
@ -1,7 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_class2.v:35:16: Unsupported: Class '::' references: 'Cls'
|
||||
35 | if (Cls::ENUM_VAL != 22) $stop;
|
||||
| ^~~~~~~~
|
||||
%Error: Internal Error: t/t_class2.v:35:11: ../V3LinkDot.cpp:#: Bad package link
|
||||
35 | if (Cls::ENUM_VAL != 22) $stop;
|
||||
| ^~~
|
||||
... See the manual and https://verilator.org for more assistance.
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -18,11 +18,14 @@ endclass : Cls
|
||||
Cls c;
|
||||
Cls d;
|
||||
|
||||
Cls::enum_t e;
|
||||
|
||||
initial begin
|
||||
// Alternate between two versions to make sure we don't
|
||||
// constant propagate between them.
|
||||
c = new;
|
||||
d = new;
|
||||
e = Cls::ENUM_VAL;
|
||||
c.imembera = 10;
|
||||
d.imembera = 11;
|
||||
c.imemberb = 20;
|
||||
@ -34,6 +37,8 @@ endclass : Cls
|
||||
if (Pkg::ENUMP_VAL != 33) $stop;
|
||||
if (Cls::ENUM_VAL != 22) $stop;
|
||||
if (c.ENUM_VAL != 22) $stop;
|
||||
if (e != Cls::ENUM_VAL) $stop;
|
||||
if (e != 22) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
@ -1,5 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_class_name.v:12:16: Unsupported: 'static' class method
|
||||
: ... In instance t
|
||||
12 | static task static_name;
|
||||
| ^~~~~~~~~~~
|
||||
%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},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
21
test_regress/t/t_class_static_method.pl
Executable file
21
test_regress/t/t_class_static_method.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
34
test_regress/t/t_class_static_method.v
Normal file
34
test_regress/t/t_class_static_method.v
Normal file
@ -0,0 +1,34 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Cls;
|
||||
|
||||
static task static_task(int x);
|
||||
$write("Called static task: %d\n", x);
|
||||
if (x != 16) $stop;
|
||||
endtask
|
||||
|
||||
static function int static_function(int x);
|
||||
$write("Called static function: %d\n", x);
|
||||
if (x != 23) $stop;
|
||||
return 42;
|
||||
endfunction
|
||||
|
||||
endclass : Cls
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
initial begin
|
||||
int x;
|
||||
Cls::static_task(16);
|
||||
x = Cls::static_function(23);
|
||||
$write("Static function result: %d\n", x);
|
||||
if (x != 42) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
@ -1,13 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_class_typedef.v:12:4: Unsupported: Class '::' reference
|
||||
12 | uvm_resource_types::rsrc_q_t rtab [string];
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_class_typedef.v:12:24: Can't find typedef: 'rsrc_q_t'
|
||||
12 | uvm_resource_types::rsrc_q_t rtab [string];
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_class_typedef.v:14:4: Unsupported: Class '::' reference
|
||||
14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string];
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_class_typedef.v:14:32: Can't find typedef: 'rsrc_q_t'
|
||||
14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string];
|
||||
| ^~~~~~~~
|
||||
%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},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
21
test_regress/t/t_module_class_static_method.pl
Normal file
21
test_regress/t/t_module_class_static_method.pl
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
24
test_regress/t/t_module_class_static_method.v
Normal file
24
test_regress/t/t_module_class_static_method.v
Normal file
@ -0,0 +1,24 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
class Cls;
|
||||
|
||||
static function int static_task();
|
||||
return 42;
|
||||
endfunction
|
||||
|
||||
endclass : Cls
|
||||
|
||||
initial begin
|
||||
if (Cls::static_task() != 42) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
@ -2,10 +2,6 @@
|
||||
: ... In instance t
|
||||
20 | static int st = 2; st++; return st;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_var_static.v:27:11: Unsupported: 'static' function/task variables
|
||||
: ... In instance t
|
||||
27 | int st = 2; st++; return st;
|
||||
| ^~
|
||||
%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;
|
||||
|
Loading…
Reference in New Issue
Block a user