diff --git a/include/verilated.cpp b/include/verilated.cpp index bdb184419..a28bb0f98 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2787,6 +2787,10 @@ void VerilatedHierarchy::add(VerilatedScope* fromp, VerilatedScope* top) { VerilatedImp::hierarchyAdd(fromp, top); } +void VerilatedHierarchy::remove(VerilatedScope* fromp, VerilatedScope* top) { + VerilatedImp::hierarchyRemove(fromp, top); +} + //=========================================================================== // VerilatedOneThreaded:: Methods diff --git a/include/verilated.h b/include/verilated.h index 6b8dc6abc..e30cdad53 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -363,6 +363,7 @@ public: // But internals only - called from VerilatedModule's class VerilatedHierarchy final { public: static void add(VerilatedScope* fromp, VerilatedScope* top); + static void remove(VerilatedScope* fromp, VerilatedScope* top); }; //=========================================================================== diff --git a/include/verilated_imp.h b/include/verilated_imp.h index ba0993570..b468f4ead 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -413,6 +413,16 @@ public: // But only for verilated*.cpp const VerilatedLockGuard lock(s_s.v.m_hierMapMutex); s_s.v.m_hierMap[fromp].push_back(top); } + static void hierarchyRemove(const VerilatedScope* fromp, + const VerilatedScope* top) VL_MT_SAFE { + // Slow ok - called at destruction for VPI accessible elements + const VerilatedLockGuard lock(s_s.v.m_hierMapMutex); + VerilatedHierarchyMap& map = s_s.v.m_hierMap; + if (map.find(fromp) == map.end()) return; + VerilatedScopeVector& scopes = map[fromp]; + const auto it = find(scopes.begin(), scopes.end(), top); + if (it != scopes.end()) scopes.erase(it); + } static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT { // Thread save only assuming this is called only after model construction completed return &s_s.v.m_hierMap; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 60847b0ec..ac049309a 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -116,6 +116,7 @@ class EmitCSyms final : EmitCBaseVisitor { void checkSplit(bool usesVfinal); void closeSplit(); void emitSymImpPreamble(); + void emitScopeHier(bool destroy); void emitSymImp(); void emitDpiHdr(); void emitDpiImp(); @@ -467,7 +468,7 @@ void EmitCSyms::emitSymHdr() { puts("\n// CREATORS\n"); puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n"); - puts(string("~") + symClassName() + "() = default;\n"); + puts(string("~") + symClassName() + "();\n"); for (const auto& i : m_usesVfinal) { puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); @@ -555,6 +556,40 @@ void EmitCSyms::emitSymImpPreamble() { } } +void EmitCSyms::emitScopeHier(bool destroy) { + if (v3Global.opt.vpi()) { + string verb = destroy ? "Tear down" : "Set up"; + string method = destroy ? "remove" : "add"; + puts("\n// " + verb + " scope hierarchy\n"); + for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); + ++it) { + string name = it->second.m_prettyName; + if (it->first == "TOP") continue; + if ((name.find('.') == string::npos) && (it->second.m_type == "SCOPE_MODULE")) { + puts("__Vhier." + method + "(0, &" + protect("__Vscope_" + it->second.m_symName) + + ");\n"); + } + } + + for (ScopeNameHierarchy::const_iterator it = m_vpiScopeHierarchy.begin(); + it != m_vpiScopeHierarchy.end(); ++it) { + for (ScopeNameList::const_iterator lit = it->second.begin(); lit != it->second.end(); + ++lit) { + string fromname = scopeSymString(it->first); + string toname = scopeSymString(*lit); + const auto from = vlstd::as_const(m_scopeNames).find(fromname); + const auto to = vlstd::as_const(m_scopeNames).find(toname); + UASSERT(from != m_scopeNames.end(), fromname + " not in m_scopeNames"); + UASSERT(to != m_scopeNames.end(), toname + " not in m_scopeNames"); + puts("__Vhier." + method + "("); + puts("&" + protect("__Vscope_" + from->second.m_symName) + ", "); + puts("&" + protect("__Vscope_" + to->second.m_symName) + ");\n"); + } + } + puts("\n"); + } +} + void EmitCSyms::emitSymImp() { UINFO(6, __FUNCTION__ << ": " << endl); string filename = v3Global.opt.makeDir() + "/" + symClassName() + ".cpp"; @@ -604,6 +639,10 @@ void EmitCSyms::emitSymImp() { puts("\n"); puts("\n// FUNCTIONS\n"); + puts(symClassName() + "::~" + symClassName() + "()\n"); + puts("{\n"); + emitScopeHier(true); + puts("}\n\n"); puts(symClassName() + "::" + symClassName() + "(" + topClassName() + "* topp, const char* namep)\n"); puts(" // Setup locals\n"); @@ -685,34 +724,7 @@ void EmitCSyms::emitSymImp() { } } - if (v3Global.opt.vpi()) { - puts("\n// Setup scope hierarchy\n"); - for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); - ++it) { - string name = it->second.m_prettyName; - if (it->first == "TOP") continue; - if ((name.find('.') == string::npos) && (it->second.m_type == "SCOPE_MODULE")) { - puts("__Vhier.add(0, &" + protect("__Vscope_" + it->second.m_symName) + ");\n"); - } - } - - for (ScopeNameHierarchy::const_iterator it = m_vpiScopeHierarchy.begin(); - it != m_vpiScopeHierarchy.end(); ++it) { - for (ScopeNameList::const_iterator lit = it->second.begin(); lit != it->second.end(); - ++lit) { - string fromname = scopeSymString(it->first); - string toname = scopeSymString(*lit); - const auto from = vlstd::as_const(m_scopeNames).find(fromname); - const auto to = vlstd::as_const(m_scopeNames).find(toname); - UASSERT(from != m_scopeNames.end(), fromname + " not in m_scopeNames"); - UASSERT(to != m_scopeNames.end(), toname + " not in m_scopeNames"); - puts("__Vhier.add("); - puts("&" + protect("__Vscope_" + from->second.m_symName) + ", "); - puts("&" + protect("__Vscope_" + to->second.m_symName) + ");\n"); - } - } - puts("\n"); - } + emitScopeHier(false); // Everything past here is in the __Vfinal loop, so start a new split file if needed closeSplit(); diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 13ba9eeef..b6c5aa40b 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -165,6 +165,9 @@ int main(int argc, char** argv, char** env) { Verilated::fatalOnVpiError(0); VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + // Test second construction + delete topp; + topp = new VM_PREFIX(""); #ifdef VERILATOR #ifdef TEST_VERBOSE