forked from github/verilator
Add separate AstInitialStatic node for static initializers
Static variable initializers run before initial blocks, so use an explicitly different procedure type for them. This also enables us to now raise errors for assignments to const variables in initial blocks.
This commit is contained in:
parent
b22e368b25
commit
9abab2c366
1
Changes
1
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]
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user