admin管理员组文章数量:1648311
默认条件下,stop_sequence 会递归kill 掉子sequence,前提是已经建立了父子关系。
如何建立sequence的父子关系呢?
1. 使用uvm_do/uvm_do_on启动sequence(自动建立父子关系);
2. 如果使用start启动sequence,则需要手动指定parent_sequence;
virtual task start (uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
int this_priority = -1,
bit call_pre_post = 1 )
my_seq.start(null,this);
在调用stop_sequences 时要注意两点:
1. 如果stop_sequences 在get_next_item 和 item_done 之间调用,则会导致error,
建议使用下述方法,即等当前txn回完item_done再调用stop_sequence.
2. 调用stop_sequences时最好把driver中当前get_next_item进程kill掉;否则可能导致error
i.e.
"The task responsible for requesting a wait_for_grant on sequencer for sequence
has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues"
上述error 是由于在do item 时会把request放入the arbitration queues,而call get_next_item时会查看request的进程是否被kill,若kill则报error;
wait_for_grant 与get_next_item是两个并行的进程,request放入the arbitration queues,call get_next_item和stop_sequences三者可能会在同一时间发生,当request放入the arbitration queues后,在call get_next_item 过程中stop_sequences 就会导致上述error。
上述error在uvm -1.1c中才加进来的判断,在调用get_next_item时会间接调用到m_choose_next_request这个function,从而引入上述error。
---------------------------------------------------------------------------------------------------------------------------------
solution 1
要从两方面入手:
- driver 端:当reset=0时,kill 当前driver 进程后要保证当前这笔transaction 的item_done回完;
- sequence端:当reset=0时,等收到当前这笔transaction 的item_done之后kill sequence;
PS: 要保证是先kill 当前driver进程后再stop_sequence.
方案1:(等driver和sequencer handshake 完成再kill sequence)
//Sequence
class idles_transmit extends uvm_sequence #(REQ= packet);
bit received_item_done;
virtualfunction void mid_do (uvm_sequence_itemthis_item);
received_item_done=0;
endfunction
virtualfunction void post_do (uvm_sequence_itemthis_item);
received_item_done=1;
endfunction
task body();
`uvm_do(req)
//wait_for_grant();
//assert(req.randomize());
//send_req(req);
//received_item_done = 0;
//wait_for_item_done();
//received_item_done = 1;
endtask
endclass
-------------------------------------------------------------------------------------------------------------
//Test
begin
fork
begin
wait(rtl_linkup == 1);
end
forever begin
idles_transmit.start(Sequencer);
end
join_any
@(posedge idles_transmit.received_item_done); //收到当前txn的item_done
disable fork;
Sequencer.stop_sequences();
end
------------------------------------------------------------------------------------------------------------------
driver :
virtual task main_phase(uvm_phase phase);
forever begin
fork
wait(intf.rst_n === 1'b0);
send_to_dut(phase);
join_any
disable fork;
if(intf.rst_n ===1'b0)begin
if((interrupt_flag1 == 1'b1) && (interrupt_flag2 == 1'b0))begin//reset时当前这边txn的item_done没有回
seq_item_port.item_done();
end
reset_output();
@(posedge intf.clk);
end
interrupt_flag1 == 1'b0;
interrupt_flag2 == 1'b0;
end
endtask
virtual task reset_output();
wait(intf.rst_n === 1'b0);
intf.irq_status <= 'd0;
intf.valid <= 'd0;
wait(intf.rst_n === 1'b1);
endtask
virtual task send_to_dut(uvm_phase phase);
seq_item_port.get_next_item(req);
interrupt_flag1 = 1'b1;
send(req);
seq_item_port.item_done();
interrupt_flag2 = 1'b1;
endtask
solution 2:(直接kill 进程)
driver端:
virtual task main_phase(uvm_phase phase);
forever begin
fork
wait(intf.rst_n === 1'b0);
send_to_dut(phase);
join_any
disable fork;
if(intf.rst_n ===1'b0)begin
reset_output();
wait(intf.rst_n ===1'b1);
@(posedge intf.clk);
end
end
endtask
sequence 端
virtual task body();//L3 seq
fork
`uvm_do_on(slv_seq,slv_sqr) //slave sequence 无需reset
reset_setting();//do reset sequence
join_none
fork
begin
fork
`uvm_do(single_scenario_seq)// main sequence !!!!!!一定是最外层的seq,比如L2 SEQ
wait(glb_cfg.irq_vif.rst_n === 1'b0);
join_any
disable fork; //kill sequence进程(针对多次do sequence场景)
if(glb_cfg.irq_vif.rst_n === 1'b0)begin
#0.01ns; //保证driver进程先kill
irq_sqr.stop_sequences(); //清空arb_sequence_q ,其他临时变量回到初始状态,kill当前sequence进程
ral_model.reset(); //针对下Rigiser的场景
end
end
join
if(glb_cfg.irq_vif.rst_n === 1'b0)
`uvm_do(single_scenario_seq)
endtask
kill `uvm_do(single_scenario_seq)进程导致seq 直接完成了body task,进而调用uvm_sequencer_base::remove_sequence_from_queues 函数 ,该函数会check arb_sequence_q是否empty,如果不为空,会判断是否descendent sequence item are processed but parent sequence has finished.进而报uvm_error.
//此函数会再body函数结束后调用
function void uvm_sequencer_base::m_sequence_exiting(uvm_sequence_base sequence_ptr);
remove_sequence_from_queues(sequence_ptr);
endfunction
//此函数会再调用stop_sequences时调用
function void uvm_sequencer_base::kill_sequence(uvm_sequence_base sequence_ptr);
remove_sequence_from_queues(sequence_ptr);
sequence_ptr.m_kill(); //kill body task 进程
endfunction
function void uvm_sequencer_base::remove_sequence_from_queues(
uvm_sequence_base sequence_ptr);
int i;
int seq_id;
seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0);
// Remove all queued items for this sequence and any child sequences
i = 0;
do
begin
if (arb_sequence_q.size() > i) begin
if ((arb_sequence_q[i].sequence_id == seq_id) ||
(is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin
if (sequence_ptr.get_sequence_state() == FINISHED)//m_sequence_state
`uvm_error("SEQFINERR", $psprintf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed. The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()))
arb_sequence_q.delete(i);
m_update_lists();
end
else begin
i++;
end
end
end
while (i < arb_sequence_q.size());
...
记得disable fork 的是最外层的sequence ,这样可以直接终止start task进程,不会执行body之后的m_sequence_exiting,否则会遇到上述问题 !!!!!
如果是以下场景:
//L2 seq
virtual task body();
hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
hw_related_seq.randomize() with {};
hw_related_seq.start(null,this);
fork
hw_related_seq.sw_tick_setting();
join_none
....
//do other HW RG seq
endtask
run time reset时,可能也会导致:
由于调用stop_sequences 进而调用到uvm_sequencer_base::remove_sequence_from_queues 函数 ,该函数会check arb_sequence_q是否empty,如果不为空,会判断是否descendent sequence item are processed but parent sequence has finished.进而报uvm_error.
root cause :
上述code中hw_related_seq start task 执行完后m_sequence_state = FINISHED,但后面仍然在调用它的task(sw_tick_setting,读写register),此时如果调用stop_sequences,子seq(读写register)还存在但parent seq已经被kill.
solution :
在调用sw_tick_setting之前,create hw_related_seq。
//L2 seq
virtual task body();
hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
hw_related_seq.randomize() with {};
hw_related_seq.start(null,this);
hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
fork
hw_related_seq.sw_tick_setting();
join_none
....
//do other HW RG seq
endtask
第二种出现此种error的场景:
l2_seq:
task body();
fork
begin
`uvm_do_on(l1_seq,sqr_1)
end
begin
wait(rst_n === 1'b0);
end
join_any
disable fork;//当reset时,l1_seq 被kill,该body函数结束
endtask
l3_seq:
task body();
fork
l2_seq.start(null);
`uvm_do_on(rst_seq,rst_sqr)
join_any
disable fork;
endtask
当 reset active时l2_seq的body函数就结束了,此时该sequence的state会变为FINISHED,进入m_sequnce_exiting执行remove_seuqence_from_request
solution:
l2_seq:
task body();
begin
`uvm_do_on(l1_seq,sqr_1)
end
endtask
l3_seq:
task body();
fork
`uvm_do_on(rst_seq,rst_sqr)
join_none
fork
fork
l2_seq.start(null);
wait(rst_n === 1'b0);
join_any
disable fork;
join
endtask
disable fork 的是最外层的sequence ,这样可以直接终止start task进程,不会执行body之后的m_sequence_exiting
版权声明:本文标题:[UVM] kill sequence 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729493314a1202654.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论