Virtual sequences and virtual sequencers: Part 2

Understanding UVM Sequences: A Two-Part Guide

Virtual Sequences (Vseq) and Virtual Sequencers (Vsqrt)

As we saw in the previous Part 1, to face the multi-controller agent, the first thing to do  will be to make a multi-level hierarchy for the Sequences. In order to ascertain whether a Virtual Sequencer is required, it is necessary to consider three potential scenarios:

  • If you have a single driving agent, you do not need a Virtual Sequencer. (Figure A) 
  • If you have multiple driving agents, but no stimulus coordination is required, you do not need a Virtual Sequencer. (Figure B)
  • If you have multiple driving agents and stimulus coordination is required, you need a Virtual Sequencer. It should be noted that if a testbench with multiple agents and non-coordinated stimulus is ever expanded in the future to require coordinated stimulus, then the environment will require updates to include one or more Virtual Sequencers. These updates, done later in the project, could be quite painful, as opposed to building in a Virtual Sequencer from the beginning and using it as needed. Engineers should make it a habit to add the Virtual Sequencer to most of their UVM testbenches. (Figure C)

Figures show when Virtual Sequences are required.

In the case of Figure A and B there's no need to implement a Virtual Sequencer. For scenario A, since there is only one agent responsible for generating stimuli and sending them to the DUT, there is no need for coordination between Sequencers or Agents.

For scenario B, although there are multiple Agents, since there is no need for stimuli coordination, there is also no need to implement the Virtual Sequencer.

 

Figure A (left) and B (right)

In the case of Figure A and B there's no need to implement a Virtual Sequencer. For scenario A, since there is only one agent responsible for generating stimuli and sending them to the DUT, there is no need for coordination between Sequencers or Agents.

For scenario B, although there are multiple Agents, since there is no need for stimuli coordination, there is also no need to implement the Virtual Sequencer. 

Figure C

Figure C illustrates the role of a Virtual Sequencer in coordinating the activities of multiple agents.

Multi-Driver control

The communication architecture between a Driver, Sequencer, Sequence item, and Sequence is designed to work through an interface. In a typical testbench, it is often necessary to handle multiple transactions across multiple interfaces while maintaining coordination between them. This could be achieved using one of two approaches:

  • The Virtual Sequence will contain itself the handles of the Agent’s Sequencers on which the Sub-Sequences are to be executed.
  • Through Virtual Sequencers, Virtual Sequence will run on a Virtual Sequencer which is of type uvm_sequencer. In this approach, Virtual Sequencer will contain the target Agent Sequencer’s handle.
Figure D- First approach
Figure E- Second approach

As you can see from the images, there are two common ways to use Virtual Sequences. The first approach is where the Virtual Sequence holds the Sequences to be used on their respective Sequencers. In this blog we will focus on the second approach, where the Virtual Sequences hold a Virtual Sequencer to coordinate and send their Sequences.

Virtual Sequences and Virtual Sequencers are understood as "Virtual" because of the way they interact with each other (Sequencers and Sequences) and their interaction with Drivers. They do not carry the "Virtual" name like some other methods or classes. UVM does not have a class called virtual_sequence or virtual_sequencer.

Virtual Sequences are therefore at a higher level in the Sequence hierarchy and will contain the Sequences to be used. These Sequences, in turn, control the stimulus using Virtual Sequencers.

Virtual Sequences start in the Virtual Sequencer and send the Sequences to the different Sequencers.

Virtual Sequencers differ from regular Sequencers in:

  • Control other Sequencers
  • Are not directly connected to the Drivers
  • Do not process independently

Sequences typically do not run directly on Virtual Sequencers; instead, they run on sub-Sequencers, which then manage the Sequences. Virtual Sequencers are responsible for coordinating Sequences among the sub-Sequencers. They are recommended in verification environments because they facilitate the use and stimulation of multiple signals in the long term. Also, the type of transaction associated with Virtual Sequences is generally not important because they typically do not create transactions. Another interesting fact is that, if a Virtual Sequence does not generate sequence_items, it does not require a Sequencer to run on.

Implementation details

For the implementation of Virtual Sequencers, there are three general ways: "Business as usual" (known as  parallel traffic generation), Disable sub-Sequencers and using grab() and ungrab(). In this blog we will focus on Business as usual.

As we mentioned before, a Virtual Sequencer is a component which provides us with the references to the sub-Sequencers and all the tools necessary to configure the Virtual Sequences. It can also be seen as a container where all the sub-Sequencers, handlers and common configuration variables are stored.

The example provided is a common declaration of a Virtual Sequencer. Here we can see that the class inherits from the uvm_sequencer and there is no need to parametrize the class to a transaction type. Since it isn't parametrized, the Sequencer is going to use the parameterized values for a uvm_sequence item by default.

In the Virtual Sequencer, the handles to the sub-Sequencers are declared. These handles can be connected to the Sequencers of their respective agents through the uvm_config_db in the end_of_elaboration_phase(), as previously set in the database, as shown in the example.

Example 1

 Another valid option is to connect the references of the Sequencers of the instantiated agents to the Sequencers of the Virtual Sequencer within the environment:

Example 2

Sequence initialization

As we have already seen, the Virtual Sequence will extend from the uvm_sequence class and will contain the Sequences to be used. However, when we talk about its execution, we see that Sequencers and execution modes are involved. The following example attempts to clarify this by showing how to configure and start the Virtual Sequence in the environment.

In the example 3, variables m_clkndata_agent and m_serial_agent are used within the class top_default_seq so that the Sequencers for the Sequences can be found later.

Creation of the Virtual Sequence:

  • top_default_seq vseq;: Declares a variable vseq of type top_default_seq, which is a class that extends uvm_sequence.
  • vseq = top_default_seq::type_id::create("vseq");: The sequence is instantiated using the type_id::create() method, which is a standard way in UVM to create an object of a class, ensuring it adheres to factory patterns. The string "vseq" is used as an identifier.

Randomization:

  • if (!vseq.randomize()): The Sequence is randomized using the randomize() method. This step is crucial to generate random stimuli based on the constraints defined within the Sequence.
  • uvm_error(get_type_name(), "Failed to randomize sequence");: If randomization fails, an error is reported using UVM’s built-in reporting mechanism.

Setting Agent Handles:

  • vseq.m_clkndata_agent = m_clkndata_config;: The handle m_clkndata_agent within the sequence is set to m_clkndata_config. This step is necessary to connect the Virtual Sequence with the specific sequencers or configurations within the environment.
  • vseq.m_serial_agent = m_serial_agent;: Similarly, another agent handle is connected, ensuring that the Virtual Sequence can control or interact with the corresponding Sequencers.

Starting Phase Association:

  • vseq.set_starting_phase(phase);: The starting phase of the Sequence is set using set_starting_phase(). This ties the Sequence’s execution to a specific phase in the UVM run-time schedule, ensuring it starts at the correct point in the simulation.

Starting the Sequence:

  • vseq.start(null);: The Sequence is started using the start() method. The argument null indicates that the sequence is not directly tied to a specific Sequencer at this point. However, typically, this could be a reference to a Sequencer if needed (e.g., vseq.start(sequencer);).
Example 3

Overview

In the creation of a verification environment, the use of Virtual Sequences and Sequencers is recommended for the coordination and management of multiple signals. 

The main difference between the two methods of using Virtual Sequences is that the Virtual Sequencer approach is a fixed implementation that is very tightly coupled to the local hierarchy of an environment, and adds complications with vertical reuse, whereas with the other method you give up the use of Virtual Sequencer methods on the sequences as the arbitration mechanism.

In the design of a testbench, the environment is created in the base test, where the Virtual Sequencer to be used is instantiated, and the basic Virtual Sequences that will utilize this Sequencer are created. Then, for each particular test, the same test base is extended and the extended base Sequences are connected and initialized with the Virtual Sequencer created in the environment through a start. 

When we have a large project, it is advisable to use Virtual Sequencers because they allow the use of coordinated stimulus, and although a coordinated stimulus is not needed at first, it may be needed at later steps in the project.

By Diaz Miguez Lucas and Doctorovich Juan

Design Verification Engineers at Emtech S.A.

Thanks, Ruben Rodriguez and  Marcelo Pouso for their valuable feedback and insightful reviews.

—-------------------------------------------------------------------------------------------------

Any Comments or questions, please feel free to contact us: info@emtech.com.ar