A UVM sequence library is a special sequence that holds a collection of registered sequence types and runs them a configurable number of times, picking which one to run next by random, cyclic-random or user-defined selection. It is the built-in way to get varied stimulus from a set of existing sequences without writing a new top-level sequence for every combination.

8 min read | Intermediate Level

What You'll Learn

  • What uvm_sequence_library is and how its selection modes work
  • Create a sequence library and register sequences statically and dynamically
  • Configure iteration count and start the library on a sequencer
  • Read the library's log output and avoid common setup errors

What is a UVM sequence library ?

A sequence defines how a series of uvm_sequence_item objects are created, randomized and sent to the DUT. Its main logic lives in the body() task.

Unlike UVM components, which are created once and form the fixed testbench hierarchy, sequences are transient objects. They are created, run and then discarded.

The uvm_sequence_library is itself a sequence, but one that holds a list of other sequence types. When it is started like any other sequence, it repeatedly selects a sequence from that list and executes it. The selection_mode field decides how each sequence is picked.

ModeDescription
UVM_SEQ_LIB_RANDRandomly select a sequence from the list each iteration. Repeats are allowed.
UVM_SEQ_LIB_RANDCRandomly select without repeating until every sequence in the list has been executed once.
UVM_SEQ_LIB_ITEMRun no sequences. Each iteration sends a single randomized item of the library's item type.
UVM_SEQ_LIB_USERCall the select_sequence() method to get the index of the next sequence. Override this method to define your own selection order.

The uvm_sequence_library class extends the uvm_sequence base class, so it can do anything a sequence can do.


class uvm_sequence_library #(type REQ=uvm_sequence_item, RSP=REQ) extends uvm_sequence#(REQ,RSP);
class hierarchy - uvm_sequence_library

Syntax


class LIB_NAME extends uvm_sequence_library #(ITEM_TYPE);  // Same item type as member sequences
  `uvm_object_utils (LIB_NAME)                            // Normal factory registration
  `uvm_sequence_library_utils (LIB_NAME)                  // Adds the library's registration table

  function new (string name = "LIB_NAME");
    super.new (name);
    init_sequence_library ();                             // Copies registered sequences into this instance
  endfunction
endclass

Key fields you set before starting the library:

  • selection_mode - one of the four modes in the table above (default UVM_SEQ_LIB_RAND)
  • min_random_count / max_random_count - limits for the number of iterations
  • sequence_count - the actual number of iterations, chosen between the two limits when the library is randomized

Why use a sequence library ?

  • Automated stimulus selection: The library picks and runs sequences from its list on its own. This produces varied and less predictable stimulus without hard-coding every scenario, which helps reach DUT corner cases.
  • Regression testing: The same library can run a different mix of sequences with every random seed, so a single test becomes many useful regression runs.
  • Configurable generation: Changing one field switches between pure random, cyclic random, item-only and user-defined selection, without touching the member sequences.

Where are Sequence Libraries Used?

Sequence libraries are common in block-level regressions for bus and memory controllers. A library of read, write, burst and error-injection sequences is run with hundreds of seeds, so each run exercises a different order and mix of traffic from the same test.

How to Use

1. Define Your Library

Extend the uvm_sequence_library class and parameterize it with the sequence item type its member sequences produce.


  class my_seq_lib extends uvm_sequence_library #(my_item);

2. Factory Registration

Register the library with the factory using `uvm_object_utils. Also call `uvm_sequence_library_utils, which adds the static table that member sequences register into.


  `uvm_object_utils(my_seq_lib)
  `uvm_sequence_library_utils(my_seq_lib)

3. Initialization

Call init_sequence_library() in the library's constructor. It copies every sequence registered with this library type into the new instance.


  function new(string name="my_seq_lib");
     super.new(name);
     init_sequence_library();
  endfunction

4. Add Member Sequences

Sequences can be added in two ways.

Statically: The `uvm_add_to_seq_lib macro is placed inside the sequence class itself. It registers that sequence with one or more library types.


  class my_seq1 extends my_seq;
     `uvm_object_utils(my_seq1);
     `uvm_add_to_seq_lib(my_seq1, my_seq_lib)
     `uvm_add_to_seq_lib(my_seq1, my_another_seq_lib)
     ...

  endclass
  

Dynamically: The static methods add_typewide_sequence() and add_typewide_sequences() register sequences with the library type, so every instance created afterwards includes them. The simplest place to call them is the library's own constructor, before init_sequence_library().


  class my_seq_lib extends uvm_sequence_library #(my_item);
     `uvm_object_utils(my_seq_lib)
     `uvm_sequence_library_utils(my_seq_lib)

     function new(string name="my_seq_lib");
        super.new(name);

        add_typewide_sequences({mem_seq1::get_type(), mem_seq2::get_type()});
        init_sequence_library();
     endfunction

  endclass
  

To add a sequence to one library instance only, use add_sequence() or add_sequences(). This is usually done in the test that creates the instance.


class my_seq_lib_test extends base_test;

  ...

  task main_phase(uvm_phase phase);
    phase.raise_objection(this, "Raising Main Objection");

    // Register another sequence with this sequence library instance
    seq_lib.add_sequence( data_err_seq::get_type() );

    // Start the data sequence
    seq_lib.start(data_sequencer); // This task call is blocking

    phase.drop_objection(this, "Dropping Main Objection");
  endtask : main_phase

endclass : my_seq_lib_test

start() does not randomize the library. When it is started this way, sequence_count keeps its default value of 10 unless you set it directly or call randomize() on the library first. A library started as a sequencer's default_sequence is randomized automatically.

Quick Check

Q: You call add_typewide_sequence() and add_sequence() on the same library. Which one affects other instances of that library type?

Show Answer

add_typewide_sequence(). It registers the sequence with the library type, so instances initialized later include it. add_sequence() changes only the instance it is called on.

Sequence Library Example

A large verification environment can have hundreds of tests with different seeds and configurations. One way to manage this is to write small sequences that each do one job, and let a sequence library combine them at random.

Take three sequences, all derived from the same base_sequence class. They are independent sequences, not nested inside each other.


class seq1 extends base_sequence;
	...
	virtual task body ();
		`uvm_info ("SEQ1", "Starting seq1", UVM_MEDIUM)
		#10;
		`uvm_info ("SEQ1", "Ending seq1", UVM_MEDIUM)
	endtask
	...
endclass

class seq2 extends base_sequence;
	...
	virtual task body ();
         `uvm_info ("SEQ2", "Starting seq2", UVM_MEDIUM)
         #10;
         `uvm_info ("SEQ2", "Ending seq2", UVM_MEDIUM)
	endtask
    ...
endclass

class seq3 extends base_sequence;
	...
	virtual task body ();
    	`uvm_info ("SEQ3", "Starting seq3", UVM_MEDIUM)
		#10;
		`uvm_info ("SEQ3", "Ending seq3", UVM_MEDIUM)
	endtask
    ...
endclass

A custom sequence library is then derived from uvm_sequence_library.


class my_seq_lib_v2 extends uvm_sequence_library #(my_data);
   `uvm_object_utils (my_seq_lib_v2)
   `uvm_sequence_library_utils (my_seq_lib_v2)

   function new (string name="my_seq_lib_v2");
      super.new (name);
      init_sequence_library();
   endfunction
endclass

Always call `uvm_sequence_library_utils in a library class. Without it, the library has no registration table, and sequences added with `uvm_add_to_seq_lib cannot find it.

Each library is itself a sequence, so it can be started on different sequencers or in different phases of the same sequencer. A test creates an instance, configures it, adds the sequences it needs, and then makes it the sequencer's default sequence.

flow of sequence from library to driver

class feature_test extends base_test;
   `uvm_component_utils (feature_test)

   my_seq_lib m_seq_lib0;
   seq1 m_seq1;
   seq2 m_seq2;
   seq3 m_seq3;

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

   function void build_phase (uvm_phase phase);
      super.build_phase (phase);

      m_seq_lib0 = my_seq_lib::type_id::create ("m_seq_lib0");
   endfunction

   virtual task configure_phase (uvm_phase phase);
      super.configure_phase (phase);
      `uvm_info ("CFG_PHASE", "Add sequences to library", UVM_MEDIUM)
      m_seq_lib0.selection_mode = UVM_SEQ_LIB_RANDC;
      m_seq_lib0.min_random_count = 5;
      m_seq_lib0.max_random_count = 10;

      m_seq_lib0.add_typewide_sequence (m_seq1.get_type());
      m_seq_lib0.add_typewide_sequence (m_seq2.get_type());
      m_seq_lib0.add_typewide_sequence (m_seq3.get_type());
      m_seq_lib0.init_sequence_library();
   endtask

   function void start_of_simulation_phase (uvm_phase phase);
      super.start_of_simulation_phase (phase);
      uvm_config_db#(uvm_sequence_base)::set(this,"m_top_env.m_seqr0.main_phase",
                                                   "default_sequence", m_seq_lib0);
   endfunction
