From 466535abdcaf6da23812f26753ac67fd610422c8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Apr 2020 20:20:17 -0400 Subject: [PATCH] Support direct class member init. --- bin/verilator | 5 ++-- src/V3LinkParse.cpp | 15 ++++++------ src/V3Task.cpp | 40 +++++++++++++++++++++++++++++--- test_regress/t/t_class_local.out | 7 ------ test_regress/t/t_class_local.pl | 8 +++---- 5 files changed, 49 insertions(+), 26 deletions(-) delete mode 100644 test_regress/t/t_class_local.out diff --git a/bin/verilator b/bin/verilator index fed1cb08d..2a2ea028b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3623,9 +3623,8 @@ path. =head2 Class Verilator class support is very limited and in active development. -Verilator supports members, and methods. Verilator doe not support initial -values on class members, class static members, class extend, or class -parameters. +Verilator supports members, and methods. Verilator doe not support class +static members, class extend, or class parameters. =head2 Dotted cross-hierarchy references diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 1d5e7a510..c5b1a89c7 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -221,17 +221,16 @@ private: if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { // 1. Parameters and function inputs: It's a default to use if not overridden } else if (VN_IS(m_modp, Class)) { - // We make a AstVar initial value, but then do not set it in the constructor - // V3Emit::emitVarRecurse only does non-value inits. - // Perhaps these should still become a new form of - // AstInitial, and we propagate the initial to the class - // constructor - nodep->valuep()->v3error("Unsupported: initial value on member"); + // 2. Class member init become initials (as might call functions) + // later move into class constructor + nodep->addNextHere( + new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), + nodep->valuep()->unlinkFrBack()))); } else if (!m_ftaskp && nodep->isNonOutput()) { nodep->v3error( "Unsupported: Default value on module input: " << nodep->prettyNameQ()); 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) { // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* newfl = new FileLine(fl); @@ -239,7 +238,7 @@ private: nodep->addNextHere(new AstInitial( newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), 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 { nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), nodep->valuep()->unlinkFrBack())); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 3ab819107..8fcd656ff 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -110,11 +110,14 @@ private: // TYPES typedef std::map, AstVarScope*> VarToScopeMap; + typedef std::vector Initials; // MEMBERS VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings AstAssignW* m_assignwp; // Current assignment + AstNodeFTask* m_ctorp; // Class constructor V3Graph m_callGraph; // Task call graph TaskBaseVertex* m_curVxp; // Current vertex we're adding to + Initials m_initialps; // Initial blocks to move public: // METHODS @@ -202,7 +205,10 @@ private: m_curVxp = getFTaskVertex(nodep); if (nodep->dpiImport()) m_curVxp->noInline(true); 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); m_curVxp = lastVxp; } @@ -225,13 +231,41 @@ private: 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); } public: // CONSTRUCTORS - explicit TaskStateVisitor(AstNetlist* nodep) { - m_assignwp = NULL; + explicit TaskStateVisitor(AstNetlist* nodep) + : m_assignwp(NULL) + , m_ctorp(NULL) { m_curVxp = new TaskCodeVertex(&m_callGraph); AstNode::user3ClearTree(); AstNode::user4ClearTree(); diff --git a/test_regress/t/t_class_local.out b/test_regress/t/t_class_local.out deleted file mode 100644 index 397a3ef37..000000000 --- a/test_regress/t/t_class_local.out +++ /dev/null @@ -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 diff --git a/test_regress/t/t_class_local.pl b/test_regress/t/t_class_local.pl index 64b3d2dde..27b3049d2 100755 --- a/test_regress/t/t_class_local.pl +++ b/test_regress/t/t_class_local.pl @@ -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, -# ); +execute( + check_finished => 1, + ); ok(1); 1;