diff --git a/Changes b/Changes index 016f91f50..acac7dee0 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 4.221 devel * Split --prof-threads into --prof-exec and --prof-pgo (#3365). [Geza Lore, Shunyao CAD] * Deprecate 'vluint64_t' and similar types (#3255). +* Raise error on assignment to const in initial blocks. [Geza Lore, Shunyao CAD] * Fix MSVC localtime_s (#3124). * Fix Bison 3.8.2 error (#3366). [elike-ypq] * Fix rare bug in -Oz (V3Localize) (#3286). [Geza Lore, Shunyao CAD] diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 043f05233..a0ed963ef 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -422,6 +422,14 @@ private: virtual void visit(AstActive* nodep) override { // Actives are being formed, so we can ignore any already made } + virtual void visit(AstInitialStatic* nodep) override { + // Relink to IACTIVE, unless already under it + UINFO(4, " INITIAL " << nodep << endl); + const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; + AstActive* const wantactivep = m_namer.getIActive(nodep->fileline()); + nodep->unlinkFrBack(); + wantactivep->addStmtsp(nodep); + } virtual void visit(AstInitial* nodep) override { // Relink to IACTIVE, unless already under it UINFO(4, " INITIAL " << nodep << endl); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 1c86aad29..5082ae08d 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3407,7 +3407,7 @@ public: }; class AstInitialAutomatic final : public AstNodeProcedure { - // initial for automatic variables + // Automatic variable initialization // That is, it runs every function start, or class construction public: AstInitialAutomatic(FileLine* fl, AstNode* bodysp) @@ -3415,6 +3415,15 @@ public: ASTNODE_NODE_FUNCS(InitialAutomatic) }; +class AstInitialStatic final : public AstNodeProcedure { + // Static variable initialization + // That is, it runs at the beginning of simulation, before 'initial' blocks +public: + AstInitialStatic(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_InitialStatic(fl, bodysp) {} + ASTNODE_NODE_FUNCS(InitialStatic) +}; + class AstAlways final : public AstNodeProcedure { const VAlwaysKwd m_keyword; diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 871a5fd8c..acb305ab0 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -716,6 +716,7 @@ private: // Ignores virtual void visit(AstInitial*) override {} virtual void visit(AstInitialAutomatic*) override {} + virtual void visit(AstInitialStatic*) override {} virtual void visit(AstTraceDecl*) override {} virtual void visit(AstCoverToggle*) override {} virtual void visit(AstNodeDType*) override {} diff --git a/src/V3Class.cpp b/src/V3Class.cpp index c7bbc91c3..6a7a3ce4f 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -153,6 +153,11 @@ private: iterateChildren(nodep); if (m_packageScopep) { m_toScopeMoves.push_back(std::make_pair(nodep, m_packageScopep)); } } + virtual void visit(AstInitialStatic* nodep) override { + // But not AstInitialAutomatic, which remains under the class + iterateChildren(nodep); + if (m_packageScopep) { m_toScopeMoves.push_back(std::make_pair(nodep, m_packageScopep)); } + } virtual void visit(AstNodeMath* nodep) override {} // Short circuit virtual void visit(AstNodeStmt* nodep) override {} // Short circuit @@ -173,7 +178,7 @@ public: vscp->scopep(scopep); vscp->unlinkFrBack(); scopep->addVarp(vscp); - } else if (VN_IS(nodep, Initial)) { + } else if (VN_IS(nodep, Initial) || VN_IS(nodep, InitialStatic)) { nodep->unlinkFrBack(); scopep->addActivep(nodep); } else { diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index e04c15e4d..594795fa5 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -99,6 +99,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { putqs(nodep, "end\n"); } virtual void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); } + virtual void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); } virtual void visit(AstAlways* nodep) override { putfs(nodep, "always "); if (m_sensesp) { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index b99b8e3a9..df1e36436 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -275,7 +275,7 @@ private: if (nodep->lifetime().isAutomatic()) { nodep->addNextHere(new AstInitialAutomatic{newfl, assp}); } else { - nodep->addNextHere(new AstInitial{newfl, assp}); + nodep->addNextHere(new AstInitialStatic{newfl, assp}); } } // 4. Under blocks, it's an initial value to be under an assign else { diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 090e81b7d..9007ce8f2 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -662,6 +662,9 @@ class OrderBuildVisitor final : public VNVisitor { virtual void visit(AstInitialAutomatic* nodep) override { // iterateLogic(nodep); } + virtual void visit(AstInitialStatic* nodep) override { // + iterateLogic(nodep); + } virtual void visit(AstAlways* nodep) override { // iterateLogic(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f4c350d6e..45a78ac8c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2041,7 +2041,8 @@ private: if (nodep->access().isWriteOrRW() && nodep->varp()->direction() == VDirection::CONSTREF) { nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ()); } else if (nodep->access().isWriteOrRW() && nodep->varp()->isConst() && !m_paramsOnly - && (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) { + && (!m_ftaskp || !m_ftaskp->isConstructor()) + && !VN_IS(m_procedurep, InitialStatic)) { // Too loose, but need to allow our generated first assignment // Move this to a property of the AstInitial block nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ());