State of the sequence after it has been killed

Hi,

Suppose I started a sequence on a sequencer in a test.
And, if specific condition is met, the sequence kills itself.
But when I try to start the sequence on the sequencer again, I get SEQ_NOT_DONE error.

UVM_FATAL @ 0: uvm_test_top.env.agent.sequencer@@seq [SEQ_NOT_DONE] Sequence uvm_test_top.env.agent.sequencer.seq already started

To simplify the issue, I’ve made my sequence always kill itself.

task my_sequence::body();
  this.kill();
endtask: body

In order for sequence to be started, looks like its state should be either CREATED, STOPPED or FINISHED.
I expected that the state will be STOPPED after it’s been killed, but it’s actually BODY.
So the sequence could not be started again.

task my_test::run_phase(uvm_phase phase);
  super.run_phase(phase);

  phase.raise_objection(this);
  
  // sequence state is CREATED
  // successfully started and kills itself (no problem so far)
  seq.start(env.agent.sequencer);
  
  // sequence state is BODY (not STOPPED)
  // failed to start the sequence (SEQ_NOT_DONE error)
  seq.start(env.agent.sequencer);

  phase.drop_objection(this);
endtask: run_phase

Below is from uvm_sequence_base.svh of UVM-1.1d.
There is a line that changes state to STOPPED but it wasn’t executed.

function void m_kill();
  do_kill();
  foreach(children_array[i]) begin
     i.kill();
  end
  if (m_sequence_process != null) begin
    m_sequence_process.kill; // <-- last executed statement
    m_sequence_process = null;
  end
  m_sequence_state = STOPPED; // <-- could not reach here
  if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this)))
    m_parent_sequence.children_array.delete(this);
endfunction

Could anyone point out what I’m missing here?

Best regards,
Jung Ik Moon

In reply to Jung Ik Moon:

In reply to Jung Ik Moon:

You are trying to start the same sequence twice at the same time. This does not work.
See the error message (fatal):
UVM_FATAL @ 0: uvm_test_top.env.agent.sequencer@@seq [SEQ_NOT_DONE] Sequence uvm_test_top.env.agent.sequencer.seq already started

In reply to chr_sue:

Thanks for the answer.
But, as far as I understand, it’s okay to start the same sequence twice (sequentially) as long as its state is CREATED, STOPPED or FINISHED.
For example, if I comment out ‘this.kill();’ from my example sequence, there will be no error. And that covers both CREATED case and FINISHED case.

virtual task start (uvm_sequencer_base sequencer,
                    uvm_sequence_base parent_sequence = null,
                    int this_priority = -1,
                    bit call_pre_post = 1);

  set_item_context(parent_sequence, sequencer);

  if (!(m_sequence_state inside {CREATED,STOPPED,FINISHED})) begin
    uvm_report_fatal("SEQ_NOT_DONE", 
       {"Sequence ", get_full_name(), " already started"},UVM_NONE);
  end

  // ...

endtask

My question is “why doesn’t my sequence move to STOPPED state after it has been killed?”.

In reply to Jung Ik Moon:

This is very easy. Because calling the start method in the test is not blocking. The 2nd call does not wait until the first has been executed.

In reply to chr_sue:

Not sure if that’s true.
The 2nd call will not be executed until the 1st one is either finished or killed.

In reply to Jung Ik Moon:

You are right. see here:

But note the kill is in the test and not in the body task of your sequence.

In reply to chr_sue:

Your example kills already finished sequence.
Yeah, that’s not the important thing here.
I understand what you were trying to say.

I can kill the sequence in the test rather than in the sequence.
I can also achieve the same by calling stop_sequences() of the sequencer.
In both cases, the state of the sequence successfully moves to STOPPED.
And can be executed again at the second call.

However, in my case, the sequence itself is the one who knows whether to kill it or not.
So I actually would like to kill the sequence “in the sequence”.
Also, I do not want to add dependency on the test and make things more complex.

And, whatever the reason may be, I want to know why the sequence state does not move to STOPPED when kill() is called in the sequence.

In reply to Jung Ik Moon:

if you dig a little bit deeper into source code you will see why.

m_sequence_process is the process forked once you enter body() task.

this.kill() will call m_kill() which will set m_sequence_state = UVM_STOPPED, and then you could restart your sequence again ideally.

but notice inside m_kill() before setting m_sequence_state = UVM_STOPPED, it killed m_sequence_process first by calling m_sequence_process.kill. so the m_sequence_state = UVM_STOPPED part never gets executed because the parent thread “commit suicide”. That’s why it won’t let you re-start, because if you print out the m_sequence_state of seq, it will show as UVM_BODY.

 914   function void m_kill();                                                       
 915     do_kill();                                                                  
 916     foreach(children_array[i]) begin                                            
 917        i.kill();                                                                
 918     end                                                                         
 919     if (m_sequence_process != null) begin                                       
 920       m_sequence_process.kill;         // killed itself !!!                                         
 921       m_sequence_process = null;                                                
 922     end                                                                         
 923     m_sequence_state = UVM_STOPPED;                                             
 924     if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this)))
 925       m_parent_sequence.children_array.delete(this);                            
 926   endfunction

in conclusion, you may want to delegate the “kill” task to someone that is not thread of body() nor child thread of body().

In reply to Jeff_Li_90:

Thanks for the answer.
I actually did get to the point where you mentioned.
But I could not understand “why”.

Maybe I should change my question this way:
“Why doesn’t UVM guarantee that the sequence state change to STOPPED when the sequence kills itself?
Or is this intended? If so, what could be the reason for that?”

In reply to Jung Ik Moon:

I guess the way it codes indicates that killed() is never supposed to be called by sequence itself. If you wanna terminate sequence inside body() there’re many other ways also.

In reply to Jeff_Li_90:

Hmm… I see.
Seems like sequence killing itself is not an intended way of using UVM.
Thanks.