三剑客齐活,内容全部来自白皮书!
1 domain简介
domain是UVM中一个用于组织不同组件的概念。
先来看一个例子,假设DUT分成两个相对独立的部分,这两个独立的部分可以分别复位、配置、启动,但如果没有domain的概念,那么这两块独立的部分则必须同时在reset_phase复位,同时在configure_phase配置,同时进入main_phase开始正常工作。
这种协同性当然是没有问题的,但是没有体现出独立性。图5-6中画出了这两个部分的driver位于同一domain的情况。
在默认情况下,验证平台中所有component都位于一个名字为common_domain的domain中。
若要体现出独立性,那么两个部分的reset_phase、configure_phae、main_phase等就不应该同步。
此时就应该让其中的一部分从common_domain中独立出来,使其位于不同的domain中。图5-7中列出了两个driver位于不同domain的情况。
domain把两块时钟域隔开,之后两个时钟域内的各个动态运行(run_time)的phase就可以不必同步。
注意,这里domain只能隔离run-time的phase,对于其他phase,其实还是同步的,即两个domain的run_phase依然是同步的,其他的function phase也是同步的。
2 多domain的例子
若将某个component置于某个新的domain中,可以使用如下的方式:
文件:src/ch5/section5.3/5.3.2/B.sv
3 class B extends uvm_component;
4 uvm_domain new_domain;
5 `uvm_component_utils(B)
6 7 function new(string name, uvm_component parent);
8 super.new(name, parent);
9 new_domain = new("new_domain");
10 endfunction
1112 virtual function void connect_phase(uvm_phase phase);
13 set_domain(new_domain);
14 endfunction
…
20 endclass
在上述代码中,新建了一个domain,并将其实例化。在connect_phase中通过set_domain将B加入到此domain中。set_domain函数的原型是:
来源:UVM源代码
function void uvm_component::set_domain(uvm_domain domain, int hier=1);
其第二个参数表示是否递归调用,如果为1,则B及其子孙都将全部加入到new_ domain中。由于子孙的实例化一般在build_phase中完成,所以这里一般在connect_phase中调用set_domain。
当B加入到new_domain后,它与其他component(默认位于common domain中)的动态运行phase异步了。
在B中:
文件:src/ch5/section5.3/5.3.2/B.sv
22 task B::reset_phase(uvm_phase phase);
23 phase.raise_objection(this);
24 `uvm_info("B", "enter into reset phase", UVM_LOW)
25 #100;
26 phase.drop_objection(this);
27 endtask
28 29 task B::post_reset_phase(uvm_phase phase);
30 `uvm_info("B", "enter into post reset phase", UVM_LOW)
31 endtask
32 33 task B::main_phase(uvm_phase phase);
34 phase.raise_objection(this);
35 `uvm_info("B", "enter into main phase", UVM_LOW)
36 #500;
37 phase.drop_objection(this);
38 endtask
39 40 task B::post_main_phase(uvm_phase phase);
41 `uvm_info("B", "enter into post main phase", UVM_LOW)
42 endtask
43
在A中:
文件:src/ch5/section5.3/5.3.2/A.sv
16 task A::reset_phase(uvm_phase phase);
17 phase.raise_objection(this);
18 `uvm_info("A", "enter into reset phase", UVM_LOW)
19 #300;
20 phase.drop_objection(this);
21 endtask
22 23 task A::post_reset_phase(uvm_phase phase);
24 `uvm_info("A", "enter into post reset phase", UVM_LOW)
25 endtask
26 27 task A::main_phase(uvm_phase phase);
28 phase.raise_objection(this);
29 `uvm_info("A", "enter into main phase", UVM_LOW)
30 #200;
31 phase.drop_objection(this);
32 endtask
33 34 task A::post_main_phase(uvm_phase phase);
35 `uvm_info("A", "enter into post main phase", UVM_LOW)
36 endtask
37
在base_test中将A和B实例化:
文件:src/ch5/section5.3/5.3.2/base_test.sv
4 class base_test extends uvm_test;
5
6 A A_inst;
7 B B_inst;
…
16 endclass
17
18
19 function void base_test::build_phase(uvm_phase phase);
20 super.build_phase(phase);
21 A_inst = A::type_id::create("A_inst", this);
22 B_inst = B::type_id::create("B_inst", this);
23 endfunction
运行上述代码后,可以得到如下结果:
# UVM_INFO B.sv(20) @ 0: uvm_test_top.B_inst [B] enter into reset phase
# UVM_INFO A.sv(18) @ 0: uvm_test_top.A_inst [A] enter into reset phase
# UVM_INFO B.sv(26) @ 100: uvm_test_top.B_inst [B] enter into post reset phase
# UVM_INFO B.sv(31) @ 100: uvm_test_top.B_inst [B] enter into main phase
# UVM_INFO A.sv(24) @ 300: uvm_test_top.A_inst [A] enter into post reset phase
# UVM_INFO A.sv(29) @ 300: uvm_test_top.A_inst [A] enter into main phase
# UVM_INFO A.sv(35) @ 500: uvm_test_top.A_inst [A] enter into post main phase
# UVM_INFO B.sv(37) @ 600: uvm_test_top.B_inst [B] enter into post main phase
可以清晰地看到,A和B的动态运行phase已经完全异步了。
3 多domain中phase的跳转
上节中的A和B分别位于不同的domain中,在此种情况下,phase的跳转将只局限于某一个domain中。
A和base_test的代码与上节相同,B的代码变更为:
文件:src/ch5/section5.3/5.3.3/B.sv
3 class B extends uvm_component;
4 uvm_domain new_domain;
5 bit has_jumped;
6 `uvm_component_utils(B)
7 8 function new(string name, uvm_component parent);
9 super.new(name, parent);
10 new_domain = new("new_domain");
11 has_jumped = 0;
12 endfunction
13 14 virtual function void connect_phase(uvm_phase phase);
15 set_domain(new_domain);
16 endfunction
…
20 endclass
21 22 task B::reset_phase(uvm_phase phase);
23 phase.raise_objection(this);
24 `uvm_info("B", "enter into reset phase", UVM_LOW)
25 #100;
26 phase.drop_objection(this);
27 endtask
28 29 task B::main_phase(uvm_phase phase);
30 phase.raise_objection(this);
31 `uvm_info("B", "enter into main phase", UVM_LOW)
32 #500;
33 if(!has_jumped) begin
34 phase.jump(uvm_reset_phase::get());
35 has_jumped = 1'b1;
36 end
37 phase.drop_objection(this);
38 endtask
由B的main_phase中跳转至reset_phase。has_jumped控制着跳转只进行一次。运行上述代码后,可以得到如下结果:
# UVM_INFO B.sv(24) @ 0: uvm_test_top.B_inst [B] enter into reset phase
# UVM_INFO A.sv(18) @ 0: uvm_test_top.A_inst [A] enter into reset phase
# UVM_INFO B.sv(31) @ 100: uvm_test_top.B_inst [B] enter into main phase
# UVM_INFO A.sv(24) @ 300: uvm_test_top.A_inst [A] enter into post reset phase
# UVM_INFO A.sv(29) @ 300: uvm_test_top.A_inst [A] enter into main phase
# UVM_INFO A.sv(35) @ 500: uvm_test_top.A_inst [A] enter into post main phase
# UVM_INFO /home/landy/uvm/uvm-1.1d/src/base/uvm_phase.svh(1314) @ 600: reporter
[PH_JUMP] phase main (schedule uvm_sched, domain new_domain) is jumping to phase reset
# UVM_INFO B.sv(24) @ 600: uvm_test_top.B_inst [B] enter into reset phase
# UVM_INFO B.sv(31) @ 700: uvm_test_top.B_inst [B] enter into main phase
可以看到B两次进入了reset_phase和main_phase,而A只进入了一次。domain的应用使得phase的跳转可以只局限于验证平台的一部分。