在上一篇博客UVM phase机制(二)中,我们有介绍到run_phase以及12个run_time_phase是如何运转起来的,但是留了一个小问题就是objection,想要run必须raise_objection,要想结束run必须drop_objection。下面我们详细分析一下为什么会这样
在运行到run_node的时候,是这样一个执行结构,
fork
fork
env.run_phase(uvm_phase phase);
join_none
fork
uvm_test_top.run_phase(uvm_phase phase);
join_none
fork
top.run_phase(uvm_phase phase);
join_none
join_none
但是,最终完整的执行结构是
fork
fork
env.run_phase(uvm_phase phase);
join_none
fork
uvm_test_top.run_phase(uvm_phase phase);
join_none
fork
top.run_phase(uvm_phase phase);
join_none
join_none
#0;
fork
begin
fork
process(0);//junp
process(1);//objection
process(2);//timeout
join_any
disable fork
end
join
所有的进程都是并行的,因此如果没有objection的话,那么进程process(1)直接结束,会直接disable fork。直接退出整个执行进程。下面介绍objection机制。有这么一行代码demo。
class my_test extends uvm_test;
.................
.................
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#1;
phase.drop_objection(this);
endtask
.................
.................
endclass
class my_env extends uvm_env;
.................
.................
task run_phase(uvm_phase phase);
.........................
.........................
.........................
endtask
endclass
在my_test的run_phase中raise_objection。那么raise_objection是如何起作用的呢,在生成UVM phase结构的时候,phase树上会生成不同的node,比如build_node等,每个node在生成的时候内部有一个变量是uvm_objection phase_done会被例化生成,名字叫run,这个变量就是控制objection的句柄。下面看一下执行流程
->phase.raise_objection(this);
->phase_done.raise_objection(this);
phase_done.raise_objection主要做
(1)首先check一下this句柄是否是uvm_component或者uvm_sequence,只有这两个地方可以在run_phase中raise_objection。
(2)置位一些标志位
这里我们在my_test中调用raise_objection函数,那么在名为run的phase_done这个句柄中有两个重要的变量
int m_source_count[uvm_object]
int m_total_count[uvm_object]
最终的结果是
m_source_count[my_test]=1;
m_total_count[top]=1;
m_total_count[my_test]=1;
在上面的代码中process(1)控制objection的结束
当我们raise_objection(this)时,process(1)进程将会一直处于等待状态,当我们调用drop_objection(this)时,会触发process(1)结束,那么结束整个执行进程。
在#1,这个时候 process(1)进程结束,调用disable fork函数kill掉进程,执行结束。
我们来看另一种情况
class my_test extends uvm_test;
.................
.................
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#1;
phase.drop_objection(this);
endtask
.................
.................
endclass
class my_env extends uvm_env;
.................
.................
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#2;
phase.drop_objection(this);.
endtask
endclass
不仅在my_test中调用了objection机制,在my_env中也调用了objection机制。
在process(1)中,该进程结束的标志是m_total_count[top]=0;
起初m_total_count[top]=2;
my_test中#1时,drop_objection,此时m_total_count[top]=1;
my_env中#2时,drop_objection,此时m_total_count[top]=0;进程结束。所以整个进程会在#2时结束。
所以说要想run_phase结束,raise_objection和drop_objection必须成对出现
。
现在在谈谈12个run_time_phase,尤其是main_phase。
一般在main_phase之前的phase中不会进行什么操作,我们一般会在main_phase中执行一些操作,并且是与run_phase并行执行的,看下面一段代码
class my_test extends uvm_test;
.................
.................
task run_phase(uvm_phase phase);
.................
.................
endtask
.................
.................
endclass
class my_env extends uvm_env;
.................
.................
task main_phase(uvm_phase phase);
phase.raise_objection(this);
#2;
phase.drop_objection(this);.
endtask
endclass
我们在run_phase中没有raise_objection,但是在main_phase中raise_objection,那么run_phase中的语句是否会执行呢,答案是肯定的。
首先在执行run_phase的时候,虽然没有raise_objection,但是进程process(1)并不会结束因为该进程会在post_shutdown的drop_objection结束,但是又在main_phase中raise_objection,那么main_phase会执行,那么在main_phase执行的时间内,run_phase依旧在执行,知道main_phase执行结束。