三剑客齐活,内容全部来自白皮书!
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
在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
在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的跳转可以只局限于验证平台的一部分。