Sequence, subsequence, start method

Hello -

I am reading sequences and having lot of doubts. Can anyone answer the following -

(1) suppose I have hierarchy of sequences (each instantiating each other) the start method should be called for which sequence instance?

e.g. seq_a instantiates seq_b; seq_b instantiates seq_c

I assume that we have to call start method for seq_a only.

(2) In one of the Mentor tutorial, it is mentioned that sequences can start sub-sequences.

A sequence may wish to start child sequences or other parent sequences. The sequence can itself start child
sequences.
sub_sequence.start(m_sequence_controller, this,
weighted_priority = 100);

This method is totally different from instantiating a subsequence and then randomizing it.
In this case, the subsequences all send transactions to sequencer. Is this correct?
In case of sub-sequences, the randomization continue until the final sequence is randomized
and the transaction item is sent. Is this correct?

(3) In the same Mentor tutorial, it is also mentioned about starting a parent sequence.
This is something I am not able to understand.

Parent start
After the declarations above are complete, the following code can be used to start a parent sequence. This
should be called from within the run task or some other task that is called when the simulation is in the run
phase.
sequence_a.start(my_sequence_controller, null,
weighted_priority = 100);
This task will return after the sequence is finished.

(4) when a sequence does randomization like this, there is nothing sent to sequencer from the sequence. For example,

virtual task body();
p_sequencer.ovm_report_info(get_type_name(),
$psprintf(“%s starting with count = %0d”,
get_sequence_path(), count), OVM_MEDIUM);
repeat(count) begin : repeat_block
`ovm_do_with(read_byte_seq0,
{ read_byte_seq0.start_addr == start_address;
read_byte_seq0.transmit_del == incr_transmit_del; } )
start_address++;
end : repeat_block
endtask : body

In the above case, the sequence above does not send a transaction item to sequencer.
Is this correct?
If this is true, what happens to send_request call?

Thank you …

Angelo,
Hopefully this will clear your confusion:

(1) All sequences need to be started using the start() method. When you have a sequence which is instantiating a sub-sequence, you call the sub-sequence start() method from within the body() of the main sequence.

(2) Prior to starting a sequence (or sub-sequence), it needs to be created and randomized. You do this a part of your run() task if you are starting the sequence from a test, or in the body() if you are starting from a sequence.

(3) A parent sequence is the sequence which starts() a sub-sequence. If you start a sequence from outside a sequence, then there is no parent sequence.

(4) A sequence can also send sequence_items. The `ovm_do* macros will create, randomize and send the sequence_item. The sequence_item is sent to the driver connected to the sequencer.

Hello Chuck,

I got an idea. Based on the answer, I have some questions. I am trying to explain using an example.

Assume my test starts 3 sequences - seq_a, seq_b, seq_c
The 3 sequences have 2 sub-sequence - seq_a_1, seq_a_2; seq_b_1, seq_b_2;seq_c_1, seq_c_2
Assume that the sequences seq_a, seq_b, seq_c all randomize their sub-sequences.
The sub-sequences seq_a_1, seq_a_2 … all directly interact with their sequencer.

Assume I don’t plan to use the macros and directly use the API’s, what API calls should be called form the body() of seq_a, seq_b, seq_c

We know that seq_a, seq_b, seq_c don’t send any transactions to driver so they don’t have to call wait_for_grant. Is this correct?
Similarly, they don’t have to call send_req?

When the macros are used, how do they know that these called should be skipped?

How does seq_a randomize seq_a_1, seq_a_2 if we don’t use macros?

Please note that I am talking about layer of sequences not layered sequences where there are
multiple sequencers.

Sorry for too many questions but I have too many doubts …

Thank you …

You create and randomize sequence the same way you create any other object:

my_seq_a seq_a;

seq_a = my_seq_a::type_id::create("seq_a");
seq_a.randomize();
seq_a.start(m_sequencer);  // Note that m_sequencer is the current sequencer

The ovm_do_* macros use the create_item(), start_item(), finish_item() methodology which is an alternate set of coding designed to handle either a sequence or sequence_item. If you expand the ovm_do macro, you will see this:

ovm_object_wrapper w_;
 w_ = seq_item.get_type();
    $cast(seq_item , create_item(w_, m_sequencer, "seq_item"));
   end
     start_item(seq_item);
    if(!seq_item.randomize()) begin
      ovm_report_warning("RNDFLD", "Randomization failed in ovm_do action");
    end
    finish_item(seq_item);
    end

The first style is more efficient with respect to sequences. For sequence items, you would use the wait_for_grant() and send_request() calls, or use the create_item/start_item/finish_item method.

The `ovm_do_* macros use the create_item(), start_item(), finish_item() methodology which is an alternate set of coding designed to handle either a sequence or sequence_item.

Can you highlight how the macros know that some API call (e.g. wait for grant) need to be skipped in case a sequence is called and not sequence item? Is there some trick?

There is no trick. The macros will always call create_item(), start_item() and finish_item(), where the parameter to start_item() and finish_item() is the sequence/sequence_item. start_item() and finish_item() will in turn call methods in the sequence/sequence_item. Since ovm_sequence is extended from ovm_sequence_item, it ensures that these methods are unique to the sequence or sequence_item. It is these methods which do the appropriate calls (i.e. start() for the sequence, wait_for_grant(), etc for the sequence item.

Got it. Thank you very much!