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
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
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?”.
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.
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().
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?”
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.