endclass

Here is what this test does:

  • selection_mode is set to UVM_SEQ_LIB_RANDC, so no sequence repeats until all three have run once
  • The library will run at least 5 and at most 10 iterations
  • The three sequences are registered with add_typewide_sequence(), then init_sequence_library() is called again so this existing instance picks them up
  • The library instance is set as the default_sequence of m_seqr0 in main_phase, so the sequencer randomizes and starts it automatically

Note that m_seq1, m_seq2 and m_seq3 are never created. This works because get_type() is a static method, so it can be called through a null class handle.

Output
----------------------------------------------------------------
CDNS-UVM-1.1d (14.10-s013)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test feature_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
------------------------------------------------------------
Name                     Type                    Size  Value
------------------------------------------------------------
uvm_test_top             feature_test            -     @2677
  m_top_env              my_env                  -     @229
    m_drv0               my_driver               -     @2793
      rsp_port           uvm_analysis_port       -     @2893
      seq_item_port      uvm_seq_item_pull_port  -     @2842
    m_seqr0              my_sequencer            -     @223
      rsp_export         uvm_analysis_export     -     @2983
      seq_item_export    uvm_seq_item_pull_imp   -     @3531
      arbitration_queue  array                   0     -
      lock_queue         array                   0     -
      num_last_reqs      integral                32    'd1
      num_last_rsps      integral                32    'd1
------------------------------------------------------------

UVM_INFO ./tb/my_pkg.sv(92) @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Applying initial reset
UVM_INFO ./tb/my_pkg.sv(96) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] DUT is now out of reset
UVM_INFO ./tb/test_pkg.sv(89) @ 390000: uvm_test_top [CFG_PHASE] Add sequence to lib
UVM_INFO ./tb/my_pkg.sv(103) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] Waiting for data from sequencer
UVM_INFO /pkg/cadence-incisiv-/14.10.013/i686-linux/tools/methodology/UVM/CDNS-1.1d/sv/src/seq/uvm_sequence_library.svh(664) @ 390000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0 [SEQLIB/START] Starting sequence library my_seq_lib in main phase: 5 iterations in mode UVM_SEQ_LIB_RANDC
UVM_INFO ./tb/my_pkg.sv(166) @ 390000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq1:1 [seq1] Executing pre_start()
UVM_INFO ./tb/my_pkg.sv(174) @ 390000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq1:1 [SEQ1] Starting seq1
UVM_INFO ./tb/my_pkg.sv(176) @ 400000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq1:1 [SEQ1] Ending seq1
UVM_INFO ./tb/my_pkg.sv(223) @ 400000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:2 [SEQ3] Starting seq3
UVM_INFO ./tb/my_pkg.sv(225) @ 410000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:2 [SEQ3] Ending seq3
UVM_INFO ./tb/my_pkg.sv(233) @ 410000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:2 [seq3] Executing post_start
UVM_INFO ./tb/my_pkg.sv(197) @ 410000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq2:3 [SEQ2] Starting seq2
UVM_INFO ./tb/my_pkg.sv(199) @ 420000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq2:3 [SEQ2] Ending seq2
UVM_INFO ./tb/my_pkg.sv(223) @ 420000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:4 [SEQ3] Starting seq3
UVM_INFO ./tb/my_pkg.sv(225) @ 430000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:4 [SEQ3] Ending seq3
UVM_INFO ./tb/my_pkg.sv(233) @ 430000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq3:4 [seq3] Executing post_start
UVM_INFO ./tb/my_pkg.sv(197) @ 430000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq2:5 [SEQ2] Starting seq2
UVM_INFO ./tb/my_pkg.sv(199) @ 440000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0.seq2:5 [SEQ2] Ending seq2
UVM_INFO /pkg/cadence-incisiv-/14.10.013/i686-linux/tools/methodology/UVM/CDNS-1.1d/sv/src/seq/uvm_sequence_library.svh(738) @ 440000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0 [SEQLIB/END] Ending sequence library in phase main
UVM_INFO /pkg/cadence-incisiv-/14.10.013/i686-linux/tools/methodology/UVM/CDNS-1.1d/sv/src/seq/uvm_sequence_library.svh(740) @ 440000: uvm_test_top.m_top_env.m_seqr0@@m_seq_lib0 [SEQLIB/DSTRB] '{"seq1":1, "seq2":2, "seq3":2}
UVM_INFO ./tb/my_pkg.sv(122) @ 440000: uvm_test_top.m_top_env.m_drv0 [my_driver] Finished DUT simulation

--- UVM Report catcher Summary ---

The log shows the library at work:

  • SEQLIB/START reports that randomization picked 5 iterations, within the 5 to 10 limit, in UVM_SEQ_LIB_RANDC mode
  • The first three iterations run seq1, seq3 and seq2, so each sequence runs once before any repeats, as RANDC requires. A new cycle then starts with seq3 and seq2
  • The suffix in names like seq3:2 is the iteration number, and each sequence runs as a child of m_seq_lib0
  • SEQLIB/DSTRB summarizes how many times each sequence ran, which is useful for checking that a regression exercised every sequence

How Teams Use the Distribution Report

In regression flows, scripts often parse the SEQLIB/DSTRB line across all seeds. If one sequence almost never runs, the team adjusts the selection mode, the iteration limits or the library contents rather than writing new tests.

Common Mistakes

Mistake #1: Adding typewide sequences to an existing instance without re-initializing

Wrong: calling add_typewide_sequence() on a library instance that is already created, and then starting it
Right: call init_sequence_library() again after the additions, as feature_test does

Why? An instance copies the typewide list only when init_sequence_library() runs. Sequences registered with the type afterwards do not appear in existing instances until it is called again.

Mistake #2: Expecting min_random_count and max_random_count to apply with start()

Wrong: setting min_random_count = 20 and max_random_count = 20, then calling start() directly
Right: call randomize() on the library before start(), or set sequence_count directly

Why? The limits only constrain sequence_count during randomization. start() does not randomize the library, so it runs the default 10 iterations. A default sequence is randomized by the sequencer, which is why the limits work in feature_test.

Mistake #3: Forgetting init_sequence_library() in the constructor

Sequences registered with `uvm_add_to_seq_lib are stored in the library type's table. Without init_sequence_library(), a new instance never copies them, so the library starts with an empty list and has nothing to run.

Practice Exercise

Challenge: Run Exactly 20 Random Iterations

Create a library burst_seq_lib of item type my_data that contains seq1 and seq2. In a test's main_phase, run it on m_top_env.m_seqr0 using start(), in UVM_SEQ_LIB_RAND mode, for exactly 20 iterations.

Hint

Setting min_random_count and max_random_count to the same value fixes the count, but only if the library is randomized before start().

Solution

class burst_seq_lib extends uvm_sequence_library #(my_data);
  `uvm_object_utils (burst_seq_lib)
  `uvm_sequence_library_utils (burst_seq_lib)

  function new (string name = "burst_seq_lib");
    super.new (name);
    add_typewide_sequences ({seq1::get_type(), seq2::get_type()});  // Register before init
    init_sequence_library ();                                        // Copy into this instance
  endfunction
endclass

class burst_test extends base_test;
  `uvm_component_utils (burst_test)
  // Rest of the code (constructor, build_phase, etc.)

  virtual task main_phase (uvm_phase phase);
    burst_seq_lib m_lib = burst_seq_lib::type_id::create ("m_lib");
    phase.raise_objection (this);

    m_lib.selection_mode   = UVM_SEQ_LIB_RAND;
    m_lib.min_random_count = 20;        // min = max fixes the count
    m_lib.max_random_count = 20;
    if (!m_lib.randomize ())            // start() does not randomize
      `uvm_fatal ("RAND", "burst_seq_lib randomization failed")

    m_lib.start (m_top_env.m_seqr0);    // Blocks until all 20 iterations finish
    phase.drop_objection (this);
  endtask
endclass

The SEQLIB/START message should report 20 iterations in UVM_SEQ_LIB_RAND mode, and the SEQLIB/DSTRB counts should add up to 20.

Summary

In this tutorial, you learned:

  • A uvm_sequence_library is a sequence that repeatedly selects and runs sequences from a registered list
  • Selection modes RAND, RANDC, ITEM and USER control how each iteration is chosen
  • A library needs `uvm_object_utils, `uvm_sequence_library_utils and init_sequence_library() in its constructor
  • Sequences are added statically with `uvm_add_to_seq_lib, typewide with add_typewide_sequence(), or per instance with add_sequence()
  • The iteration count comes from sequence_count, which the min and max limits constrain only when the library is randomized
  • The SEQLIB/START and SEQLIB/DSTRB messages show the iteration count and how often each sequence ran
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5