Support direct class member init.

This commit is contained in:
Wilson Snyder 2020-04-18 20:20:17 -04:00
parent efacac2e3d
commit 466535abdc
5 changed files with 49 additions and 26 deletions

View File

@ -3623,9 +3623,8 @@ path.
=head2 Class =head2 Class
Verilator class support is very limited and in active development. Verilator class support is very limited and in active development.
Verilator supports members, and methods. Verilator doe not support initial Verilator supports members, and methods. Verilator doe not support class
values on class members, class static members, class extend, or class static members, class extend, or class parameters.
parameters.
=head2 Dotted cross-hierarchy references =head2 Dotted cross-hierarchy references

View File

@ -221,17 +221,16 @@ private:
if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
// 1. Parameters and function inputs: It's a default to use if not overridden // 1. Parameters and function inputs: It's a default to use if not overridden
} else if (VN_IS(m_modp, Class)) { } else if (VN_IS(m_modp, Class)) {
// We make a AstVar initial value, but then do not set it in the constructor // 2. Class member init become initials (as might call functions)
// V3Emit::emitVarRecurse only does non-value inits. // later move into class constructor
// Perhaps these should still become a new form of nodep->addNextHere(
// AstInitial, and we propagate the initial to the class new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
// constructor nodep->valuep()->unlinkFrBack())));
nodep->valuep()->v3error("Unsupported: initial value on member");
} else if (!m_ftaskp && nodep->isNonOutput()) { } else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3error( nodep->v3error(
"Unsupported: Default value on module input: " << nodep->prettyNameQ()); "Unsupported: Default value on module input: " << nodep->prettyNameQ());
nodep->valuep()->unlinkFrBack()->deleteTree(); nodep->valuep()->unlinkFrBack()->deleteTree();
} // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial } // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
else if (m_valueModp) { else if (m_valueModp) {
// Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it
FileLine* newfl = new FileLine(fl); FileLine* newfl = new FileLine(fl);
@ -239,7 +238,7 @@ private:
nodep->addNextHere(new AstInitial( nodep->addNextHere(new AstInitial(
newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
nodep->valuep()->unlinkFrBack()))); nodep->valuep()->unlinkFrBack())));
} // 3. Under blocks, it's an initial value to be under an assign } // 4. Under blocks, it's an initial value to be under an assign
else { else {
nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())); nodep->valuep()->unlinkFrBack()));

View File

@ -110,11 +110,14 @@ private:
// TYPES // TYPES
typedef std::map<std::pair<AstScope*, AstVar*>, AstVarScope*> VarToScopeMap; typedef std::map<std::pair<AstScope*, AstVar*>, AstVarScope*> VarToScopeMap;
typedef std::vector<AstInitial*> Initials;
// MEMBERS // MEMBERS
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
AstAssignW* m_assignwp; // Current assignment AstAssignW* m_assignwp; // Current assignment
AstNodeFTask* m_ctorp; // Class constructor
V3Graph m_callGraph; // Task call graph V3Graph m_callGraph; // Task call graph
TaskBaseVertex* m_curVxp; // Current vertex we're adding to TaskBaseVertex* m_curVxp; // Current vertex we're adding to
Initials m_initialps; // Initial blocks to move
public: public:
// METHODS // METHODS
@ -202,7 +205,10 @@ private:
m_curVxp = getFTaskVertex(nodep); m_curVxp = getFTaskVertex(nodep);
if (nodep->dpiImport()) m_curVxp->noInline(true); if (nodep->dpiImport()) m_curVxp->noInline(true);
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
if (nodep->isConstructor()) m_curVxp->noInline(true); if (nodep->isConstructor()) {
m_curVxp->noInline(true);
m_ctorp = nodep;
}
iterateChildren(nodep); iterateChildren(nodep);
m_curVxp = lastVxp; m_curVxp = lastVxp;
} }
@ -225,13 +231,41 @@ private:
if (m_curVxp->pure() && !nodep->varp()->isXTemp()) m_curVxp->impure(nodep); if (m_curVxp->pure() && !nodep->varp()->isXTemp()) m_curVxp->impure(nodep);
} }
} }
virtual void visit(AstClass* nodep) VL_OVERRIDE {
// Move initial statements into the constructor
m_initialps.clear();
m_ctorp = NULL;
{ // Find m_initialps, m_ctor
iterateChildren(nodep);
}
UASSERT_OBJ(m_ctorp, nodep, "class constructor missing"); // LinkDot always makes it
for (Initials::iterator it = m_initialps.begin(); it != m_initialps.end(); ++it) {
AstInitial* initialp = *it;
if (AstNode* newp = initialp->bodysp()) {
newp->unlinkFrBackWithNext();
if (!m_ctorp->stmtsp()) {
m_ctorp->addStmtsp(newp);
} else {
m_ctorp->stmtsp()->addHereThisAsNext(newp);
}
}
VL_DO_DANGLING(pushDeletep(initialp->unlinkFrBack()), initialp);
}
m_initialps.clear();
m_ctorp = NULL;
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
m_initialps.push_back(nodep);
iterateChildren(nodep);
}
//-------------------- //--------------------
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit TaskStateVisitor(AstNetlist* nodep) { explicit TaskStateVisitor(AstNetlist* nodep)
m_assignwp = NULL; : m_assignwp(NULL)
, m_ctorp(NULL) {
m_curVxp = new TaskCodeVertex(&m_callGraph); m_curVxp = new TaskCodeVertex(&m_callGraph);
AstNode::user3ClearTree(); AstNode::user3ClearTree();
AstNode::user4ClearTree(); AstNode::user4ClearTree();

View File

@ -1,7 +0,0 @@
%Error: t/t_class_local.v:12:22: Unsupported: initial value on member
12 | local int m_loc = 2;
| ^
%Error: t/t_class_local.v:13:27: Unsupported: initial value on member
13 | protected int m_prot = B;
| ^
%Error: Exiting due to

View File

@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
compile( compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
); );
#execute( execute(
# check_finished => 1, check_finished => 1,
# ); );
ok(1); ok(1);
1; 1;