Overview
One key to improving verification productivity is thinking at the appropriate level of abstraction. UVM provides transaction-level communication interfaces for this purpose.
Transactions
In UVM, transactions model the information required for communication between two components (variables, constraints, etc.). Below is a simple bus-protocol transaction example:
class simple_trans extends uvm_transaction;
rand data_t data;
rand addr_t addr;
rand enum {WRITE, READ} kind;
constraint c1 { addr < 16'h2000; }
...
endclass
After defining transactions, an interface that operates on those transactions must be provided.
TLM ports initiate transaction operations; TLM exports provide concrete implementations of those transaction methods.
Basic TLM Communication: put operation
The most basic transaction-level operation is one component putting a transaction to another component.
In the diagram, the square on the producer represents a port; the circle on the consumer represents an export.
class producer extends uvm_component;
uvm_blocking_put_port #(simple_trans) put_port; // 1 parameter
function new(string name, uvm_component parent);
put_port = new("put_port", this);
...
endfunction
virtual task run();
simple_trans t;
for (int i = 0; i < N; i++) begin
// Generate t.
put_port.put(t);
end
endtask
endclass
The producer declares a uvm_blocking_put_port parameterized with simple_trans, then issues put operations inside its run() task.
class consumer extends uvm_component;
uvm_blocking_put_imp #(simple_trans, consumer) put_export; // 2 parameters
...
task put(simple_trans t);
case (t.kind)
READ: // Do read.
WRITE: // Do write.
endcase
endtask
endclass
The consumer declares a uvm_blocking_put_imp parameterized with simple_trans and specifying the implementing component. The put() method implementation resides in the consumer.
Basic TLM Communication: get operation
The get transaction-level operation is similar to put.
In the diagram, the square on the get_consumer represents a port; the circle on the get_producer represents an export.
class get_consumer extends uvm_component;
uvm_blocking_get_port #(simple_trans) get_port;
function new(string name, uvm_component parent);
get_port = new("get_port", this);
...
endfunction
virtual task run();
simple_trans t;
for (int i = 0; i < N; i++) begin
// Generate t.
get_port.get(t);
end
endtask
endclass
The corresponding export implements the get operation:
class get_producer extends uvm_component;
uvm_blocking_get_imp #(simple_trans, get_producer) get_export;
...
task get(output simple_trans t);
simple_trans tmp = new();
// Assign values to tmp.
t = tmp;
endtask
endclass
ALLPCB
