Part 4 · TLM & Analysis · Intermediate
connect() Binding Rules: Semantics, Cardinality, and One-to-One Flow
How connect() resolves endpoint chains, when one-to-one assumptions apply, and how to catch invalid bindings early.
connect_phase is interface binding time
UVM expects TLM endpoint binding to happen in connect_phase. By this point, component creation is complete and handles are stable, so interface chains can be verified consistently.
Binding in build_phase is possible in small cases but brittle in large hierarchies. Binding in run_phase is too late and risks nondeterministic behavior.
function void env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
prod.out_port.connect(router.in_export);
router.in_export.connect(cons.in_imp);
endfunction[UVM][TLM] connect lifecycle
build_phase:
create components + endpoint objects
connect_phase:
bind ports/exports to providers
run_phase:
initiator calls methods on resolved chainTreat connect_phase as the source of truth for TLM topology.
Keep binds centralized for readability and debug.
Avoid conditional binding unless topology intentionally varies by config.
Type compatibility and interface family matching
Endpoints in a chain must match interface family and transaction type parameters. Mixing put with get, blocking with non-blocking, or mismatched item types causes compile/connect failures.
[TLM] compatibility matrix mindset
must match:
interface family (put/get/peek/transport/analysis)
blocking flavor where required
transaction type parameter(s)
method signature expectations
cannot rely on:
implicit cast across endpoint families// Valid
uvm_blocking_put_port #(pkt_t) p_port;
uvm_blocking_put_export #(pkt_t) p_exp;
uvm_blocking_put_imp #(pkt_t, sink_t) p_imp;
// Invalid intent examples
// p_port.connect(nonblocking_put_imp) // blocking mismatch
// p_port.connect(blocking_put_imp#(other_t)) // type mismatch
// p_port.connect(get_imp#(pkt_t,...)) // interface family mismatch[UVM] practical policy
for every connect() call, review:
endpoint class names
type parameter list
expected method set
owner role on each sideSmall type mismatches become large debug sessions if unchecked early.
Use typedefs for transaction types to keep chains consistent across files.
Prefer explicit endpoint naming that reflects interface family.
Cardinality and one-to-one semantics
Many point-to-point TLM interfaces are conceptually one initiator to one provider path. Even when chaining through exports, semantics remain single resolved provider for deterministic flow-controlled operation.
Analysis broadcast is different and supports one-to-many delivery. Do not project analysis rules onto put/get families.
[UVM][TLM] cardinality comparison
flow-controlled families (put/get/transport):
typical: 1 initiator path -> 1 provider chain
objective: deterministic handshake semantics
analysis family:
1 initiator write() -> N subscribers
objective: broadcast observation[TLM] one-to-one enforcement checklist
- exactly one terminal imp expected for each point-to-point initiator call path
- no accidental fan-out via ad-hoc adapters
- no duplicate providers bound to same initiator endpoint
- flow-control status should be attributable to one targetfunction void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// Canonical one path:
req_gen.req_port.connect(req_router.req_export);
req_router.req_export.connect(req_sink.req_imp);
endfunctionKeep one-to-one chains explicit for flow-controlled interfaces.
Use analysis endpoints for fan-out instead of forcing multi-target put/get patterns.
Document intentional exceptions with adapter components and strict tests.
Binding diagnostics and failure triage
When a call fails at runtime or silently stalls, isolate whether issue is unresolved bind, wrong family, or role mismatch. Debug topology before transaction content.
[UVM][TLM] failure signatures
compile-time error:
endpoint class/type mismatch likely
connect-time fatal/warning:
unresolved chain or illegal binding
run-time stall/drop:
call path bound but provider behavior/flow control not as expected[TLM] triage sequence
1) print endpoint declarations and types
2) inspect each connect() call in connect_phase
3) verify terminal imp exists and implements required methods
4) run one deterministic transaction
5) correlate initiator call timestamp to provider method entryKey takeaways
connect_phase is the contractual place to bind TLM endpoint chains.
Compatibility requires matching family, flavor, and transaction type parameters.
Point-to-point interfaces should preserve one resolved provider path for clarity.
Topology-first debugging finds bind errors faster than payload-level debugging.
Common pitfalls
Applying analysis broadcast assumptions to put/get interfaces.
Scattering connect calls across many components without ownership clarity.
Ignoring warnings in connect_phase that later become run-time behavior anomalies.
Using mismatched typedefs for transaction types across endpoint declarations.