🚀 Introduction#
This page explains how to use TLM FIFO, Analysis Port, and the _decl macro in UVM TLM. These building blocks make data transfer easier and increase modularity in testbench design.
1️⃣ TLM FIFO Usage#
📌 What is it?#
uvm_tlm_fifo
in UVM allows transactions to be stored sequentially.- It supports both blocking and non-blocking interfaces.
📌 Advantages#
✅ Using FIFO enables producer/consumer decoupling.
✅ Allows asynchronous data flow without data loss.
📦 Example Usage#
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
// Transaction class
class my_transaction extends uvm_sequence_item;
rand int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Producer
class my_producer extends uvm_component;
uvm_tlm_fifo #(my_transaction) fifo;
`uvm_component_utils(my_producer)
function new(string name = "my_producer", uvm_component parent = null);
super.new(name, parent);
fifo = new("fifo", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
for (int i = 0; i < 5; i++) begin
tr = my_transaction::type_id::create("tr");
assert(tr.randomize()) else `uvm_error("PRODUCER", "Failed to randomize transaction")
`uvm_info("PRODUCER", $sformatf("Sending data: %0d", tr.data), UVM_LOW)
fifo.put(tr); // Blocking put
#100; // Simulated delay
end
phase.drop_objection(this);
endtask
endclass
// Consumer
class my_consumer extends uvm_component;
uvm_tlm_fifo #(my_transaction) fifo;
`uvm_component_utils(my_consumer)
function new(string name = "my_consumer", uvm_component parent = null);
super.new(name, parent);
fifo = new("fifo", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
repeat (5) begin
fifo.get(tr);
`uvm_info("CONSUMER", $sformatf("Received data: %0d", tr.data), UVM_LOW)
#50;
end
phase.drop_objection(this);
endtask
endclass
// Testbench
class my_env extends uvm_env;
my_producer producer;
my_consumer consumer;
uvm_tlm_fifo #(my_transaction) shared_fifo;
`uvm_component_utils(my_env)
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
shared_fifo = new("shared_fifo", this);
producer = my_producer::type_id::create("producer", this);
consumer = my_consumer::type_id::create("consumer", this);
producer.fifo = shared_fifo;
consumer.fifo = shared_fifo;
endfunction
endclass
// Test
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
endclass
endpackage
// Test run
module top;
import uvm_pkg::*;
import my_pkg::*;
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule
📌 Note#
- When using blocking ports, FIFO ensures synchronous data transfer.
- Non-blocking methods: try_put(), can_put(), try_get(), can_get().
2️⃣ Analysis Port Usage#
📌 What is it?#
- The analysis port is used to send data to multiple subscribers simultaneously.
- Data is broadcasted using the
write()
method.
📌 Advantages#
✅ The broadcast structure makes it easy to connect to coverage or scoreboard components. ✅ Operates non-blocking.
📦 Example Usage#
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
// Transaction class
class my_transaction extends uvm_sequence_item;
int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Producer
class my_producer extends uvm_component;
uvm_analysis_port #(my_transaction) analysis_port;
`uvm_component_utils(my_producer)
function new(string name = "my_producer", uvm_component parent = null);
super.new(name, parent);
analysis_port = new("analysis_port", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
for (int i = 0; i < 5; i++) begin
tr = my_transaction::type_id::create("tr");
tr.data = i;
`uvm_info("PRODUCER", $sformatf("Sending data: %0d", tr.data), UVM_LOW)
analysis_port.write(tr); // Broadcast data
#100; // Simulated delay
end
phase.drop_objection(this);
endtask
endclass
// Subscriber 1
class my_subscriber1 extends uvm_subscriber #(my_transaction);
`uvm_component_utils(my_subscriber1)
function new(string name = "my_subscriber1", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void write(my_transaction t);
`uvm_info("SUBSCRIBER1", $sformatf("Received data: %0d", t.data), UVM_LOW)
endfunction
endclass
// Subscriber 2
class my_subscriber2 extends uvm_subscriber #(my_transaction);
`uvm_component_utils(my_subscriber2)
function new(string name = "my_subscriber2", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void write(my_transaction t);
`uvm_info("SUBSCRIBER2", $sformatf("Received data: %0d", t.data), UVM_LOW)
endfunction
endclass
// Testbench
class my_env extends uvm_env;
my_producer producer;
my_subscriber1 subscriber1;
my_subscriber2 subscriber2;
`uvm_component_utils(my_env)
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
producer = my_producer::type_id::create("producer", this);
subscriber1 = my_subscriber1::type_id::create("subscriber1", this);
subscriber2 = my_subscriber2::type_id::create("subscriber2", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
producer.analysis_port.connect(subscriber1.analysis_export);
producer.analysis_port.connect(subscriber2.analysis_export);
endfunction
endclass
// Test
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
endclass
endpackage
// Test run
module top;
import uvm_pkg::*;
import my_pkg::*;
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule