uvm component phase
a.phase基本概念
- 按照其是否消耗仿真时间($time打印出的时间)的特性,可以分成两大类:
一类是function phase,这些phase是通过函数实现;另外一类是task phase,这些phase是通过任务实现的 - run_phase启动时间是0ns
除了build_phase自顶而下(top-down)之外,所有不耗费仿真时间的phase(即function phase)都是自下而上(bottom-up)执行的。- 类似run_phase、main_phase等task_phase也都是按照自下而上的顺序执行
- task phase是耗费时间的,所以它并不是等到“下面”的phase(如driver的run_phase)执行完才执行“上面”的phase(如agent的run_phase),而是将这些run_phase通过fork…join_none的形式全部启动。所以更准确的说法是task 的phase 自下而上的启动,同时在运行。
图1中,灰色背景所示的是task phase,其他白色背景为function phase。在时间上,所有的phase都会按照图1中的顺序自上而下自动执行。
最右侧的12个phase是run-time phase (动态运行phase)
- 对于同一component来说,其12个run-time的phase(动态运行phase)是顺序执行的,但是它们也仅仅是顺序执行,并不是说前面一个phase执行完就立即执行后一个phase。
- phase的调试可以用 +UVM_PHASE_TRACE来打印phase相关信息
a1. phase同步
以A component和B component中的main_phase和post_main_phase为例,如图2所示。
从图中可以看到对于A来说,main_phase在100时刻结束,其post_main_phase在200时刻执行。在100~200时刻,A处于等待B的状态,除了等待不做任何事情。B的post_main_phase在400时刻结束,之后处于等待A的状态。无论从A还是从B的角度看,都存在一段 等待时间。但是从整个验证平台的角度来看,各个task phase之间是没有任何空白的。整个验证平台必须所有的main_phase执行完毕,接下来执行post_main_phase;所有的post_main_phase执行完毕,接下来执行下一个phase,如pre_shutdown_phase。
- 这种phase同步不仅适用于不同component的动态运行(run-time)phase之间,还适用于run_phase与run_phase之间。这两种同步都是不同component之间的相同phase之间的同步。
- 除了这两种同步外,还存在一种run_phase与post_shutdown_phase之间的同步。这种同步的特殊之处在于,它是同一个component的不同类型phase(两类task phase,即run_phase与run-time phase)之间的同步,即同一个component的run_phase与其post_shutdown_phase全部完成才会进入下一个phase(extract_phase)。phase同步主要可以总结为图3的三种方式。
b. run_phase 和 main_phase区别
- 从uvm1.1后,uvm的run_phase会与12个task phase并行执行,12个task phase包括pre_reset_phase, reset_phase,…main_phase等等,一般的大部分人并不太用除了main_phase之外的别的task phase,因此一般使用可以认为main_phase跟run_phase几乎相同的作用;
- run_phase跟12个task phase所属的domain并不一样,run_phase属于common_domain, 其余的12个task phase属于uvm_domain
- run_phase和main phase都是task phase,且是并行运行的,后者称为动态运行(run-time)的phase。如果想执行一些耗费时间的代码,那么要在此phase下任意一个component中至少提起一次objection,这个结论只适用于12个run-time的phase。
- 对于run_phase则不适用,由于run_phase与动态运行的phase是并行运行的,如果12个动态运行的phase有objection被提起,那么run_phase根本不需要raise_objection就可以自动执行。
不要混合使用run_phase与main_phase- phase.raise_objection(this) 这里的this是调用这个的component
virtual function void raise_objection (
uvm_object obj,
string description = "",
int count = 1
)
uvm中应该推荐使用reset,main等run_time phase,还是使用run_phase?
UVM基础之------uvm phases机制
c.一个sequence可以指定在main_phase中跑,也可以在其他phase中跑;
来源《uvm实战》7.7.1
case0_cfg_vseq在configure_phase中跑,如果都指定在main_phase中则,后边一个会覆盖前一个;
`ifndef MY_CASE0__SV
`define MY_CASE0__SV
class case0_sequence extends uvm_sequence #(my_transaction);
my_transaction m_trans;
function new(string name= "case0_sequence");
super.new(name);
endfunction
virtual task body();
repeat (10) begin
`uvm_do(m_trans)
end
endtask
`uvm_object_utils(case0_sequence)
endclass
class case0_cfg_vseq extends uvm_sequence;
`uvm_object_utils(case0_cfg_vseq)
`uvm_declare_p_sequencer(my_vsqr)
function new(string name= "case0_cfg_vseq");
super.new(name);
endfunction
virtual task body();
uvm_status_e status;
uvm_reg_data_t value;
if(starting_phase != null)
starting_phase.raise_objection(this);
p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);
`uvm_info("case0_cfg_vseq", $sformatf("invert's initial value is %0h", value), UVM_LOW)
p_sequencer.p_rm.invert.write(status, 1, UVM_FRONTDOOR);
p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);
`uvm_info("case0_cfg_vseq", $sformatf("after set, invert's value is %0h", value), UVM_LOW)
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
class case0_vseq extends uvm_sequence;
`uvm_object_utils(case0_vseq)
`uvm_declare_p_sequencer(my_vsqr)
function new(string name= "case0_vseq");
super.new(name);
endfunction
virtual task body();
case0_sequence dseq;
uvm_status_e status;
uvm_reg_data_t value;
if(starting_phase != null)
starting_phase.raise_objection(this);
#10000;
dseq = case0_sequence::type_id::create("dseq");
dseq.start(p_sequencer.p_my_sqr);
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
class my_case0 extends base_test;
function new(string name = "my_case0", uvm_component parent = null);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
`uvm_component_utils(my_case0)
endclass
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
//case0_cfg_vseq在configure_phase中跑,
//如果都指定在main_phase中则,后边一个会覆盖前一个;
uvm_config_db#(uvm_object_wrapper)::set(this,
"v_sqr.configure_phase",
"default_sequence",
case0_cfg_vseq::type_id::get());
uvm_config_db#(uvm_object_wrapper)::set(this,
"v_sqr.main_phase",
"default_sequence",
case0_vseq::type_id::get());
endfunction
`endif
case0_cfg_vseq跑在bus_driver的configure_phase
bus_driver中要定义run_phase, 因为run_phase包含config_phase;也可以在bus_driver使用configure_phase; 但是不能使用其他phase,会造成不匹配的情况
task bus_driver::run_phase(uvm_phase phase);
vif.bus_cmd_valid <= 1'b0;
vif.bus_op <= 1'b0;
vif.bus_addr <= 15'b0;
vif.bus_wr_data <= 15'b0;
while(!vif.rst_n)
@(posedge vif.clk);
while(1) begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
seq_item_port.item_done();
end
endtask
my_driver使用main_phase 跑 case0_vseq
task my_driver::main_phase(uvm_phase phase);
vif.valid <= 1'b0;
vif.data <= 8'b0;
while(!vif.rst_n)
@(posedge vif.clk);
while(1) begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
seq_item_port.item_done();
end
endtask
set_drain_time
- UVM 在main_phase 检查到所有objection 被撤销后,会检查是否设置drain_time,如果有,则延迟drain_time。
- UVM所有的objection 设置了 drain_time 属性;
- 一个phase 对应一个drain_time,其他phase 要用,要给自己单独设置。不共享。
可以set_drain_time设置一个大的延迟,避免用下边方法
timeout
domain
- run_phase 是common
- 12个小phase是uvm
55、uvm_component类中的phase_ready_to_end()方法有什么用途?
phase_ready_to_end(uvm_phase phase)是component类中的回调(callback)方法,当该phase的所有objections均被drop之后调用该方法。component类可以使用此回调方法来定义phase即将结束时需要执行的功能。
如果某个组件希望在objections被drop之后将phase结束延迟到某个条件,可以使用此回调方法来完成;
这个方法和set_drain_time区别???