Query Regarding Sequence Layering Management

  1. How to Connect multiple sequencers in one lower sequence which is connected with Driver??
    i.e. I am having Sqr1(higher), Sqr2(higher), SeqL(Lower). SqrL is lower one which is running lower sequence, it is connected with Lower Driver which is communicating with DUT pin wiggles. I want to connect Sqr1 and Sqr2 into the Sqr3.
  2. How to connect one higher level sequencer into multiple lower level sequences?
    i.e. I am having one higher sequencer (SqrH), it is connected with two lower level Sequences (seqL1 and seqL2). When i start the higher sequence, these data should be get by any one of the lower sequences depend on my higher sequence logic. But the problem is i couldn’t get the higher layer packets in any of the lower sequencers.

Code Snippet for Question 2:
// Higher Sequence
class high_sequence extends uvm_sequence#(high_packet);

high_packet h_pkt;
task body();
h_pkt.Low_seq1_en = 1;
endtask
endclass

// Lower Sequence 1
class Low_sequence1 extends uvm_sequence#(low_packet1);

uvm_sequencer #(high_packet) SqrH;
high_packet h_pkt;
low_packet1 l_pkt1;
task body();
sqrH.get(h_pkt); // I am not able to get higher layer packet
start_item(l_pkt1);
finish_item(l_pkt1);

sqrH.put(rsp);
endtask
endclass

// Lower Sequence 2
class Low_sequence2 extends uvm_sequence#(low_packet2);

uvm_sequencer #(high_packet) SqrH;
high_packet h_pkt;
low_packet2 l_pkt2;
task body();
sqrH.get(h_pkt); // I am not able to get higher layer packet
start_item(l_pkt2);
finish_item(l_pkt2);

sqrH.put(rsp);
endtask
endclass

If both Lower sequences are trying to get higher layer packets at same time (Sqr.get(item)), which lower sequence will get the higher packets and How to do that?

You should definitely check out the Cookbook and the Advanced UVM video for more information on layered sequences. As to your specific questions:

  1. How to Connect multiple sequencers in one lower sequence which is connected with Driver??
    i.e. I am having Sqr1(higher), Sqr2(higher), SeqL(Lower). SqrL is lower one which is running lower sequence, it is connected with Lower Driver which is communicating with DUT pin wiggles. I want to connect Sqr1 and Sqr2 into the Sqr3.

As I understand it, you have two upstream sequencers, each of which presumably is running one (or more) sequence(s). If SqrL (the sequencer) is connected to your driver, then you need to have two translator sequences running on SqrL, each to communicate with one of the upstream sequencers. Each of these translator sequences will get a transaction from the upstream sequencer and convert it into a “lower_transaction” which is the type that the Lower Driver is expecting. The type of the upstream transactions can be different, as long as each translator sequence is paramterized appropriately.

  1. How to connect one higher level sequencer into multiple lower level sequences?
    i.e. I am having one higher sequencer (SqrH), it is connected with two lower level Sequences (seqL1 and seqL2). When i start the higher sequence, these data should be get by any one of the lower sequences depend on my higher sequence logic. But the problem is i couldn’t get the higher layer packets in any of the lower sequencers.

The important thing to remember about sequence layering is that each layer needs to look like it is communicating with a driver at the lower level. So, when you have

// Higher Sequence
 class high_sequence extends uvm_sequence#(high_packet);
 ....
 high_packet h_pkt;
 task body();
   h_pkt.Low_seq1_en = 1;
 endtask
 endclass

there is no way for the high_sequence to pass a high_packet sequence_item to anybody, since you’ve neglected the start_item()/finish_item() calls.
The other problem you have is that the lower-level sequences are each trying to call get() on the high_sequencer, and the handshakes will get confused. You could implement a semaphore/mutex in high_sequence and have each lower-level translator sequence get the semaphore before calling get, but that makes the translator sequences less reusable.

Please explain why you think you need two lower-level sequences to communicate to a single high_sequence. Are these two lower-level sequences running on the same lower-level sequencer or are they running on different sequencers?

In reply to vadivelan014:

The way you’ve written your higher_default_sequence:

