Source Deep Dive: sc_export and Hierarchical Binding
How exports expose interfaces upward, how hierarchical binding resolves, and why binding errors appear at elaboration end.
How to Read This Lesson
Ports are how a module asks for an interface. Exports are how a module offers an interface from something inside it. If that feels backwards at first, imagine a submodule hiding a channel while still exposing the channel's API to its parent.
Source and LRM Trail
Use Docs/LRMs/SystemC_LRM_1666-2023.pdf for interfaces, ports, exports, channels, and binding rules. In source, inspect .codex-src/systemc/src/sysc/communication/sc_export.*, sc_port.*, sc_interface.*, and the binding completion logic connected through sc_simcontext.
Why Exports Exist
Suppose a subsystem contains an internal FIFO, but the parent should connect to the subsystem rather than to the FIFO directly.
SC_MODULE(Subsys) {
sc_core::sc_export<sc_core::sc_fifo_in_if<int>> in_export;
sc_core::sc_fifo<int> fifo;
SC_CTOR(Subsys)
: in_export("in_export"), fifo("fifo", 16) {
in_export.bind(fifo);
}
};The export says: "from outside this module, you may treat me as this interface." The implementation object is still the internal channel.
Port to Export to Channel
A parent can connect a port to the export:
sc_core::sc_port<sc_core::sc_fifo_in_if<int>> in_port;
Subsys subsys{"subsys"};
in_port.bind(subsys.in_export);At the API level, that looks like one bind. At elaboration completion, the kernel resolves the chain:
port -> export -> fifo channel -> interface implementationThen the port can call interface methods through the resolved interface pointer.
How the Source Makes This Work
The implementation defers full binding checks until the end of elaboration. That is not laziness; it is what lets C++ constructors build a hierarchy in any practical order.
During construction:
- ports register with the port registry
- exports register as objects that can provide interfaces
- bind calls record relationships
During binding completion:
- hierarchical chains are resolved
- missing bindings are reported
- type mismatches are reported
- final interface pointers are cached
Pitfall: Export Without an Interface
An export that is never bound to a concrete interface is not useful. It is like a public API endpoint with no implementation behind it.
Good review question: if this export is visible in the hierarchy, what channel or object actually implements its interface?
Review Checklist
- Does every export bind to a concrete interface?
- Is the export exposing the smallest interface needed?
- Does the parent connect to the subsystem boundary instead of reaching into internals?
- Are binding errors caught during elaboration rather than hidden until runtime?
- Are names stable enough for hierarchy inspection and reports?
Comments and Corrections