mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Fix interface modport resolution against non-scope symbol tables (#8420)
LinkDotFindVisitor queued an AstIface into m_ifaceModSyms once for every symbol table entry it was reached through. When creating scopes, LinkDotIfaceVisitor resolves the modport items against the AstVarScopes, which LinkDotScopeVisitor only inserts under the entry of an AstScope. A hierarchical block wrapper builds a second copy of the instance tree in the symbol table, and an interface reached through that copy has no AstVarScopes to resolve against. Resolving is destructive (the AstModportVarRef is deleted once resolved), so this only worked when a resolvable entry happened to be processed first, and failed with "Modport item not found" otherwise. When creating scopes, register from the AstScopes instead, as those are exactly the entries that hold the AstVarScopes. Reproduces on t_hier_block with -fno-inline, added as a test.
This commit is contained in:
+12
-3
@@ -1344,9 +1344,13 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
iterateChildren(nodep);
|
||||
nodep->user2(false);
|
||||
nodep->user4(true);
|
||||
// Interfaces need another pass when signals are resolved
|
||||
if (AstIface* const ifacep = VN_CAST(nodep, Iface)) {
|
||||
m_statep->insertIfaceModSym(ifacep, m_curSymp);
|
||||
// Interfaces need another pass when signals are resolved. When creating
|
||||
// scopes this is done from the AstScopes in LinkDotScopeVisitor instead, as
|
||||
// only those entries hold the AstVarScopes the modport items resolve against.
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
if (AstIface* const ifacep = VN_CAST(nodep, Iface)) {
|
||||
m_statep->insertIfaceModSym(ifacep, m_curSymp);
|
||||
}
|
||||
}
|
||||
} else if (isHierBlockWrapper(nodep->name())) {
|
||||
UINFO(5, "Module is hierarchical block, must not be dead: " << nodep);
|
||||
@@ -2684,6 +2688,11 @@ private:
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_scopep);
|
||||
m_modSymp = m_statep->getScopeSym(nodep);
|
||||
// Interfaces need another pass when signals are resolved. Register the scope's
|
||||
// entry, as that is the one holding the AstVarScopes.
|
||||
if (AstIface* const ifacep = VN_CAST(nodep->modp(), Iface)) {
|
||||
m_statep->insertIfaceModSym(ifacep, m_modSymp);
|
||||
}
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.priority(30)
|
||||
test.scenarios('vlt')
|
||||
test.top_filename = "t/t_hier_block.v"
|
||||
|
||||
# Compilation of hierarchical blocks is skipped if their libs exist
|
||||
test.clean_objs()
|
||||
|
||||
test.compile(v_flags2=['t/t_hier_block.cpp'],
|
||||
verilator_flags2=['-fno-inline', '--hierarchical', '--Wno-TIMESCALEMOD'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
Reference in New Issue
Block a user