class higher_default_sequence extends uvm_sequence #(higher_packet); 
 `uvm_sequence_utils(higher_default_sequence, higher_sequencer); 
.....

 higher_sequence1 h_seq1;
 higher_sequence2 h_seq2;
 higher_sequence3 h_seq3;
 higher_sequence4 h_seq4;

 task body();
 `uvm_do(h_seq1);
 `uvm_do(h_seq2);
 `uvm_do(h_seq3);
 `uvm_do(h_seq4);
 endtask
 endclass

shows the four sequences running serially (that is, h_seq2 starts after h_seq1 completes, etc.). If that’s all you want to do, then I think you may be overthinking things a bit. It appears that each of your h_seq sequences generates a single h_pkt that the lower_sequences (actually translator sequences, as defined in the Cookbook) use to generate a corresponding lower_packet. Since each h_pkt includes the enable logic for either L1 or L2, it makes no sense to have the two lower_sequences each trying to get from the higher_sequence simultaneously, since it screws up the handshake as you’ve seen.
Instead, you would be better off actually treating higher_default_sequence as a virtual sequence:

class higher_default_sequence extends uvm_sequence #(higher_packet); 
 `uvm_object_utils(higher_default_sequence, higher_sequencer); 
.....
 lower_sequencer1 Lsqr1;
 lower_sequencer2 Lsqr2;

 higher_sequence1 h_seq1;
 higher_sequence2 h_seq2;
 higher_sequence3 h_seq3;
 higher_sequence4 h_seq4;

 task body();
   h_seq1.start(Lsqr1, this);
   h_seq2.start(Lsqr2, this);
   h_seq3.start(Lsqr1, this);
   h_seq4.start(Lsqr2, this);
 endtask
 endclass

Please see the UVM Cookbook for more details on virtual sequences. Notice that we’re not using a virtual sequence**r**, which is unnecessary since you can put the lower_sequencer pointers directly in the virtual sequence.
You’d have to change the definitions of h_seq[1,2,3,4] since they are now running on the lower_sequencers. These now become what we call “worker sequences” (see the Cookbook) which will call the lower_sequence with the appropriate values.
By starting the four sequences one-at-a-time on the lower_sequencers, you should avoid the handshake problem. The downstream layering low sqr1 ↔ low sqr 1a ↔ low sqr 1b ↔ driver ↔ DUT should remain unchanged.
Remember, the key to layering is to make each layer appear that it’s just a sequence/sequencer/driver connection. Since you can’t connect a single sequence to multiple drivers, you can’t have multiple translator sequences talking to the same sequence either.

