Understanding uvm_pool in UVM — The Hidden Gem for Shared Objects 🚀

Understanding uvm_pool in UVM — The Hidden Gem for Shared Objects 🚀

In UVM, we often need a way to share data or objects across different components, phases, or even testbenches — without relying on global variables or messy static handles.That’s where uvm_pool quietly shines ✨

uvm_pool #(KEY,T) Implements a class-based dynamic associative array. Allows sparse arrays to be allocated on demand, and passed and stored by reference.

Class Hierarchy: uvm_void > uvm_object > uvm_pool#(KEY,T)

🧩 Class Declaration in uvm

class uvm_pool #(type KEY = int, type T = uvm_void ) extends uvm_object;        

This means each pool instance maps keys of type KEY to items of type T.


⚙️ Commonly Used Methods

Method Description

  1. Creates : a new pool with the given name.
  2. get_global_pool : Returns the singleton global pool for the item type, T.
  3. get_global : Returns the specified item instance from the global item pool.
  4. get Returns : the item with the given key.
  5. add : Adds the given (key, item) pair to the pool.
  6. num : Returns the number of uniquely keyed items stored in the pool.
  7. delete : Removes the item with the given key from the pool.
  8. exists : Returns 1 if an item with the given key exists in the pool, 0 otherwise.
  9. first : Returns the key of the first item stored in the pool.
  10. last : Returns the key of the last item stored in the pool.
  11. next : Returns the key of the next item in the pool. prev Returns the key of the previous item in the pool.

Let’s understand this step-by-step 👇


🔹 Step 1: Create a uvm_pool Handle

Wherever you want to share something globally (say from your top module), first create a pool handle:

uvm_pool#(.T(OBJ), .KEY(string)) shared_obj_pool;
        

Here:

  • T → Type of object you want to store (e.g. OBJ)
  • KEY → Type of key you’ll use (usually string)


🔹 Step 2: Get the Global Pool Handle

Now assign this handle to the global pool instance:

shared_obj_pool = uvm_pool#(.T(OBJ), .KEY(string))::get_global_pool();
        

This means you’re not creating a new pool — you’re connecting to a global one. Anything you add here will be visible across all classes or modules that access the same global pool.


🔹 Step 3: Add Objects to the Pool

You can add multiple objects (of type OBJ) with different keys — think of it as a dynamic array or map that stores (key → object) pairs:

shared_obj_pool.add("shared_obj", shared_obj);
shared_obj_pool.add("obj_sec", obj_sec);
        

So now both shared_obj and obj_sec are globally accessible anywhere in your environment.


🔹 Step 4: Retrieve Objects Anywhere (like in a test)

In your my_test class, you can directly fetch them using the same keys:

class my_test extends uvm_test;
  `uvm_component_utils(my_test)
  OBJ obj;
  OBJ sec;

  function new(string name="my_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    #100ns;

    // Fetch from global pool
    obj = uvm_pool#(.T(OBJ), .KEY(string))::get_global("shared_obj");
    sec = uvm_pool#(.T(OBJ), .KEY(string))::get_global("obj_sec");

    // Monitor both continuously
    fork
      forever begin
        @(obj.value);
        obj.display();
        sec.display();
      end
    join_none

    #500ns;
    phase.drop_objection(this);
  endtask
endclass
        

Now both obj and sec point to the same objects that were created in your top module.


🔹 Step 5: Update Values from TB Top

From your top-level module, you can change their values — and your test will automatically see the updated ones!

module tb;
  initial begin
    OBJ shared_obj, obj_sec;
    uvm_pool#(.T(OBJ), .KEY(string)) shared_obj_pool;

    // Get the global pool
    shared_obj_pool = uvm_pool#(.T(OBJ), .KEY(string))::get_global_pool();

    // Create and add both objects
    shared_obj = new("shared_obj");
    obj_sec    = new("obj_sec");
    shared_obj_pool.add("shared_obj", shared_obj);
    shared_obj_pool.add("obj_sec", obj_sec);

    $display("[TB] Shared objects added to global pool:");

    #300ns;
    shared_obj.value = 132; obj_sec.value = 82;
    #5ns;  shared_obj.value = 133; obj_sec.value = 83;
    #5ns;  shared_obj.value = 134; obj_sec.value = 84;
    #5ns;  shared_obj.value = 135; obj_sec.value = 85;
    #5ns;  shared_obj.value = 136; obj_sec.value = 86;
  end

  initial begin
    run_test("my_test");
  end
endmodule
        

🧩 Output

[TB] Shared objects added to global pool:
OBJ name=shared_obj, value=132
OBJ name=obj_sec, value=82
OBJ name=shared_obj, value=133
OBJ name=obj_sec, value=83
OBJ name=shared_obj, value=134
OBJ name=obj_sec, value=84
OBJ name=shared_obj, value=135
OBJ name=obj_sec, value=85
OBJ name=shared_obj, value=136
OBJ name=obj_sec, value=86
        

So, we created two objects in the top-level module, added them to the global pool, and then accessed them in a completely different UVM class — both sharing real-time updated values 🔄

Code Link


💬 Final Thoughts

uvm_pool is like a global mailbox for objects — you can store, retrieve, and share any data type anywhere in your UVM environment.

It’s especially useful when:

  • You need to share configuration or status between TB top and UVM test
  • Multiple components need access to the same live object
  • You want a simple way to connect module world with class world

Once you start using it, it really simplifies your testbench architecture!


🧠 Key Takeaway

uvm_pool = Global Object Sharing Made Simple

You can add any number of items with unique keys and fetch them anytime, anywhere — all without extra connections or config_db complexity.

#UVM #SystemVerilog #Verification #VLSI #LearningByDoing #DesignVerification #testbench #verilog

To view or add a comment, sign in

More articles by Vikas Kumar

Others also viewed

Explore content categories