“想弄清楚函数的功能,先清楚是谁的函数”
来源| 杰瑞IC验证(ID:Jerry_IC) |原创
作者| Jerry Ren
在UVM中,有几个和“name”有关的“小”函数, 如get_name(), get_full_name(), get_type_name() ,set_name ()。 长得这么像,分不太清楚啊?这都是怎么玩的?先收藏再说!
如果一个人问:“Jerry,你说get_full_name()这个函数是什么含义和功能啊?”
我会反问:“你说的是谁的这个函数?”
哈哈,没错!各位初学者们注意了,Jerry先纠正大家一个思维习惯。UVM验证平台中提到函数,他们往往是定义在某个class中的,你调用某个函数其实是某个class中的函数!所以大家心里要明白,我在调用谁的函数?光说一个函数名,是无法判断他的功能的,我自己的class也可以定义这样一个名字的函数~
为什么要明确这一点呢?我们今天开场白说的get_name(), get_full_name(), get_type_name() ,set_name()这些小函数,用的时候,还真是各自class各自的定义!在UVM中的class主要指的就是最常用的他们:uvm_component,uvm_sequence_item。怎么样?有没有初学者平时玩这些小函数稀里糊涂的?来,今天和Jerry一起把这里的东西弄清楚!
01
uvm_component中get_name系列小函数
来段代码:
比如在UVM验证平台中,我们在这样的一个class中调用这几个函数:
class jerry_component extends uvm_component;
…
$display(“%0s”,get_name());
$display(“%0s”,get_full_name());
$display(“%0s”,get_type_name());
…
endclass
而这个class在env中例化:
class jerry_env extends uvm_env;
…
jerry_component u_jerry_c;
…
function void build_phase (uvm_phase phase);
u_jerry_c =jerry_component::type_id::create(“u_jerry_so_cool”,this);
endfunction
…
endclass
jerry_env例化在base_test中名为u_jerry_env。
如上代码中jerry_component中调用的小函数打印出会是什么字符串呢?
大家先猜猜再看下面的答案:
1.get_name() 会打印出:
“u_jerry_so_cool”。
大家注意了!相信很多人都会认为这个函数会打印出“u_jerry_c”,
实际竟然会是“u_jerry_so_cool”!这个是哪里来的?
原来是这句u_jerry_c=jerry_component::type_id::create(“u_jerry_so_cool”,this);
例化的时候写进去的字符串啊!使用u_jerry_c =new(“u_jerry_so_cool”)方式写进去的字符串也是一样的效果。为什么你会认为是打印这句“u_jerry_c”?因为常常我们习惯于例化时候传入的字符串与这个名字是保持一致的!!但其实我们心里还是应该有点数比较好~
2.get_full_name()会打印出:
“uvm_test_top.u_jerry_env.u_jerry_so_cool”。
这带full的小函数,打印出的是路径名字。
这里要注意两点:
a.路径的结尾:“u_jerry_so_cool”。这个不要怀疑,就是get_name()拼出来的,而不是“u_jerry_c”。
b.路径的开头:“uvm_test_top”。记住打印的路径不是从UVM树根开始的!是树根的下一级。(Tip:树根路径对应“__top__”)
3.get_type_name()会打印出:
“jerry_component”。
对于uvm_component,这个get_type_name(),就是class的名字。
02
uvm_sequence_item中get_name系列小函数
class jerry_tr extends uvm_sequence_item;
…
`uvm_object_utils_begin( jerry_tr )
…
`uvm_object_utils_end
…
endclass
class jerry_component extends uvm_component;
jerry_tr u_tr;
…
u_tr=new(“jerry_is_good”);
…
$display(“%0s”,u_tr.get_name());
$display(“%0s”,u_tr.get_full_name());
$display(“%0s”,u_tr.get_type_name());
…
endclass
还是老规矩,先猜猜这几句打印什么?然后再看下面的解释:
1. u_tr.get_name() 会打印出:
“jerry_is_good”。
uvm_sequence_item中的get_name函数与uvm_component一样,是打印“new()”时候传入的字符串!
2. u_tr.get_full_name()会打印出:
“jerry_is_good”。
注意!对于uvm_sequence_item,get_full_name()与get_name()一样!因为它是不作为UVM树节点的,所以路径没有别的层次。这点保留了uvm_object原本的函数性质。
3. u_tr.get_type_name()会打印出:
“jerry_tr”。
实际上,在原始的uvm_object的get_type_name()传出的是<unknow>,也就是无返回值的!但是我们为什么看到此处打印的与uvm_component一样是一个class名呢?
原因是因为这句话:
`uvm_object_utils_begin( jerry_tr )
…
`uvm_object_utils_end
原来通过这几句话,UVM实际上会把uvm_object的get_type_name()函数重载,这个函数就会返回class名字!
那我们屏蔽了它会出现什么呢?!
如果你屏蔽了这几句,或者不需要这几句,u_tr.get_type_name()会打出“uvm_sequence_item”!!
这个为什么?因为uvm_sequence_item里面本身也会重载这个函数!
03
关于set_name
在上述uvm_sequence_item中,我们加入set_name这样一行代码。
class jerry_component extends uvm_component;
jerry_tr u_tr;
…
u_tr=new(“jerry_is_good”);
u_tr.set_name(“jerry_is_cool”);
…
$display(“%0s”,u_tr.get_name());
$display(“%0s”,u_tr.get_full_name());
$display(“%0s”,u_tr.get_type_name());
…
endclass
1. u_tr.get_name() 会打出“jerry_is_cool”。
2. u_tr.get_full_name()会打出“jerry_is_cool”。
3. u_tr.get_type_name()会打出“jerry_tr”。
我们清楚的可以看出来,在uvm_sequence_item中,调用set_name是更改了“new()”中的字符串名,相当于这个字符串的名字重新改写了!
同样,如果我们在uvm_component中使用set_name呢?我们在前文代码中加入:
class jerry_component extends uvm_component;
…
set_name(“I love jerry”);
…
endclass
各位注意了,这个时候不等打印,就会报出一个UVM_ERROR!!
大致如下:
It is illegal to change the name of a component. The component name will not be changed to “I love jerry”
是因为uvm_component不喜欢“I love Jerry”这句话吗?
当然不是!它可能只是羞于表达……
当然除了这个羞于表达的原因,还有一个原因:就是uvm_component使用set_name的时候希望其本身的名字是空的才能改名!也就是说,uvm_component没名字才能起名字,名字一旦起好不能乱改!(因为好歹是一个UVM树的节点,还是要稳重点)。其实,在uvm_component中new()的时候就会调用set_name()函数,所以uvm_component的这个函数一般不是给外人用的,我们就不改他的名字了。