How to to run multiple sequences on single sequencer - fork join or sequence arbitration?

Hi,

I have the following question to sum multiple sequences using a single sequencer.
For a single sequencer, there are 3 sequences (A,B,C) trying to get driven with different delays for each sequence.
All the sequences are started in parallel using fork-join. The conditions for sequences are as follows:

  1. Seq A delay < B delay < C delay
  2. C is a power sequence which will be ON/OFF on consecutive executions
  3. When C gets initiated, A will pause and resume when C is done.
  4. For eg; if I want to generate the sequence pattern as AABACBBBCABBA for the sequences to be executed in this order, how am I supposed to write the code.

(Assume A takes 5ns, B takes 10ns and C takes 20ns to complete for convenience.)
Does simple fork join techniques be sufficient or do I have to use UVM sequence arbitration mechanisms or methods like grab()/ungrab().
Any thoughts and code is appreciated.

Thanks,
Sruthi.

Here is the sample code I am working on:

class main_seq extends uvm_sequence #(my_txn);

  //factory registration
  `uvm_object_utils(main_seq)

 /// Sub-sequences class handle declaration
 sub_seq A, B, C;

 /// Constructor 
  function new(string name = "main_seq");
  super.new(name);
 endfunction: new

 
task body;
  A = arb_seq::type_id::create("A");
  A.seq_no = 1;
  B = arb_seq::type_id::create("B");
  B.seq_no = 2;
  C = arb_seq::type_id::create("C");
  C.seq_no = 3;

// AABACBBBCABBA
//Assuming A takes 5, B takes 10 and C takes 15 to finish.
 m_sequencer.set_arbitration(UVM_SEQ_ARB_USER);
     
fork
  begin
    A.start(m_sequencer, this, 300);
    #5;
  end
join_any
wait fork
      
fork
  begin
    B.start(m_sequencer, this, 200);
    #10;
  end
join_none
  
fork
  begin
    C.start(m_sequencer, this, 100); 
    #20;
  end
join_none

endtask: body

endclass: master_seq

In reply to sruthikrapa:

I would highly recommend removing all # delay statements from your sequences. All UVM code should be untimed with the exception of driver code. You should instead make any delay requirements part of your sequence items (i.e. wait ‘x’ number of clock cycles before or after the transaction).

By doing this, you don’t worry about when a sequence or sequence_item will complete. You simply start() the sequence and when it finishes, you start the next sequence.

In reply to cgales:

Hi cgales,

Thank you for the response.
Please help me out in tweaking the above code if possible so that it will meet the requirements for all the 3 sequences.

Regards,
Sruthi.

In reply to sruthikrapa:

It’s not clear what your requirements are. When you state that the sequence pattern should be ‘AABACBBBCABBA’, does this mean execute sequence A two times, then sequence B, then sequence A, then C? Or does it mean to send one sequence_item from the specified sequence?

If you want the entire sequence to run, then you should use a sequential series of start() calls in the order that you want the sequences executed.

If each sequence is a loop that sends out a number of sequence_items and you want to interleave the items, then you should fork() all three sequences and use a sequencer arbitration scheme which will meet your needs. You need to remember that the sequencer will re-arbitrate the active sequence when get_next_item() is called by the driver.

In reply to cgales:

In reply to sruthikrapa:
Hi Cgales,
Please see my inline responses below.
It’s not clear what your requirements are. When you state that the sequence pattern should be ‘AABACBBBCABBA’, does this mean execute sequence A two times, then sequence B, then sequence A, then C? Or does it mean to send one sequence_item from the specified sequence?
Yes, I want sequence A to execute 2 times then sequence B and so on. But all sequences have to start in parallel. Sequence C is a power related sequence. The only condition is that A needs to be suspended when C executes and A needs to be resumed back when C starts again.
AABA (A is executing but C started) C (A is suspended here until C is executed again) BBBC (A resumed back here) ABBA
This is how C works:
power-on C power-off C power-on C power-off C power-on and so on…
If you want the entire sequence to run, then you should use a sequential series of start() calls in the order that you want the sequences executed.
If each sequence is a loop that sends out a number of sequence_items and you want to interleave the items, then you should fork() all three sequences and use a sequencer arbitration scheme which will meet your needs. You need to remember that the sequencer will re-arbitrate the active sequence when get_next_item() is called by the driver.

Yes, this is what I am trying to do in my above code. But I am not sure how exactly to use the fork join in this case with respect to sequence arbitration.

Thanks,
Sruthi.

In reply to sruthikrapa:

Your requirements are still not clear. You can have one sequence execute to completion, then the next sequence execute to completion. When you want this to happen, you don’t start the sequences in parallel.

The other approach is to have sequence A send one sequence_item, then sequence B send one sequence_item, and then continue in some random pattern. In this case, you would have the sequences run in parallel.

Perhaps if you post code showing the actual sequences we can get a better understanding of what you are trying to accomplish. Your example shows three of the same sub-sequences, which doesn’t match what you are saying.

In reply to sruthikrapa:

I think this will generate random combination of three sequence items , assuming arb_seq have N number of sequence items. Delay you can put inside the arb_seq, you can control it depending on seq_no.

It will be more clear if you put arb_seq definition too


task body;
  A = arb_seq::type_id::create("A");
  A.seq_no = 1;
  B = arb_seq::type_id::create("B");
  B.seq_no = 2;
  C = arb_seq::type_id::create("C");
  C.seq_no = 3;

 
fork
  begin
    A.start(m_sequencer, this);
  end
  begin
    B.start(m_sequencer, this);
  end
  begin
    C.start(m_sequencer, this); 
  end
join
 
endtask: body