Other comments on your code:
You’ll notice that I replace uvm_sequence_utils with uvm_object_utils. The sequence utils has been deprecated, as has uvm_update_sequence_lib_and_item. If you really think you need to use a sequence library, please see the [Cookbook](https://verificationacademy.com/cookbook/sequences/sequencelibrary) to learn how to do it, but I don't think you do. You'll also notice that I replaced the uvm_do macros with sequence.start(). The uvm_do macros are evil and we recommend against using them. In your original approach, you would replace the uvm_do macro with

h_seq1.start(m_sequencer, this);

if you really wanted to start h_seq1 on the higher_sequencer. Using my approach, you would have had to change uvm_do to uvm_do_on (I think - I can never keep those macros straight).

Hope this helps.

In reply to tfitz:

Thanks for reply tfitz…
I am having one higher level sequencer(SqrH). It is connected with two lower level sequences(seqL1,seqL2). The two lower level sequences are running in different sequencer (SqrL1, SqrL2). In my case i am having only one interface (lets assume 2 i/p signals and 2 o/p signals).
Lets assume 4 sequences are running in higher sequencer. These 4 sequences will be started by one default sequence in higher sequencer(According to UVM LRM). when i am using one Lower sequencer with that higher sequencer, it is working fine. but when i introduce two lower level sequencers, both lower sequencers are trying to get sequence from higher sequencer. I thing that’s why i couldn’t get the packets in any one of the lower sequencer. Will it be solved by Virtual sequencer?

Code Snippet:

//////////////////////////////////////////////////
// Higher layer packet
//////////////////////////////////////////////////

class higher_packet extends uvm_sequence_item;

rand bit en_L1;
rand bit en_L2;

.....

endclass

//////////////////////////////////////////////////
// Higher layer sequence1
//////////////////////////////////////////////////

class higher_sequence1 extends uvm_sequence #(higher_packet);

task body();
	higher_packet h_pkt, rsp_pkt;
	....
	start_item(h_pkt);
	assert(h_pkt.randomize() with {h_pkt.en_L1 == 1;
                                       h_pkt.en_L2 == 0; });
	finish_item(h_pkt);

	get_response(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Higher layer sequence2
//////////////////////////////////////////////////

class higher_sequence2 extends uvm_sequence #(higher_packet);

task body();
	higher_packet h_pkt, rsp_pkt;
	....
	start_item(h_pkt);
	assert(h_pkt.randomize() with {h_pkt.en_L1 == 0;
                                       h_pkt.en_L2 == 1; });
	finish_item(h_pkt);

	get_response(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Higher layer sequence3
//////////////////////////////////////////////////

class higher_sequence3 extends uvm_sequence #(higher_packet);

task body();
	higher_packet h_pkt, rsp_pkt;
	....
	start_item(h_pkt);
	assert(h_pkt.randomize() with {h_pkt.en_L1 == 1;
                                       h_pkt.en_L2 == 0; });
	finish_item(h_pkt);

	get_response(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Higher layer sequence4
//////////////////////////////////////////////////

class higher_sequence4 extends uvm_sequence #(higher_packet);

task body();
	higher_packet h_pkt, rsp_pkt;
	....
	start_item(h_pkt);
	assert(h_pkt.randomize() with {h_pkt.en_L1 == 0;
                                       h_pkt.en_L2 == 1; });
	finish_item(h_pkt);

	get_response(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Higher layer default sequence
//////////////////////////////////////////////////

class higher_default_sequence extends uvm_sequence #(higher_packet);
/* I configured this default class in test class build phase by using set_config_string(“hsqr”, “default_sequence”, "higher_default_sequence ") and running it in top module using hsqr.start_default_sequence() */

   `uvm_sequence_utils(higher_default_sequence, higher_sequencer);  
.....

higher_sequence1	h_seq1;
higher_sequence2	h_seq2;
higher_sequence3	h_seq3;
higher_sequence4	h_seq4;

task body();
	`uvm_do(h_seq1);
	`uvm_do(h_seq2);
	`uvm_do(h_seq3);
	`uvm_do(h_seq4);
endtask

endclass

//////////////////////////////////////////////////
// Higher layer sequencer
//////////////////////////////////////////////////

class higher_sequencer extends uvm_sequencer #(higher_packet);
`uvm_sequencer_utils(higher_sequencer);

function new(string name = "higher_sequencer", uvm_component parent);
	super.new(name, parent);
	`uvm_update_sequence_lib_and_item(higher_packet)             // Sequence Library Updatation (Default Sequence)
endfunction

endclass

//////////////////////////////////////////////////
// Lower layer 1 packet
//////////////////////////////////////////////////

class lower_packet1 extends uvm_sequence_item;

endclass

//////////////////////////////////////////////////
// Lower layer 1 sequence
//////////////////////////////////////////////////

class lower_sequence1 extends uvm_sequence #(lower_packet1);

uvm_sequencer #(higher_packet) hsqr;
higher_packet hpkt, rsp_pkt;

task body();
	lower_packet1 lpkt1;
	.....
	hsqr.get(hpkt);
	start_item(lpkt1);
	
	if(hpkt.en_L1 == 1)
	begin
		assert(lpkt1.randomize());
		.......
	end

	finish_item(lpkt1);

	get_response(rsp);

	......

	hsqr.put(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Lower layer 1 sequencer
//////////////////////////////////////////////////

class lower_sequencer1 extends uvm_sequencer #(lower_packet1);

endclass

//////////////////////////////////////////////////
// Lower layer 2 packet
//////////////////////////////////////////////////

class lower_packet2 extends uvm_sequence_item;

endclass

//////////////////////////////////////////////////
// Lower layer 2 sequence
//////////////////////////////////////////////////

class lower_sequence2 extends uvm_sequence #(lower_packet2);

uvm_sequencer #(higher_packet) hsqr;
higher_packet hpkt, rsp_pkt;

task body();
	lower_packet2 lpkt2;
	.....
	hsqr.get(hpkt);
	start_item(lpkt2);
	
	if(hpkt.en_L2 == 1)
	begin
		assert(lpkt1.randomize());
		.......
	end

	finish_item(lpkt2);

	get_response(rsp);

	......

	hsqr.put(rsp_pkt);
endtask

endclass

//////////////////////////////////////////////////
// Lower layer 2 sequencer
//////////////////////////////////////////////////

class lower_sequencer2 extends uvm_sequencer #(lower_packet2);

endclass

And finally this lower sequncer 1 will be connected to low sqr 1a , then low sqr 1a will be connected to low sqr 1b which is connected with driver. Lower level sequencer 2 will be connected with low sqr 1b.
when hseq1 or hseq3 is running it should reach the driver through the following path :
hsqr ↔ low sqr1 ↔ low sqr 1a ↔ low sqr 1b ↔ driver ↔ DUT

when hseq2 or hseq4 is running it should reach the driver through the following path :
hsqr ↔ low sqr2 ↔ low sqr 1b ↔ driver ↔ DUT

How can i achieve it? will it possible with virtual sequencer and how??
Thanks…

In reply to tfitz:

Thanks for reply tfitz. I tried your idea, making default sequence as a virtual sequence. but i am getting Fatal Error “default_seq.h_seq1 Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer”. How to solve this error?? Here default_seq is instance of higher_default_sequence in test class.

As per your idea, in virtual sequence,

class higher_default_sequence extends uvm_sequence #(higher_packet);
`uvm_object_utils(higher_default_sequence, higher_sequencer);

lower_sequencer1 Lsqr1;
lower_sequencer2 Lsqr2;

higher_sequence1 h_seq1;
higher_sequence2 h_seq2;
higher_sequence3 h_seq3;
higher_sequence4 h_seq4;

task body();
h_seq1.start(Lsqr1, this);
h_seq2.start(Lsqr2, this);
h_seq3.start(Lsqr1, this);
h_seq4.start(Lsqr2, this);

endtask
endclass

Here, h_seq1 will try to start in Lower sequencer 1, how it is possible?? Because h_seq1 and higher sequencer has same sequence item(h_pkt) but Lower sequencer1 or Lower sequencer2 is having different sequence item (lpkt1 or lpkt2)…I think due to this, I am getting above mentioned error. Please give some to idea to solve this bug…I am having one idea to do it, that is making two agents,
one agent will contain hsqr ↔ low sqr1 ↔ low sqr 1a ↔ low sqr 1b ↔ driver ↔ DUT
and Another agent will contain hsqr ↔ low sqr2 ↔ low sqr 1b ↔ driver ↔ DUT
Now i hope i can control higher sequences using virtual sequence in test.

Is this correct idea or any other easier way is there to do it??
Thank you.

In reply to vadivelan014:

That’s exactly the problem. You can’t run h_seq* parameterized by h_pkt on a sequencer that is expecting lower_pkt. The issue is that this is no longer a standard layering. h_seq1 and h_seq3 should be parameterized with lpkt1 and h_seq2 and h_seq4 should be parameterized with lpkt2. You’ll need to make sure that these sequences call the lower_sequences rather than expecting the lower_sequences to call get().

In reply to tfitz:

Hi tfitz,
I got the source of error, so we cant run sequence in sequencer which is not the same parameterized item (* extends uvm_sequence#(h_pkt) as well as * extends uvm_sequencer #(h_pkt)).
And I am not understanding the last line in your previous comment which is “You’ll need to make sure that these sequences call the lower_sequences rather than expecting the lower_sequences to call get().”… can u explain this?? Thank you.

In reply to vadivelan014:

You want your h_seq sequences to behave as “worker sequences” [see the Cookbook] when running on the lower_sequencers. That means they’ll set values of things in the lower_sequences and call

lower_sequence.start(m_sequencer, this);

In your original design, the lower sequences were “translator sequences” [see the Cookbook] which called the get() methods of the higher_sequencer (which isn’t there anymore) to appear as a driver to the h_seqs.

In reply to tfitz:

Finally my sequence layering works finely with “Worker Sequence & Virtual Sequence”. Thanks a lot tfitz, for your timely help.

In reply to vadivelan014:

You’re welcome.
Glad I could help.