diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h
index 55239b529..580e34c08 100644
--- a/src/V3AstNodes.h
+++ b/src/V3AstNodes.h
@@ -9155,6 +9155,7 @@ private:
AstExecGraph* m_execGraphp = nullptr; // Execution MTask graph for threads>1 mode
VTimescale m_timeunit; // Global time unit
VTimescale m_timeprecision; // Global time precision
+ bool m_changeRequest = false; // Have _change_request method
bool m_timescaleSpecified = false; // Input HDL specified timescale
public:
AstNetlist();
@@ -9178,6 +9179,8 @@ public:
AstNode* miscsp() const { return op3p(); } // op3 = List of dtypes etc
void addMiscsp(AstNode* nodep) { addOp3p(nodep); }
AstTypeTable* typeTablep() { return m_typeTablep; }
+ void changeRequest(bool specified) { m_changeRequest = specified; }
+ bool changeRequest() const { return m_changeRequest; }
AstConstPool* constPoolp() { return m_constPoolp; }
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
AstPackage* dollarUnitPkgAddp() {
diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp
index 062da8eac..dc3343f87 100644
--- a/src/V3Changed.cpp
+++ b/src/V3Changed.cpp
@@ -47,11 +47,33 @@ public:
AstCFunc* m_tlChgFuncp = nullptr; // Top level change function we're building
int m_numStmts = 0; // Number of statements added to m_chgFuncp
int m_funcNum = 0; // Number of change functions emitted
+ bool m_madeTopChg = false;
ChangedState() = default;
~ChangedState() = default;
void maybeCreateChgFuncp() {
+ maybeCreateTopChg();
+ maybeCreateMidChg();
+ }
+ void maybeCreateTopChg() {
+ if (m_madeTopChg) return;
+ m_madeTopChg = true;
+ v3Global.rootp()->changeRequest(true);
+
+ // Create a wrapper change detection function that calls each change detection function
+ m_tlChgFuncp
+ = new AstCFunc{m_scopetopp->fileline(), "_change_request", m_scopetopp, "QData"};
+ m_tlChgFuncp->isStatic(false);
+ m_tlChgFuncp->isLoose(true);
+ m_tlChgFuncp->declPrivate(true);
+ m_scopetopp->addActivep(m_tlChgFuncp);
+ // Each change detection function needs at least one AstChangeDet
+ // to ensure that V3EmitC outputs the necessary code.
+ maybeCreateMidChg();
+ m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr, false});
+ }
+ void maybeCreateMidChg() {
// Don't create an extra function call if splitting is disabled
if (!v3Global.opt.outputSplitCFuncs()) {
m_chgFuncp = m_tlChgFuncp;
@@ -242,24 +264,11 @@ private:
UINFO(4, " TS " << nodep << endl);
// Clearing
AstNode::user1ClearTree();
- // Create the change detection function
+ // Prep for if make change detection function
AstScope* const scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
- // Create a wrapper change detection function that calls each change detection function
- m_statep->m_tlChgFuncp
- = new AstCFunc{nodep->fileline(), "_change_request", scopep, "QData"};
- m_statep->m_tlChgFuncp->isStatic(false);
- m_statep->m_tlChgFuncp->isLoose(true);
- m_statep->m_tlChgFuncp->declPrivate(true);
- m_statep->m_scopetopp->addActivep(m_statep->m_tlChgFuncp);
- // Each change detection function needs at least one AstChangeDet
- // to ensure that V3EmitC outputs the necessary code.
- m_statep->maybeCreateChgFuncp();
- m_statep->m_chgFuncp->addStmtsp(
- new AstChangeDet{nodep->fileline(), nullptr, nullptr, false});
-
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) override {
diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp
index 5729c51e2..ed130c578 100644
--- a/src/V3EmitCFunc.cpp
+++ b/src/V3EmitCFunc.cpp
@@ -772,7 +772,7 @@ void EmitCFunc::emitChangeDet() {
puts("QData __req = false; // Logically a bool\n"); // But not because it results in
// faster code
bool gotOne = false;
- for (AstChangeDet* changep : m_blkChangeDetVec) {
+ for (AstChangeDet* const changep : m_blkChangeDetVec) {
if (changep->lhsp()) {
if (!gotOne) { // Not a clocked block
puts("__req |= (");
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index 5b3922e6d..965cf56c0 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -312,8 +312,10 @@ class EmitCModel final : public EmitCFunc {
const string topModNameProtected = prefixNameProtect(modp);
putsDecoration("// Evaluate till stable\n");
- puts("int __VclockLoop = 0;\n");
- puts("QData __Vchange = 1;\n");
+ if (v3Global.rootp()->changeRequest()) {
+ puts("int __VclockLoop = 0;\n");
+ puts("QData __Vchange = 1;\n");
+ }
if (v3Global.opt.trace()) puts("vlSymsp->__Vm_activity = true;\n");
puts("do {\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ ");
@@ -322,29 +324,34 @@ class EmitCModel final : public EmitCFunc {
if (initial)
puts(topModNameProtected + "__" + protect("_eval_settle") + "(&(vlSymsp->TOP));\n");
puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n");
- puts("if (VL_UNLIKELY(++__VclockLoop > " + cvtToStr(v3Global.opt.convergeLimit())
- + ")) {\n");
- puts("// About to fail, so enable debug to see what's not settling.\n");
- puts("// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n");
- puts("int __Vsaved_debug = Verilated::debug();\n");
- puts("Verilated::debug(1);\n");
- puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request")
- + "(&(vlSymsp->TOP));\n");
- puts("Verilated::debug(__Vsaved_debug);\n");
- puts("VL_FATAL_MT(");
- putsQuoted(protect(modp->fileline()->filename()));
- puts(", ");
- puts(cvtToStr(modp->fileline()->lineno()));
- puts(", \"\",\n");
- puts("\"Verilated model didn't ");
- if (initial) puts("DC ");
- puts("converge\\n\"\n");
- puts("\"- See https://verilator.org/warn/DIDNOTCONVERGE\");\n");
- puts("} else {\n");
- puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request")
- + "(&(vlSymsp->TOP));\n");
- puts("}\n");
- puts("} while (VL_UNLIKELY(__Vchange));\n");
+ if (v3Global.rootp()->changeRequest()) {
+ puts("if (VL_UNLIKELY(++__VclockLoop > " + cvtToStr(v3Global.opt.convergeLimit())
+ + ")) {\n");
+ puts("// About to fail, so enable debug to see what's not settling.\n");
+ puts("// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n");
+ puts("int __Vsaved_debug = Verilated::debug();\n");
+ puts("Verilated::debug(1);\n");
+ puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request")
+ + "(&(vlSymsp->TOP));\n");
+ puts("Verilated::debug(__Vsaved_debug);\n");
+ puts("VL_FATAL_MT(");
+ putsQuoted(protect(modp->fileline()->filename()));
+ puts(", ");
+ puts(cvtToStr(modp->fileline()->lineno()));
+ puts(", \"\",\n");
+ puts("\"Verilated model didn't ");
+ if (initial) puts("DC ");
+ puts("converge\\n\"\n");
+ puts("\"- See https://verilator.org/warn/DIDNOTCONVERGE\");\n");
+ puts("} else {\n");
+ puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request")
+ + "(&(vlSymsp->TOP));\n");
+ puts("}\n");
+ }
+ puts("} while ("
+ + (v3Global.rootp()->changeRequest() ? std::string{"VL_UNLIKELY(__Vchange)"}
+ : std::string{"0"})
+ + ");\n");
}
void emitStandardMethods(AstNodeModule* modp) {
@@ -360,8 +367,10 @@ class EmitCModel final : public EmitCFunc {
puts("void " + topModNameProtected + "__" + protect("_eval_initial") + selfDecl + ";\n");
puts("void " + topModNameProtected + "__" + protect("_eval_settle") + selfDecl + ";\n");
puts("void " + topModNameProtected + "__" + protect("_eval") + selfDecl + ";\n");
- puts("QData " + topModNameProtected + "__" + protect("_change_request") + selfDecl
- + ";\n");
+ if (v3Global.rootp()->changeRequest()) {
+ puts("QData " + topModNameProtected + "__" + protect("_change_request") + selfDecl
+ + ";\n");
+ }
puts("#ifdef VL_DEBUG\n");
puts("void " + topModNameProtected + "__" + protect("_eval_debug_assertions") + selfDecl
+ ";\n");
diff --git a/test_regress/t/t_protect_ids_key.out b/test_regress/t/t_protect_ids_key.out
index 7a7d53d4b..4575b30b0 100644
--- a/test_regress/t/t_protect_ids_key.out
+++ b/test_regress/t/t_protect_ids_key.out
@@ -22,8 +22,6 @@
-
-
diff --git a/test_regress/t/t_verilated_debug.out b/test_regress/t/t_verilated_debug.out
index 5ac844a6b..932ee8483 100644
--- a/test_regress/t/t_verilated_debug.out
+++ b/test_regress/t/t_verilated_debug.out
@@ -13,18 +13,12 @@ internalsDump:
-V{t#,#}+ Initial loop
-V{t#,#}+ Vt_verilated_debug___024root___eval_settle
-V{t#,#}+ Vt_verilated_debug___024root___eval
--V{t#,#}+ Vt_verilated_debug___024root___change_request
--V{t#,#}+ Vt_verilated_debug___024root___change_request_1
-V{t#,#}+ Clock loop
-V{t#,#}+ Vt_verilated_debug___024root___eval
--V{t#,#}+ Vt_verilated_debug___024root___change_request
--V{t#,#}+ Vt_verilated_debug___024root___change_request_1
-V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step
-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions
-V{t#,#}+ Clock loop
-V{t#,#}+ Vt_verilated_debug___024root___eval
-V{t#,#}+ Vt_verilated_debug___024root___sequent__TOP__2
*-* All Finished *-*
--V{t#,#}+ Vt_verilated_debug___024root___change_request
--V{t#,#}+ Vt_verilated_debug___024root___change_request_1
-V{t#,#}+ Vt_verilated_debug___024root___final