Virtual sequences and sequencers in UVM are just virtual containers of multiple sequences and sequencers.
Using virtual sequencers and sequences can be done in these three ways:
Using virtual sequencers and sequences can be done in these three ways:
- Using only virtual Sequence and handles of sequencers inside the virtual sequence.
- Using Virtual sequencer to hold the sequencers
- Same as step 2, by using uvm_declare_p_sequencer.
Virtual Sequencer does not create any sequencer objects, rather it points to other physical sequencers in different agents.
Virtual Sequencer extends from uvm_sequencer.
Virtual sequence will create its sequences and start them. Running sequences can be controlled by user in the body() task.
virtual sequence extends from uvm_sequence.
METHOD-1:
In this method, we will have one base virtual sequence which will hold the handles to different sequencers. Here we dont use any virtual sequencer. We just use the nested seqeunces with handles ot sequencers inside sequence itself.
//This is the base virtual sequence. class v_seq_base extends uvm_sequence; `uvm_object_utils(v_seq_base) //Declare the sequencer handles. //This is two types of sequencer declaration. //One with using parameterized uvm_sequencer uvm_sequencer#(seq_item_1) seqr1; //Second with direct sequencer type. This may be less reusable when there are multiple sequencers in agent. seqr_2 seqr2; function new(string name='v_seq_base'); super.new(name) endfunction endclass //Sequence class class v_seq1 extends v_seq_base; `uvm_object_utils(v_seq1) function new(string name='v_seq1'); super.new(name) endfunction //Body virtual task body(); //Create child sequences. //They can be different type of sequences, that you chose to run on the sequencers inside the virtual sequencer. sequence1 seq1; sequence2 seq2; seq1 = sequence1::type_id::create('seq1'); seq2 = sequence2::type_id::create('seq2'); fork begin seq1.start(seqr1); seq2.start(seqr2); end endtask endclass //Connecting sequencers and starting sequences. class base_test extends uvm_test; `uvm_component_utils(base_test); //Your Env. Test_env env; function new(string name='base_test',uvm_component parent = null); endfunction function build_phase(uvm_phase phase); env = Test_env::type_id::create('env'); endfunction function set_seqr(v_seq_base v_seq); v_seq.seqr1 = env.agent1.seqr_handle; v_seq.seqr2 = env.agent2.seqr_handle_x; endfunction endclass //Main Test class test1 extends base_test; `uvm_component_utils(test1) function new(string name='test1',uvm_component parent = null); endfunction //No build phase explicitly required as parent already has it. task run_phase(uvm_phase phase); //Create the sequence phase.raise_objection(); v_seq1 v_seq; vseq = v_seq1::type_id::create('v_seq'); //SEt the virtual sequencer handles. set_vseq(v_seq); //Start sequence. v_seq.start(null); phase.drop_objection(); endtask endclass
METHOD-2:
In this method we will use the virtual sequencer. A virtual sequencer is just a normal uvm_sequencer which holds the handles to different sequences.
In this method we will use the virtual sequencer. A virtual sequencer is just a normal uvm_sequencer which holds the handles to different sequences.
//Create a virtual sequencer class v_seqr extends uvm_sequencer; //Create the sub seqeuncer handles. //This is two types of sequencer declaration. //One with using parameterized uvm_sequencer uvm_sequencer#(seq_item_1) seqr1; //Second with direct sequencer type. This may be less reusable when there are multiple sequencers in agent. seqr_2 seqr2; //Constructor function new(string name='v_seqr', uvm_component parent); endfunction endclass //This is the base virtual sequence. class v_seq_base extends uvm_sequence; `uvm_object_utils(v_seq_base) //create virtual sequencer handle v_seqr v_seqr1; function new(string name='v_seq_base'); super.new(name) endfunction //Body task body(); //Assign the virtual sequencer.. //Get the sequencer this is running on.(the actual object) if(!$cast(v_seqr1, m_sequencer)) begin `uvm_error(get_full_name(), "Virtual Sequencer casting Faled"); end endtask endclass //Sequence class class v_seq1 extends v_seq_base; `uvm_object_utils(v_seq1) function new(string name='v_seq1'); super.new(name) endfunction //Body task body(); //Call super.body to get the v_seqr handle. super.body(); //Create child sequences. //They can be different type of sequences, that you chose to run on the sequencers inside the virtual sequencer. sequence1 seq1; sequence2 seq2; seq1 = sequence1::type_id::create('seq1'); seq2 = sequence2::type_id::create('seq2'); fork begin seq1.start(v_seqr1.seqr1); seq2.start(v_seqr1.seqr2); end endtask endclass //Connecting sequencers and starting sequences. class base_test extends uvm_test; `uvm_component_utils(base_test); //Declare the virtual sequencer. You can chose to place the sequencer in the environment too. v_seqr v_sqr; //Your Env. Test_env env; function new(string name='base_test',uvm_component parent = null); endfunction function build_phase(uvm_phase phase); env = Test_env::type_id::create('env'); v_sqr = v_seqr::type_id::create('v_sqr'); endfunction function connect_phase(uvm_phase phase); v_sqr.seqr1 = env.agent1.seqr_handle; v_sqr.seqr2 = env.agent2.seqr_handle_x; endfunction endclass //Main Test class test1 extends base_test; `uvm_component_utils(test1) function new(string name='test1',uvm_component parent = null); endfunction //No build phase explicitly required as parent already has it. task run_phase(uvm_phase phase); //Create the sequence phase.raise_objection(); v_seq1 v_seq; vseq = v_seq1::type_id::create('v_seq'); //Start virtual sequence on virtual sequrncer v_seq.start(v_sqr); phase.drop_objection(); endtask endclass
METHOD-3:
In this method, is pretty much similar to the method-2, but we declared virtual_sequencer handle manually and then type casted it. But UVM provides a way to create handle of specified sequencer
uvm_declare_p_sequencer(X) will create handle of type X.
When that sequence is called, it will take the m_sequencer and casts it to p_sequencer. In short this is the code it executes when sequence is called.
$cast(p_sequencer, m_sequencer)
Hope this explains well about usage of virtual sequences and sequencers.
In this method, is pretty much similar to the method-2, but we declared virtual_sequencer handle manually and then type casted it. But UVM provides a way to create handle of specified sequencer
uvm_declare_p_sequencer(X) will create handle of type X.
When that sequence is called, it will take the m_sequencer and casts it to p_sequencer. In short this is the code it executes when sequence is called.
$cast(p_sequencer, m_sequencer)
//Create a virtual sequencer class v_seqr extends uvm_sequencer; //Create the sub seqeuncer handles. //This is two types of sequencer declaration. //One with using parameterized uvm_sequencer uvm_sequencer#(seq_item_1) seqr1; //Second with direct sequencer type. This may be less reusable when there are multiple sequencers in agent. seqr_2 seqr2; //Constructor function new(string name='v_seqr', uvm_component parent); endfunction endclass //This is the base virtual sequence. class v_seq_base extends uvm_sequence; `uvm_object_utils(v_seq_base) //Use uvm method to declare and get the virtual sequencer handle. //This will assign the sequencer on which this sequence is called to p_sequencer and casts it to the v_seqr. `uvm_declare_p_sequencer(v_seqr) function new(string name='v_seq_base'); super.new(name) endfunction endtask endclass //Sequence class class v_seq1 extends v_seq_base; `uvm_object_utils(v_seq1) function new(string name='v_seq1'); super.new(name) endfunction //Body task body(); //Create child sequences. //They can be different type of sequences, that you chose to run on the sequencers inside the virtual sequencer. sequence1 seq1; sequence2 seq2; seq1 = sequence1::type_id::create('seq1'); seq2 = sequence2::type_id::create('seq2'); fork begin seq1.start(p_sequencer.seqr1); seq2.start(p_sequencer.seqr2); end endtask endclass //Connecting sequencers and starting sequences. class base_test extends uvm_test; `uvm_component_utils(base_test); //Declare the virtual sequencer. You can chose to place the sequencer in the environment too. v_seqr v_sqr; //Your Env. Test_env env; function new(string name='base_test',uvm_component parent = null); endfunction function build_phase(uvm_phase phase); env = Test_env::type_id::create('env'); v_sqr = v_seqr::type_id::create('v_sqr'); endfunction function connect_phase(uvm_phase phase); v_sqr.seqr1 = env.agent1.seqr_handle; v_sqr.seqr2 = env.agent2.seqr_handle_x; endfunction endclass //Main Test class test1 extends base_test; `uvm_component_utils(test1) function new(string name='test1',uvm_component parent = null); endfunction //No build phase explicitly required as parent already has it. task run_phase(uvm_phase phase); //Create the sequence phase.raise_objection(); v_seq1 v_seq; vseq = v_seq1::type_id::create('v_seq'); //Start virtual sequence on virtual sequrncer v_seq.start(v_sqr); phase.drop_objection(); endtask endclass
Hope this explains well about usage of virtual sequences and sequencers.
Nice explanation Venky.
ReplyDelete