Part 4 · TLM & Analysis · Intermediate

Port, Export, and Imp Objects: What Each Type Does

Detailed object responsibilities for TLM endpoints and how each one participates in binding and execution.

Object semantics in one view

A clean mental model is: port expresses demand, imp provides capability, export forwards capability through hierarchy. These are not interchangeable declarations - they represent distinct intent.

diagram
[UVM][TLM] endpoint responsibilities

port:
  - call site handle
  - initiates interface methods
  - may chain through hierarchy

export:
  - relay endpoint
  - forwards interface binding
  - often used at subsystem boundaries

imp:
  - terminal endpoint
  - binds to concrete class method implementation
diagram
[TLM] ownership pattern

testbench composition:
  requester component owns port
  intermediate container may own export
  provider component owns imp

execution:
  requester call travels through chain to imp
  • Declare endpoints by role intent, not by what compiles fastest.

  • Imp is the only endpoint that actually executes interface behavior.

  • Export is best treated as interface plumbing through component layers.


Port deep dive

A port is a typed handle used by initiator code. For example, uvm_blocking_put_port#(txn_t) means this component wants to call blocking put on txn_t objects through some provider chain resolved in connect_phase.

systemverilog
class req_gen extends uvm_component;
  `uvm_component_utils(req_gen)
  uvm_nonblocking_put_port #(req_t) req_port;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    req_port = new("req_port", this);
  endfunction

  task run_phase(uvm_phase phase);
    req_t r;
    bit ok;
    forever begin
      r = req_t::type_id::create("r");
      assert(r.randomize());
      ok = req_port.try_put(r);
      if (!ok) `uvm_warning("FLOW", "try_put failed due to flow control")
    end
  endtask
endclass
diagram
[UVM][TLM] port behavior notes

port does:
  - type checks interface signature
  - initiates call during run-time
  - reports bind/connect issues when unresolved

port does not:
  - store business logic implementation
  - decide provider semantics
  • Use blocking vs non-blocking ports to express flow-control expectations clearly.

  • Keep initiator behavior in the owner component, not in connection code.

  • Initialize ports in constructor/build and bind only in connect_phase.


Export deep dive

An export is a forwarding endpoint that re-exposes an interface. It lets parent components present interfaces owned by deeper child components, avoiding direct external references into child internals.

systemverilog
class stream_agent extends uvm_component;
  `uvm_component_utils(stream_agent)
  stream_driver drv;
  uvm_blocking_put_export #(req_t) req_export;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    drv = stream_driver::type_id::create("drv", this);
    req_export = new("req_export", this);
  endfunction

  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    // Parent-level users connect to agent.req_export.
    // Agent forwards to internal driver port/chain endpoint.
    req_export.connect(drv.req_port);
  endfunction
endclass
diagram
[UVM][TLM] export as boundary contract

outside world sees:
  agent.req_export

inside agent:
  req_export forwards to child endpoint chain

benefit:
  child structure can evolve while external interface remains stable
diagram
[TLM] where export shines

- subsystem-to-agent boundary
- reusable VIP wrappers
- multi-layer env composition
- preserving encapsulation with explicit public TLM surface
  • Use exports to publish stable TLM boundaries from composite components.

  • Document where each export forwards to reduce hidden coupling.

  • Avoid long anonymous export chains; name them by functional intent.


Imp deep dive and terminal behavior

Imp is the terminal endpoint that binds method calls to concrete class code. Its second type parameter is the implementation class, which is where interface methods are executed.

systemverilog
class req_sink extends uvm_component;
  `uvm_component_utils(req_sink)
  uvm_nonblocking_put_imp #(req_t, req_sink) req_imp;
  int accepted_count;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    req_imp = new("req_imp", this);
  endfunction

  virtual function bit try_put(req_t r);
    if (!can_accept(r)) return 0;
    accepted_count++;
    process_req(r);
    return 1;
  endfunction

  protected function bit can_accept(req_t r);
    return (r != null);
  endfunction

  protected function void process_req(req_t r);
    `uvm_info("SINK", $sformatf("accepted req id=%0d", r.id), UVM_MEDIUM)
  endfunction
endclass
diagram
[UVM][TLM] imp terminal role

incoming call chain:
  requester port -> ... -> req_imp.try_put(r)

terminal behavior:
  class method executes
  local state updates
  status/return values produced

Key takeaways

  • Port expresses call intent, export relays interface, and imp executes behavior.

  • Export helps maintain encapsulation by exposing stable public TLM boundaries.

  • Imp methods are where flow control and semantics become real behavior.

  • Design endpoint declarations as API contracts, not temporary wiring artifacts.

Common pitfalls

  • Declaring imps without implementing required interface methods correctly.

  • Hiding critical export forwarding in undocumented connect code.

  • Treating port declarations as passive fields instead of runtime call endpoints.

  • Using inconsistent transaction type parameters across endpoint chain.