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.