slang: find which instances an interface instance is bound to (through interface ports passed down)
Checked against slang v12.1 source and a 2-level test design. Goal: for each SystemVerilog interface instance, list every module instance whose interface port is bound to it (its real fanout), e.g. to find where its signals are read without walking the whole subtree.
- Interface ports aren't PortSymbols. In inst.body.getPortList() they have kind SymbolKind::InterfacePort. inst.getPortConnection(port.as<InterfacePortSymbol>()) returns a PortConnection, and conn->getIfaceConn() gives std::pair<const Symbol*, const ModportSymbol*>.
- The Symbol can be:
- an InstanceSymbol (the interface instance);
- an InstanceArraySymbol (recurse into .elements);
- when a parent passes its own interface port down (n_leaf u_leaf(.bus(bus)) inside a module whose bus is a port), resolve it with sym->as<InterfacePortSymbol>().getConnection().first, recursively.
With that, a leaf two levels down maps to the top-level interface instance.
- The modport is conn pair's second (or port.modport, a string, when the connection carries none).
- Build the map once: iterate all instances, then invert it (interface instance -> users). Sort the output for deterministic JSON.
- Reads through the port show up in expressions as references resolved to the interface instance's members, so in an export the fanout list plus the parent (which can read bus.x directly) covers every port-based reader. Hierarchical references from unrelated instances are not covered; list them separately.
Effect on a 6.6k-signal synthetic SoC with 56 interfaces: the per-signal load walk went from up to 167 visited instances (breadth-first under the parent) to at most 4, worst-case query 12 ms -> 2.7 ms, and a brute-force check found no missed reads.