A UVM subscriber is a specialized component derived from uvm_subscriber that is primarily used to receive and process transactions. It is often utilized in scoreboards, coverage collectors, or monitors to analyze simulation data. Mostly we use uvm_subscriber for functional coverage monitor.
A subscriber typically:
- Connects to an analysis port to receive transactions
- Stores, compares, or checks incoming data
- Is used for checking functional coverage, logging, or verification.
Unlike a monitor, which captures DUT activity and forwards data to multiple components, a subscriber’s primary role is to consume and process transactions.
Structure of a UVM Subscriber
A user-defined subscriber class is extended from uvm_subsriber. uvm_subscriber is inherited by uvm_component. A UVM subscriber typically consists of:
- TLM Analysis Export (
analysis_export): Receives transactions from another UVM component (such as a monitor or scoreboard). - Write Method (
write()function): Processes incoming transactions when received. - Storage (Optional): Keeps track of received data for further comparison or analysis.

Example: Implementing a UVM Subscriber
Let’s walk through a simple UVM subscriber that collects transaction data and prints it for debugging.
Step 1: Define a Transaction Class
First, we create a basic transaction class that the subscriber will receive.
class transaction extends uvm_sequence_item;
rand bit [7:0] data;
`uvm_object_utils(transaction)
function new(string name = "transaction");
super.new(name);
endfunction
function void do_print(uvm_printer printer);
printer.print_field("data", data, 8, UVM_DEC);
endfunction
endclass
Step 2: Create a UVM Subscriber to Collect Coverage
In this step, we define a UVM subscriber that collects functional coverage every time it receives a transaction.
class coverage_subscriber extends uvm_subscriber#(transaction);
`uvm_component_utils(coverage_subscriber)
transaction trans;
// Functional coverage collection
covergroup transaction_cg;
coverpoint trans.data {
bins low_range = {[0:63]};
bins mid_range = {[64:127]};
bins high_range = {[128:255]};
}
endgroup
function new(string name = "coverage_subscriber", uvm_component parent = null);
super.new(name, parent);
transaction_cg = new();
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
$display("======in the coverage file==========");
trans = transaction::type_id::create("trans",this);
endfunction
// Write method to collect coverage
function void write(transaction trans);
transaction_cg.sample();
`uvm_info("COVERAGE_SUBSCRIBER", $sformatf("Received transaction: Data = %0d, Coverage of trans signal= %0d %%", trans.data,transaction_cg.get_coverage()), UVM_MEDIUM)
endfunction
endclass
Step 3: Connect Subscriber in a UVM Environment
Now, let’s integrate the subscriber into a UVM environment.
class my_env extends uvm_env;
`uvm_component_utils(my_env)
uvm_analysis_port#(transaction) ap;
coverage_subscriber cov_sub; // Coverage subscriber instance
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
cov_sub = coverage_subscriber::type_id::create("cov_sub", this);
ap = new("ap", this);
endfunction
function void connect_phase(uvm_phase phase);
ap.connect(cov_sub.analysis_export); // Connect subscriber to analysis port
endfunction
endclass
Step 4: Create a UVM Test to Generate Transactions
We now create a test to generate random transactions and send them to the subscriber for coverage collection.
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env;
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
task run_phase(uvm_phase phase);
transaction t;
phase.raise_objection(this);
for (int i = 0; i < 10; i++) begin
t = transaction::type_id::create("t");
t.randomize();
env.ap.write(t); // Send transaction to the coverage subscriber
#10;
end
phase.drop_objection(this);
endtask
endclass
Simulation Output
When the test runs, the subscriber receives transactions and collects coverage. You will see output similar to this:
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
======in the coverage file==========
UVM_INFO subscriber.sv(30) @ 0: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 50, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 10: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 38, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 20: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 25, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 30: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 0, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 40: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 218, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 50: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 91, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 60: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 21, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 70: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 93, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 80: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 53, Coverage of trans signal= 33 %
UVM_INFO subscriber.sv(30) @ 90: uvm_test_top.env.cov_sub [COVERAGE_SUBSCRIBER] Received transaction: Data = 197, Coverage of trans signal= 33 %
UVM_INFO /apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_objection.svh(1276) @ 100: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_report_server.svh(904) @ 100: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 13
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[COVERAGE_SUBSCRIBER] 10
[RNTST] 1
[TEST_DONE] 1
[UVM/RELNOTES] 1
$finish called from file "/apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_root.svh", line 527.
$finish at simulation time
By integrating functional coverage into a UVM subscriber, we can track the effectiveness of test patterns and ensure all important scenarios are verified.
