UVM TLM Non-Blocking Put

Non-blocking put is a UVM TLM communication mechanism where a producer attempts to send a transaction without waiting for the consumer to finish processing it.

Learning Objectives

  • Understand non-blocking communication in UVM TLM
  • Learn how try_put() differs from blocking put()
  • Understand handshake-style transaction flow
  • Run and analyze a working example

What is Non-Blocking Put?

In non-blocking put communication, the sender calls the try_put() function and immediately receives a success/failure response.

Unlike blocking put, the producer does not wait for the consumer to complete processing. Instead, it checks whether the consumer is ready to accept the transaction.

Non-blocking communication enables flow control without stalling the producer.

Architecture Overview

Non-blocking put communication is built using three TLM elements. The structure is identical to blocking put, but behavior differs.

Producer (Port) → Export (Forwarding) → Implementation (Consumer)

TLM Components

Non-Blocking Put Port

The port belongs to the producer and initiates the transaction transfer. It declares the try_put() function.

uvm_nonblocking_put_port #(packet) put_port;
  • Owned by the sender
  • Calls try_put()
  • Returns 1 (success) or 0 (failure)
Non-Blocking Put Export

The export forwards the transaction to another component. It does not implement functionality.

uvm_nonblocking_put_export #(packet) put_export;
Non-Blocking Put Implementation

The implementation resides in the consumer and defines the try_put() function.

uvm_nonblocking_put_imp #(packet, consumer) put_imp;
The producer is never blocked. Flow control must be handled explicitly.

Connections and Code Behavior

p.put_port.connect(c.put_export);
c.put_export.connect(c.put_imp);

Connections are established during the connect_phase. When the producer calls try_put(), UVM routes the call through the connected chain until it reaches the implementation.

Port → Export → Implementation → try_put()

The consumer decides whether it can accept the transaction. The return value determines if the producer should retry later.

Execution Flow

  1. Producer calls try_put(transaction)
  2. Call is forwarded through export
  3. Consumer checks readiness
  4. Function returns success (1) or failure (0)
Non-blocking put is ideal for modeling backpressure and ready/valid behavior.

Verification Insight

Non-blocking put is commonly used when modeling hardware interfaces that support retry mechanisms or ready/valid handshakes. It allows more accurate timing control compared to blocking communication.

Engineers often combine try_put() with retry loops or event-based synchronization to simulate realistic hardware behavior.

Run This Example on EDA Playground

Run the complete example directly in your browser without installing tools.

▶ Open in EDA Playground

View Source Code on GitHub

The complete source code for this example is available on GitHub. You can explore the project structure, download the files, or clone the repository to run locally.

Open on GitHub