Internals: Remove m_pkgp and m_classp from WidthVisitor (#4402)
This commit is contained in:
parent
9caa79a7ea
commit
4afa14b612
|
|
@ -201,7 +201,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
string m_name; // Name from upper typedef, if any
|
string m_name; // Name from upper typedef, if any
|
||||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
AstNodeModule* m_classOrPackagep = nullptr; // Package it will be emitted with
|
||||||
const int m_uniqueNum;
|
const int m_uniqueNum;
|
||||||
bool m_packed;
|
bool m_packed;
|
||||||
bool m_isFourstate = false; // V3Width computes
|
bool m_isFourstate = false; // V3Width computes
|
||||||
|
|
@ -1053,7 +1053,7 @@ private:
|
||||||
// Post-width typedefs are removed and point to type directly
|
// Post-width typedefs are removed and point to type directly
|
||||||
AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef
|
AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef
|
||||||
string m_name; // Name of an AstTypedef
|
string m_name; // Name of an AstTypedef
|
||||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
AstNodeModule* m_classOrPackagep = nullptr; // Class/package in which it was defined
|
||||||
public:
|
public:
|
||||||
AstRefDType(FileLine* fl, const string& name)
|
AstRefDType(FileLine* fl, const string& name)
|
||||||
: ASTGEN_SUPER_RefDType(fl)
|
: ASTGEN_SUPER_RefDType(fl)
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
|
||||||
// @astgen op3 := pinsp : List[AstNodeExpr]
|
// @astgen op3 := pinsp : List[AstNodeExpr]
|
||||||
// @astgen op4 := scopeNamep : Optional[AstScopeName]
|
// @astgen op4 := scopeNamep : Optional[AstScopeName]
|
||||||
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
|
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
|
||||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the task
|
||||||
string m_name; // Name of variable
|
string m_name; // Name of variable
|
||||||
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||||
|
|
@ -449,7 +449,7 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr {
|
||||||
VAccess m_access; // Left hand side assignment
|
VAccess m_access; // Left hand side assignment
|
||||||
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
||||||
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
|
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
|
||||||
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable
|
||||||
string m_selfPointer; // Output code object pointer (e.g.: 'this')
|
string m_selfPointer; // Output code object pointer (e.g.: 'this')
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -716,7 +716,7 @@ class AstClassOrPackageRef final : public AstNodeExpr {
|
||||||
private:
|
private:
|
||||||
string m_name;
|
string m_name;
|
||||||
// Node not NodeModule to appease some early parser usage
|
// Node not NodeModule to appease some early parser usage
|
||||||
AstNode* m_classOrPackageNodep; // Package hierarchy
|
AstNode* m_classOrPackageNodep; // Pointer to class/package referenced
|
||||||
public:
|
public:
|
||||||
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
|
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
|
||||||
AstPin* paramsp)
|
AstPin* paramsp)
|
||||||
|
|
@ -1057,7 +1057,7 @@ public:
|
||||||
};
|
};
|
||||||
class AstEnumItemRef final : public AstNodeExpr {
|
class AstEnumItemRef final : public AstNodeExpr {
|
||||||
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
|
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
|
||||||
AstNodeModule* m_classOrPackagep; // Package hierarchy
|
AstNodeModule* m_classOrPackagep; // Class/package in which it was defined
|
||||||
public:
|
public:
|
||||||
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
|
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
|
||||||
: ASTGEN_SUPER_EnumItemRef(fl)
|
: ASTGEN_SUPER_EnumItemRef(fl)
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ private:
|
||||||
bool m_recursive : 1; // Recursive or part of recursion
|
bool m_recursive : 1; // Recursive or part of recursion
|
||||||
bool m_underGenerate : 1; // Under generate (for warning)
|
bool m_underGenerate : 1; // Under generate (for warning)
|
||||||
bool m_virtual : 1; // Virtual method in class
|
bool m_virtual : 1; // Virtual method in class
|
||||||
bool m_fromStd : 1; // Part of std
|
bool m_needProcess : 1; // Implements part of a process that allocates std::process
|
||||||
VLifetime m_lifetime; // Lifetime
|
VLifetime m_lifetime; // Lifetime
|
||||||
protected:
|
protected:
|
||||||
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
||||||
|
|
@ -112,7 +112,7 @@ protected:
|
||||||
, m_recursive{false}
|
, m_recursive{false}
|
||||||
, m_underGenerate{false}
|
, m_underGenerate{false}
|
||||||
, m_virtual{false}
|
, m_virtual{false}
|
||||||
, m_fromStd{false} {
|
, m_needProcess{false} {
|
||||||
addStmtsp(stmtsp);
|
addStmtsp(stmtsp);
|
||||||
cname(name); // Might be overridden by dpi import/export
|
cname(name); // Might be overridden by dpi import/export
|
||||||
}
|
}
|
||||||
|
|
@ -172,8 +172,8 @@ public:
|
||||||
bool underGenerate() const { return m_underGenerate; }
|
bool underGenerate() const { return m_underGenerate; }
|
||||||
void isVirtual(bool flag) { m_virtual = flag; }
|
void isVirtual(bool flag) { m_virtual = flag; }
|
||||||
bool isVirtual() const { return m_virtual; }
|
bool isVirtual() const { return m_virtual; }
|
||||||
void isFromStd(bool flag) { m_fromStd = flag; }
|
void setNeedProcess() { m_needProcess = true; }
|
||||||
bool isFromStd() const { return m_fromStd; }
|
bool needProcess() const { return m_needProcess; }
|
||||||
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
||||||
VLifetime lifetime() const { return m_lifetime; }
|
VLifetime lifetime() const { return m_lifetime; }
|
||||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||||
|
|
@ -2138,7 +2138,7 @@ public:
|
||||||
class AstClass final : public AstNodeModule {
|
class AstClass final : public AstNodeModule {
|
||||||
// @astgen op4 := extendsp : List[AstClassExtends]
|
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under
|
AstClassPackage* m_classOrPackagep = nullptr; // Package it will be emitted with
|
||||||
bool m_extended = false; // Is extension or extended by other classes
|
bool m_extended = false; // Is extension or extended by other classes
|
||||||
bool m_interfaceClass = false; // Interface class
|
bool m_interfaceClass = false; // Interface class
|
||||||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||||
|
|
|
||||||
|
|
@ -3152,7 +3152,15 @@ private:
|
||||||
} else if (nodep->name() == "randomize" || nodep->name() == "srandom"
|
} else if (nodep->name() == "randomize" || nodep->name() == "srandom"
|
||||||
|| nodep->name() == "get_randstate"
|
|| nodep->name() == "get_randstate"
|
||||||
|| nodep->name() == "set_randstate") {
|
|| nodep->name() == "set_randstate") {
|
||||||
// Resolved in V3Width
|
if (AstClass* const classp = VN_CAST(m_modp, Class)) {
|
||||||
|
nodep->classOrPackagep(classp);
|
||||||
|
} else {
|
||||||
|
nodep->v3error("Calling implicit class method "
|
||||||
|
<< nodep->prettyNameQ() << " without being under class");
|
||||||
|
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if (nodep->dotted() == "") {
|
} else if (nodep->dotted() == "") {
|
||||||
if (nodep->pli()) {
|
if (nodep->pli()) {
|
||||||
if (v3Global.opt.bboxSys()) {
|
if (v3Global.opt.bboxSys()) {
|
||||||
|
|
|
||||||
|
|
@ -1322,7 +1322,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the fact that this function allocates std::process
|
// Mark the fact that this function allocates std::process
|
||||||
if (nodep->isFromStd() && nodep->name() == "self") cfuncp->setNeedProcess();
|
if (nodep->needProcess()) cfuncp->setNeedProcess();
|
||||||
|
|
||||||
// Delete rest of cloned task and return new func
|
// Delete rest of cloned task and return new func
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,6 @@ private:
|
||||||
// STATE
|
// STATE
|
||||||
VMemberMap memberMap; // Member names cached for fast lookup
|
VMemberMap memberMap; // Member names cached for fast lookup
|
||||||
WidthVP* m_vup = nullptr; // Current node state
|
WidthVP* m_vup = nullptr; // Current node state
|
||||||
AstClass* m_classp = nullptr; // Current class
|
|
||||||
const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
|
const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
|
||||||
const AstEnumItem* m_enumItemp = nullptr; // Current enum item
|
const AstEnumItem* m_enumItemp = nullptr; // Current enum item
|
||||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||||
|
|
@ -234,7 +233,6 @@ private:
|
||||||
const AstWith* m_withp = nullptr; // Current 'with' statement
|
const AstWith* m_withp = nullptr; // Current 'with' statement
|
||||||
const AstFunc* m_funcp = nullptr; // Current function
|
const AstFunc* m_funcp = nullptr; // Current function
|
||||||
const AstAttrOf* m_attrp = nullptr; // Current attribute
|
const AstAttrOf* m_attrp = nullptr; // Current attribute
|
||||||
AstPackage* m_pkgp = nullptr; // Current package
|
|
||||||
const bool m_paramsOnly; // Computing parameter value; limit operation
|
const bool m_paramsOnly; // Computing parameter value; limit operation
|
||||||
const bool m_doGenerate; // Do errors later inside generate statement
|
const bool m_doGenerate; // Do errors later inside generate statement
|
||||||
int m_dtTables = 0; // Number of created data type tables
|
int m_dtTables = 0; // Number of created data type tables
|
||||||
|
|
@ -2630,28 +2628,35 @@ private:
|
||||||
}
|
}
|
||||||
void visit(AstClass* nodep) override {
|
void visit(AstClass* nodep) override {
|
||||||
if (nodep->didWidthAndSet()) return;
|
if (nodep->didWidthAndSet()) return;
|
||||||
// If the package is std::process, set m_process type to VlProcessRef
|
|
||||||
if (m_pkgp && m_pkgp->name() == "std" && nodep->name() == "process") {
|
// If the class is std::process
|
||||||
if (AstVar* const varp = VN_CAST(memberMap.findMember(nodep, "m_process"), Var)) {
|
if (nodep->name() == "process") {
|
||||||
AstBasicDType* const dtypep = new AstBasicDType{
|
AstPackage* const packagep = getItemPackage(nodep);
|
||||||
nodep->fileline(), VBasicDTypeKwd::PROCESS_REFERENCE, VSigning::UNSIGNED};
|
if (packagep && packagep->name() == "std") {
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
// Change type of m_process to VlProcessRef
|
||||||
varp->getChildDTypep()->unlinkFrBack();
|
if (AstVar* const varp = VN_CAST(memberMap.findMember(nodep, "m_process"), Var)) {
|
||||||
varp->dtypep(dtypep);
|
AstNodeDType* const dtypep = varp->getChildDTypep();
|
||||||
|
if (!varp->dtypep()) {
|
||||||
|
VL_DO_DANGLING(pushDeletep(dtypep->unlinkFrBack()), dtypep);
|
||||||
|
}
|
||||||
|
AstBasicDType* const newdtypep = new AstBasicDType{
|
||||||
|
nodep->fileline(), VBasicDTypeKwd::PROCESS_REFERENCE, VSigning::UNSIGNED};
|
||||||
|
v3Global.rootp()->typeTablep()->addTypesp(newdtypep);
|
||||||
|
varp->dtypep(newdtypep);
|
||||||
|
}
|
||||||
|
// Mark that self requires process instance
|
||||||
|
if (AstNodeFTask* const ftaskp
|
||||||
|
= VN_CAST(memberMap.findMember(nodep, "self"), NodeFTask)) {
|
||||||
|
ftaskp->setNeedProcess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must do extends first, as we may in functions under this class
|
// Must do extends first, as we may in functions under this class
|
||||||
// start following a tree of extends that takes us to other classes
|
// start following a tree of extends that takes us to other classes
|
||||||
VL_RESTORER(m_classp);
|
|
||||||
m_classp = nodep;
|
|
||||||
userIterateAndNext(nodep->extendsp(), nullptr);
|
userIterateAndNext(nodep->extendsp(), nullptr);
|
||||||
userIterateChildren(nodep, nullptr); // First size all members
|
userIterateChildren(nodep, nullptr); // First size all members
|
||||||
}
|
}
|
||||||
void visit(AstPackage* nodep) override {
|
|
||||||
VL_RESTORER(m_pkgp);
|
|
||||||
m_pkgp = nodep;
|
|
||||||
userIterateChildren(nodep, nullptr);
|
|
||||||
}
|
|
||||||
void visit(AstThisRef* nodep) override {
|
void visit(AstThisRef* nodep) override {
|
||||||
if (nodep->didWidthAndSet()) return;
|
if (nodep->didWidthAndSet()) return;
|
||||||
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->childDTypep()));
|
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->childDTypep()));
|
||||||
|
|
@ -5315,7 +5320,6 @@ private:
|
||||||
nodep->didWidth(true);
|
nodep->didWidth(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_pkgp && m_pkgp->name() == "std") nodep->isFromStd(true);
|
|
||||||
if (nodep->classMethod() && nodep->name() == "rand_mode") {
|
if (nodep->classMethod() && nodep->name() == "rand_mode") {
|
||||||
nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden"
|
nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden"
|
||||||
" (IEEE 1800-2017 18.8)");
|
" (IEEE 1800-2017 18.8)");
|
||||||
|
|
@ -5592,22 +5596,17 @@ private:
|
||||||
|| (!nodep->taskp()
|
|| (!nodep->taskp()
|
||||||
&& (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) {
|
&& (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) {
|
||||||
// TODO perhaps this should move to V3LinkDot
|
// TODO perhaps this should move to V3LinkDot
|
||||||
if (!m_classp) {
|
AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class);
|
||||||
nodep->v3error("Calling implicit class method " << nodep->prettyNameQ()
|
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
|
||||||
<< " without being under class");
|
|
||||||
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nodep->name() == "randomize") {
|
if (nodep->name() == "randomize") {
|
||||||
nodep->taskp(V3Randomize::newRandomizeFunc(m_classp));
|
nodep->taskp(V3Randomize::newRandomizeFunc(classp));
|
||||||
memberMap.clear();
|
memberMap.clear();
|
||||||
} else if (nodep->name() == "srandom") {
|
} else if (nodep->name() == "srandom") {
|
||||||
nodep->taskp(V3Randomize::newSRandomFunc(m_classp));
|
nodep->taskp(V3Randomize::newSRandomFunc(classp));
|
||||||
memberMap.clear();
|
memberMap.clear();
|
||||||
} else if (nodep->name() == "get_randstate") {
|
} else if (nodep->name() == "get_randstate") {
|
||||||
methodOkArguments(nodep, 0, 0);
|
methodOkArguments(nodep, 0, 0);
|
||||||
m_classp->baseMostClassp()->needRNG(true);
|
classp->baseMostClassp()->needRNG(true);
|
||||||
v3Global.useRandomizeMethods(true);
|
v3Global.useRandomizeMethods(true);
|
||||||
AstCExpr* const newp
|
AstCExpr* const newp
|
||||||
= new AstCExpr{nodep->fileline(), "__Vm_rng.get_randstate()", 1, true};
|
= new AstCExpr{nodep->fileline(), "__Vm_rng.get_randstate()", 1, true};
|
||||||
|
|
@ -5620,7 +5619,7 @@ private:
|
||||||
AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit
|
AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit
|
||||||
iterateCheckString(nodep, "LHS", expr1p, BOTH);
|
iterateCheckString(nodep, "LHS", expr1p, BOTH);
|
||||||
AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp();
|
AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||||
m_classp->baseMostClassp()->needRNG(true);
|
classp->baseMostClassp()->needRNG(true);
|
||||||
v3Global.useRandomizeMethods(true);
|
v3Global.useRandomizeMethods(true);
|
||||||
AstCExpr* const newp
|
AstCExpr* const newp
|
||||||
= new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1, true};
|
= new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1, true};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
%Error: t/t_randomize_method_nclass_bad.v:9:7: Calling implicit class method 'randomize' without being under class
|
%Error: t/t_randomize_method_nclass_bad.v:9:7: Calling implicit class method 'randomize' without being under class
|
||||||
: ... In instance t
|
|
||||||
9 | randomize(1);
|
9 | randomize(1);
|
||||||
| ^~~~~~~~~
|
| ^~~~~~~~~
|
||||||
%Error: t/t_randomize_method_nclass_bad.v:10:7: Calling implicit class method 'srandom' without being under class
|
%Error: t/t_randomize_method_nclass_bad.v:10:7: Calling implicit class method 'srandom' without being under class
|
||||||
: ... In instance t
|
|
||||||
10 | srandom(1);
|
10 | srandom(1);
|
||||||
| ^~~~~~~
|
| ^~~~~~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2023 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();
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
typedef class Cls;
|
||||||
|
|
||||||
|
class A;
|
||||||
|
extern function void method();
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class B;
|
||||||
|
extern function void method();
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class C;
|
||||||
|
extern function void method();
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class D;
|
||||||
|
extern function void method();
|
||||||
|
endclass
|
||||||
|
|
||||||
|
function void A::method();
|
||||||
|
B obj = new;
|
||||||
|
obj.method();
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function void B::method();
|
||||||
|
this.srandom(0);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function void C::method();
|
||||||
|
this.srandom(0);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function void D::method();
|
||||||
|
C obj = new;
|
||||||
|
obj.method();
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
module t;
|
||||||
|
A obj1 = new;
|
||||||
|
D obj2 = new;
|
||||||
|
initial begin
|
||||||
|
obj1.method();
|
||||||
|
obj2.method();
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2023 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);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
verilator_flags2 => ["--exe --main --timing"],
|
||||||
|
make_main => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
verilator_flags2 => ["--exe --main --timing --DUSE_STD_PREFIX"],
|
||||||
|
make_main => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -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, 2023 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
static task do_something();
|
||||||
|
`ifdef USE_STD_PREFIX
|
||||||
|
std::process p;
|
||||||
|
`else
|
||||||
|
process p;
|
||||||
|
`endif
|
||||||
|
p = process::self();
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t();
|
||||||
|
initial begin
|
||||||
|
Foo::do_something();
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue