How Virtual Sequence Works? – Part 2

Hi Friends, Welcome for the Part 2 of our discussion about “How Virtual Sequence Works?“. I believe you’ve gone through my post “How Virtual Sequence Works? – Part 1” where we got to know about Sequence Hierarchy, Virtual Sequence & different approaches of Virtual Sequence Implementation. My recommendation is to go through “Part 1” if you haven’t already done so.

As you know from Part 1 that we’re going to discuss the 2nd approach of the Virtual Sequence Implementation in this post, Let me restate here again the different Virtual Sequence Implementation approaches before jumping into the details of the 2nd approach.

In UVM, Virtual Sequence can be implemented using 2 approaches.

  • In the 1st approach, Virtual Sequence will contain itself the handles of the Agent’s Sequencers on which the Sub-Sequences are to be executed.
  • In the 2nd approach, 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.

Now, lets dive deep into the 2nd approach.

Virtual Sequence Implementation (2nd approach):

To understand the 2nd approach in a better way, first its important to understand about Virtual Sequencer.

Virtual Sequencer is a Sequencer that is not connected to the UVM Driver itself, but contains the handles of the target Sequencer in the Testbench hierarchy.

In the Diagram 1 below, there is an example UVM Testbench environment to show the Virtual Sequencer’s application and 2nd approach of Virtual Sequence Implementation:

Virtual_Seq_2nd_Approach

Diagram 1: Virtual Sequence Implementation (2nd approach)

As shown in the above diagram, Virtual Sequencer is the part of the Environment i.e. “Env”. Virtual Sequencer contains the handles of the target Sequencers i.e. & which are physically located inside the Agents i.e. AHB Agent & AXI Agent respectively. These target Sequencers handles assignment will be done during connect phase of the Environment class.

Virtual Sequence is located outside the Environment class & it is created in the run_phase() method of the Test. The Virtual Sequence is designed to run on the Virtual Sequencer & Virtual Sequence also gets the handles of the target Sequencers from the Virtual Sequencer.

Note: It’s a good practice to give names to the handles which test writer could understand easily.

Lets see the applicable UVM code for the Virtual Sequence Implementation, 2nd approach, as shown below:

///// Virtual Sequencer Class
class virtual_seqr extend uvm_sequencer;
 `uvm_component_utils(virtual_seqr)
 
 /// Target Sequencer Handles
  ahb_seqr SQR_AHB;
  axi_seqr SQR_AXI;
 
 /// Constructor
 function new (string name = "virtual_seqr", uvm_component parent);
  super.new(name, parent);
 endfunction: new
 
endclass: virtual_seqr

Virtual Sequencer i.e. “virtual_seqr” class is declared by extended the UVM base class uvm_sequencer. Target Sequencer handles are also declared inside it.

Now lets see the implementation of the Virtual Sequence. First a Base Virtual Sequence will be declared & later Virtual Sequence will be derived from the base virtual sequence. Lets see how its being done:

///// Base Virtual Sequence
class base_vseq extends uvm_sequence #(uvm_sequence_item);
 `uvm_object_utils(base_vseq)
 
 /// Virtual Sequencer Handle
 virtual_seqr v_sqr;
 
 /// Target Sequencers Handle
 ahb_seqr SQR_AHB;
 axi_seqr SQR_AXI;
 
 /// Constructor
 function new (string name = "base_vseq");
  super.new(name);
 endfunction: new
 
 /// Body Task (Assign target sequencers handle)
 task body();
  if (!$cast(v_sqr, m_sequencer)) begin
   `uvm_error(get_full_name(), "Virtual Seqr pointer cast failed")
  end
  SQR_AHB = v_sqr.SQR_AHB;
  SQR_AXI = v_sqr.SQR_AXI;
 endtask: body
 
endclass: base_vseq

///// Virtual Sequence
class my_vseq extends base_vseq;
 `uvm_object_utils(my_vseq)
 
 /// Constructor
 function new (string name = "my_vseq");
  super.new(name);
 endfunction: new
 
 /// Body Task(starting the sub-sequences)
 task body();
 
  /// Assigning the Sub-Sequencer Handles
  super.body;
  /// Sub-Sequence Creation & Execution
  ahb_sequence ahb_seq;
  axi_sequence axi_seq;
 
  ahb_seq = ahb_sequence::type_id::create("ahb_seq");
  axi_seq = axi_sequence::type_id::create("axi_seq");
 
  repeat(30) begin
   ahb_seq.start(SQR_AHB);
   axi_seq.start(SQR_AXI);
  end
 
 endtask: body
 
endclass: my_vseq

Now its turn to see the UVM code for the Environment class which instantiates Virtual Sequencer as well as both the Agents.

///// Environment Class
class Environ extends uvm_env;
 `uvm_component_utils(Environ)
 
 /// Virtual Sequencer Handle
 virtual_seqr v_sqr;
 
 /// Agents Handles
 ahb_agent AHB_AGNT;
 axi_agent AXI_AGNT;
 
 /// Constructor
 function new (string name = "Environ", uvm_component parent);
  super.new(name, parent);
 endfunction: new
 
 /// Build Phase
 function void build_phase (uvm_phase phase);
  v_sqr = virtual_seqr::type_id::create("v_sqr");
  AHB_AGNT = ahb_agent::type_id::create("AHB_AGNT");
  AXI_AGNT = axi_agent::type_id::create("AXI_AGNT");
 endfunction: build_phase
 
 /// Connect Phase
 function void connect_phase (uvm_phase phase);
  v_sqr.SQR_AHB = AHB_AGNT.m_sequencer;
  v_sqr.SQR_AXI = AXI_AGNT.m_sequencer;
 endfunction: connect_phase
 
endclass: Envrion

In the above Environment class i.e. “Environ”, Virtual Sequencer is instantiated & built along with two Agents i.e. “AHB_AGNT” & “AXI_AGNT”. Target Sequencer handles are also assigned in the connect_phase(). Usage of a flexible & handy feature of UVM i.e. “m_sequencer” is being shown which by default points to the UVM Sequencer derived from the uvm_sequencer.

Finally lets see how the Virtual Sequence is started on the Virtual Sequencer from the Test:

///// Main Test
class Test extends uvm_test;
 `uvm_component_utils(Test)
 
 /// Instantiations
 my_vseq vseq;
 Environ Env;
 /// Constructor
 function new (string name = "Test", uvm_component parent = null);
  super.new(name, parent);
 endfunction: new

 /// Build Phase
function void build_phase (uvm_phase phase);
   Env  = Environ::type_id::create("Env");
endfunction: build_phase
 
 /// Run Phase
 task run_phase (uvm_phase phase);
  /// Create the Virtual Sequence & Environment
   vseq = my_vseq::type_id::create("vseq");
   phase.raise_objection(this);
  /// Start the Virtual Sequence
  vseq.start(Env.v_sqr);
  phase.drop_objection(this);
 endtask: run_phase

endclass: Test

In the Test class i.e. “Test”, both Environment & Virtual Sequence i.e. “Environ” & “my_vseq” are instantiated and created. Finally Virtual Sequence is started on the Virtual Sequencer which exists inside the Environment.

So thats how, the Virtual Sequence can be implemented using the 2nd approach in UVM.


With this, We reached to the concluding part of the topic “How Virtual Sequence Works?”. In fact we covered “How Virtual Sequences can be Implemented?” as well. I hope it will provide you the value which I want to share with you. Please keep sharing your comments, inputs & suggestions. I feel happy hearing from you.

I’ll meet you with a new post soon. Keep visiting for other topics! Till then..take care, bye!