Part 4 · TLM & Analysis · Intermediate
Environment Connection Patterns: Practical Port/Export/Imp Wiring
Common environment-level wiring blueprints for point-to-point paths, analysis fan-out, and layered hierarchy composition.
Pattern 1: canonical point-to-point agent path
A common pattern is sequence/producer side calling through a port, optional agent export as public boundary, and driver/consumer imp as terminal endpoint.
[UVM][TLM] point-to-point template
producer.port
-> agent.req_export
-> driver.req_imp
Characteristics:
single provider chain
deterministic flow control
clear ownership boundariesclass my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_driver drv;
my_producer prod;
uvm_blocking_put_export #(req_t) req_export;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
drv = my_driver::type_id::create("drv", this);
prod = my_producer::type_id::create("prod", this);
req_export = new("req_export", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
prod.req_port.connect(req_export);
req_export.connect(drv.req_imp);
endfunction
endclassKeep each point-to-point path visually traceable from caller to terminal imp.
Use exports at agent boundaries to avoid exposing private child handles.
Add one smoke sequence that exercises each bound path during bring-up.
Pattern 2: monitor analysis fan-out
Analysis paths are the canonical one-to-many pattern. A monitor publishes once and many subscribers consume independently.
[MON][UVM][TLM] analysis fan-out
monitor.analysis_port
-> env.analysis_export
-> scoreboard.analysis_imp
-> coverage_sub.analysis_imp
-> logger_sub.analysis_imp
One write(), multiple observers, no backpressure.function void env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
mon.ap.connect(ap_export);
ap_export.connect(sb.analysis_imp);
ap_export.connect(cov.analysis_imp);
ap_export.connect(log.analysis_imp);
endfunction[TLM] fan-out design reminders
- analysis subscribers should be side-effect isolated
- no subscriber should assume it is sole consumer
- ordering among subscribers should not affect correctness
- use tags/time for cross-subscriber correlationUse analysis for observation networks; avoid forcing put/get fan-out.
Subscribers should tolerate independent activation and ordering variations.
Keep monitor payload rich enough for scoreboard and coverage needs together.
Pattern 3: layered env -> subsystem -> agent wiring
Large SoC benches use layered composition. Each layer publishes minimal boundary endpoints and forwards downward in connect_phase. This keeps integration modular.
[UVM][TLM] layered hierarchy blueprint
top_env.req_export
-> periph_ss.req_export
-> uart_agent.req_export
-> uart_driver.req_imp
top_env.obs_export
<- periph_ss.obs_export
<- uart_agent.mon_ap (analysis write source)function void top_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
req_export.connect(periph_ss.req_export);
periph_ss.obs_export.connect(obs_export);
endfunction
function void periph_ss::connect_phase(uvm_phase phase);
super.connect_phase(phase);
req_export.connect(uart_agt.req_export);
uart_agt.mon_ap.connect(obs_export);
endfunction[TLM] layered wiring rules
1) each layer exposes only needed public endpoints
2) each connection declared at ownership layer
3) no top-level direct bind to deep private children
4) diagram both command and observation pathsLayered endpoints prevent tight coupling between top env and deep agent internals.
Keep request and observation path naming separate to avoid role confusion.
Require subsystem-level topology review before large integration merges.
Pattern 4: debug-first wiring discipline
Connection bugs are cheaper to catch with topology probes than with full regression failures. Add minimal diagnostics that confirm each chain is alive before heavy stimulus.
[UVM][TLM] pre-regression checks
check A: all expected connect calls executed
check B: no unresolved endpoint warnings
check C: one deterministic transaction reaches terminal imp
check D: one monitor write reaches all intended subscriberstask env_smoke_seq::body();
req_t r;
r = req_t::type_id::create("r");
r.id = 1;
p_sequencer.req_port.put(r);
// Expect terminal imp and scoreboard observation logs.
endtask[TLM] maintainability checklist for env wiring
- endpoints named by role and payload domain
- connect_phase grouped by communication path
- hierarchy diagrams updated when topology changes
- one smoke test per major path (cmd, rsp, analysis)Key takeaways
Use repeatable wiring templates to keep large environments understandable.
Point-to-point and analysis fan-out should use their natural TLM families.
Layered exports provide modular integration without exposing private internals.
Topology smoke tests catch miswires earlier than functional regressions.
Common pitfalls
Copy-paste connect blocks without updating endpoint families/types.
Deep direct binds that bypass published subsystem interfaces.
No early smoke path checks before long randomized runs.
Combining command and analysis paths under ambiguous endpoint names.