- 使用factory机制注册的component类,可以通过类名(字符串)进行实例化,并自动调用其main_phase。其功能的实现是因为UVM内部定义了一个参数化的类来实现此功能。本质上看factory机制是对sv中new函数的重载。new函数太简单,factory经过改良提供了更多的功能。
- 使用factory机制注册的component类,在接收外部set的变量时,如果要传递的变量使用`uvm_field宏注册后,可以在此component类中省略get语句。用`uvm_field宏注册后可以使用诸如copy、print、compare、pack、unpack等方法,无需自己定义实现。
- 经注册的类在用creat实例化后,set_type_override_by_type进行重载时会用子类代替父类。
1) 定义my_driver类派生自uvm_driver类,并声明变量pre_num。
class my_driver extends uvm_driver;
int pre_num;
`uvm_component_utils(my_driver)
`uvm_field_int(pre_num)
function new(string name = "my_driver", uvm_component parent=null);
super.new(name,parent);
endfunction
extern virtual task biuld_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
task my_driver::build_phase(uvm_phase phase);
super.build_phase(phase);
endtask
task my_driver::main_phase(uvm_phase phase);
endtask
uvm_component类使用uvm_component_utils等宏注册,如test,env,agent,drv,mon,seqr。uvm_object类使用uvm_object_utils等宏注册,如seq,item。
声明component类时使用`uvm_component_utils注册,其参数为要注册的类。此宏将这个类注册登记到uvm的一张表里,之后可以通过类名创建一个实例。所有派生自uvm_component的类及其派生类的类都应该使用此宏注册。(在执行用例启动仿真时候的build_phase自动创建各自节点?)
在创建节点实例化此类时,此类里的main_phase也会被自动调用。
与`uvm_component_utils相关的宏有:`uvm_component_param_utils,用于注册参数化的类。`uvm_component_utils_begin,uvm_component_utils_end,用于同时需要factory机制和field_automation机制的类的注册。
2)field_automation机制对于uvm_component类最大的作用在于自动使用config_db获取某些变量的值。在env或case中使用config_db传递pre_num的值给driver,在执行uvm的super.build_phase时,会自动执行config_db的get语句,因此可以省略。这种用法的前提是:1. 收信的类需使用`uvm_component_utils宏注册,2. 要传递的变量需在收信的类里使用`uvm_field_xx宏注册,3. set语句和get语句的变量名称应该一致,即在收信类里声明和注册的变量名称。set语句无法省略。这种函数/任务重载的功能在UVM中得到了大量的应用。其实最典型的莫过于各个phase。在一个验证平台中,UVM树上的结点是各个类型的,UVM不必理会它们具体是什么类型,统一将它们当作uvm_component来对待,这极大方便了管理。
3)如果在build_phase阶段添加set_type_override_by_type,其中括号里的第一个参数为父类,第二个为子类。
1 class bird extends uvm_object;
2 virtual function void hungry();
3 $display("I am a bird, I am hungry");
4 endfunction
5 function void hungry2();
6 $display("I am a bird, I am hungry2");
7 endfunction
8 endclass
9 class parrot extends bird;
10 virtual function void hungry();
11 $display("I am a parrot, I am hungry");
12 endfunction
13 function void hungry2();
14 $display("I am a parrot, I am hungry2");
15 endfunction
16 endclass
17 function void my_case0::print_hungry(bird b_ptr);
18 b_ptr.hungry();
19 b_ptr.hungry2();
20 endfunction
21 function void my_case0::build_phase(uvm_phase phase);
22 bird bird_inst;
23 parrot parrot_inst;
24 super.build_phase(phase);
25 bird_inst = bird::type_id::create("bird_inst");
26 parrot_inst = parrot::type_id::create("parrot_inst");
27 print_hungry(bird_inst);
28 print_hungry(parrot_inst);
29 endfunction
function void my_case0::build_phase(uvm_phase phase);
72 set_type_override_by_type(bird::get_type(), parrot::get_type());
73
74 bird_inst = bird::type_id::create("bird_inst");
75 parrot_inst = parrot::type_id::create("parrot_inst");
76 print_hungry(bird_inst);
77 print_hungry(parrot_inst);
78 endfunction
打印结果为:
I am a parrot, I am hungry
I am a bird, I am hungry2
I am a parrot, I am hungry
I am a bird, I am hungry2
其原因为:经注册的类在使用factory机制实例化(class::type_id::creat)时,如果类之间存在派生关系,用set_type_override_by_type进行重载时,set_type_override_by_type语句相当于在factory机制的表格中加入了一条记录,当查到有重载纪录时,用新的类型代替旧的类型。因此74行创建的类的实例实际上是parrot类。对于定义的virtual类型的function则执行子类的行为,非virtual不能重载。
可以使用set_inst_override_by_type函数重载部分类,函数源代码如下。
extern function void set_inst_override_by_type(string relative_inst_path,
uvm_object_wrapper original_type,
uvm_object_wrapper override_type);
如要将monitor重载,将env.o_agt.mon替换成new_monitor,第一个参数为相对路径。
class new_monitor extends my_monitor;
`uvm_component_utils(new_monitor)
virtual task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
`uvm_info("new_monitor", "I am new monitor", UVM_MEDIUM)
endtask
endclass
set_inst_override_by_type("env.o_agt.mon", my_monitor::get_type(), new_monitor::get_type())
另外还有set_type_override,其源代码是
extern static function void set_type_override(string original_type_name,
string override_type_name,
bit replace=1);
parrot类重载bird,用下述语句即可。还有其它函数,不再详述。
set_type_override("bird", "parrot")
上述讲了部分重载,还有连续重载、替换重载等。连续重载好理解,创建实例时,爷爷实例化的是孙子的类型。替换重载:在使用set_type_override_by_type添加记录时,factory并不会在看完第一条记录后即直接创建一个parrot的实例,而是看完最后记录后才会创建最后类型的实例。
在UVM中,item,seq以及uvm_component都可以重载。对完成特定用例提供了极大的方便和自由。
本文章参考《UVM实战》、《芯片验证漫游指南》等资料整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。