Skip to main content

Using TLM FIFO, Analysis Port, and _decl Macro in UVM

· loading · loading · ·
Education UVM Verification UVM Verification SystemVerilog TLM FIFO Analysis Port
Education UVM Verification
Axolot Logic
Author
Axolot Logic
Digital Design Engineer
Table of Contents
UVM Series - This article is part of a series.
Part 28: This Article

🚀 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

UVM Series - This article is part of a series.
Part 28: This Article

Related

Using the _decl Macro in UVM
· loading · loading
Education UVM Verification UVM Verification SystemVerilog _Decl Macro Analysis Port
Education UVM Verification
UVM Agent Usage and Adder Example
· loading · loading
Education UVM Verification UVM Verification SystemVerilog Uvm_agent Testbench Structure
Education UVM Verification
UVM Base Classes
· loading · loading
Education UVM Verification UVM Verification SystemVerilog Class Hierarchy
Education UVM Verification
UVM Driver Usage and Adder Example
· loading · loading
Education UVM Verification UVM Verification SystemVerilog Uvm_driver Stimulus Driving
Education UVM Verification
UVM Environment Usage and adder_env Example
· loading · loading
Education UVM Verification UVM Verification SystemVerilog Uvm_env Testbench Structure
Education UVM Verification
UVM Monitor Usage and Adder Example
· loading · loading
Education UVM Verification UVM Verification SystemVerilog Uvm_monitor Coverage
Education UVM Verification