UVM的field automation机制,拷贝、比较和打印
1.拷贝
通过上面的数据操作方法默认类型可以看到,当拷贝对象时,默认进行的是深拷贝,即会执行copy()和do_copy()。
module object_copy2;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef enum {RED, WHITE, BLACK} color_t;
class ball extends uvm_object;
int diameter = 10;
color_t color = RED;
`uvm_object_utils_begin(ball)//域的自动化
`uvm_field_int(diameter, UVM_DEFAULT)
`uvm_field_enum(color_t, color, UVM_NOCOPY)
`uvm_object_utils_end
function new(string name="ball");
super.new(name);
endfunction
function void do_copy(uvm_object rhs);
ball b;
$cast(b, rhs);
$display("ball::do_copy entered..");
if(b.diameter <= 20) begin
diameter = 20;
end
endfunction
endclass
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
ball b;
`uvm_object_utils_begin(box)
`uvm_field_int(volume, UVM_ALL_ON)
`uvm_field_enum(color_t, color, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
`uvm_field_object(b, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name="box");
super.new(name);
this.name = name;
b = new();
endfunction
endclass
box b1, b2;
initial begin
b1 = new("box1");
b1.volume = 80;
b1.color = BLACK;
b1.b.color = WHITE;
b2 = new();
b2.copy(b1);
b2.name = "box2";
$display("%s", b1.sprint());
$display("%s", b2.sprint());
end
endmodule
输出结果:
ball::do_copy entered..
-----------------------------------
Name Type Size Value
-----------------------------------
box1 box - @336
volume integral 32 'h50
color color_t 32 BLACK
name string 4 box1
b ball - @337
diameter integral 32 'ha
color color_t 32 WHITE
-----------------------------------
-----------------------------------
Name Type Size Value
-----------------------------------
box box - @338
volume integral 32 'h50
color color_t 32 BLACK
name string 4 box2
b ball - @340
diameter integral 32 'h14
color color_t 32 RED
-----------------------------------
这段例码新添加了一个类ball,并且在box中例化了一个对象。而在拷贝过程中,box的其它成员都正常拷贝了,但对于box::b的拷贝则通过了ball的深拷贝方式进行。即先执行自动拷贝copy(),来拷贝允许拷贝的域,由于ball::color不允许拷贝,所以只拷贝了ball::diameter。
接下来,再执行do_copy()函数,这个函数是需要用户定义的回调函数(callback function),即在copy()执行完后会执行do_copy()。如果用户没有定义该函数,那么则不会执行额外的数据操作。
从ball::do_copy()函数可以看到的是,如果被拷贝对象的diameter小于20,那么则将自身的diameter设置为20。
因此,最后对象b2.b的成员与b1.b的成员数值不同。
2.比较
对于比较方法,默认情况下,如果不对比较的情况作出额外地配置,用户可以在调用compare()方法时,省略第二项参数,即采用默认的比较配置。
module object_compare1;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef enum {RED, WHITE, BLACK} color_t;
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`uvm_object_utils_begin(box)
`uvm_field_int(volume, UVM_ALL_ON)
`uvm_field_enum(color_t, color, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name="box");
super.new(name);
this.name = name;
endfunction
endclass
box b1, b2;
initial begin
b1 = new("box1");
b1.volume = 80;
b1.color = BLACK;
b2 = new("box2");
b2.volume = 90;
if(!b2.compare(b1)) begin
`uvm_info("COMPARE", "b2 comapred with b1 failure", UVM_LOW)
end
else begin
`uvm_info("COMPARE", "b2 comapred with b1 succes", UVM_LOW)
end
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [MISCMP] Miscompare for box2.volume: lhs = 'h5a : rhs = 'h50
UVM_INFO @ 0: reporter [MISCMP] 1 Miscompare(s) for object box1@336 vs. box2@337
UVM_INFO @ 0: reporter [COMPARE] b2 comapred with b1 failure
在上面的两个对象的比较中,会将每一个自动化的域进行比较,所以在执行compare()函数时,内置的比较方法也会将比较错误输出。从上面的结果来看,比较发生了错误,返回了0值。那么,b1.color和b2.color虽然不相同,为什么没有比较错误的信息呢?原因在于,默认的比较器,即***uvm_package::uvm_default_comparer***最大输出的错误比较信息是1,也就是说当比较错误发生时,则不会进行后续的比较。
3.打印
打印方法是核心基类提供的另外一种便于开发和调试的功能。通过field automation,使得声明之后的各个成员域会在调用uvm_object::print()函数时自动打印出来。
module object_print;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef enum {RED, WHITE, BLACK} color_t;
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`uvm_object_utils_begin(box)
`uvm_field_int(volume, UVM_ALL_ON)
`uvm_field_enum(color_t, color, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name="box");
super.new(name);
this.name = name;
endfunction
endclass
box b1;
uvm_table_printer local_printer;
initial begin
b1 = new("box1");
local_printer = new();
$display("default table printer format");
b1.print();
$display("default line printer format");
uvm_default_printer = uvm_default_line_printer;
b1.print();
$display("default tree printer format");
uvm_default_printer = uvm_default_tree_printer;
b1.print();
$display("customized printer format");
local_printer.knobs.full_name = 1;
b1.print(local_printer);
end
endmodule
输出结果:
default table printer format
-------------------------------
Name Type Size Value
-------------------------------
box1 box - @336
volume integral 32 'h78
color color_t 32 WHITE
name string 4 box1
-------------------------------
default line printer format
box1: (box@336) { volume: 'h78 color: WHITE name: box1 }
default tree printer format
box1: (box@336) {
volume: 'h78
color: WHITE
name: box1
}
customized printer format
------------------------------------
Name Type Size Value
------------------------------------
box1 box - @336
box1.volume integral 32 'h78
box1.color color_t 32 WHITE
box1.name string 4 box1
------------------------------------
**从上面这段例码中,读者可以发现,只要被在field automation中声明过的域,在稍后的print()函数打印室,都将打印出它们的类型、大小和数值。如果用户不对打印的格式做出修改,那么在打印时,UVM会按照uvm_default_printer规定的格式来打印。在上面“比较”一节中,读者已经知道uvm_pkg中在仿真一开始的时候就会例化不少全局的对象,这其中就包括了uvm_default_printer和其它几个用于打印的对象,它们分别是:
uvm_default_tree_printer:可以将对象按照数状结构打印。
uvm_default_line_printer : 可以将对象打印到一行上面。
uvm_default_table_printer : 可以将对象按照表格的方式打印。
uvm_default_printer : UVM环境默认的打印设置,该句柄默认指向了uvm_default_table_printer。
所以通过给全局打印机uvm_default_printer赋予不同的打印机句柄,就可以在调用任何uvm_object的print()方法时,得到不同的打印格式。如果用户需要自定义一些打印的属性,用户可以自己创建一个打印机,进而通过修改其属性uvm_printer::knobs中的成员,来输出自己的打印格式。每一台打印机中,都有自己的打印属性,用户可以通过查看UVM类的参考手册,查找关于详细的打印属性类uvm_printer_knobs。
除了简单的print()函数,用户还可以通过uvm_object::sprint()将对象的信息作为字符串返回,或者自定义do_print()函数来定制一些额外的打印输出
4.常见错误
在vcs跑sv结果时候需要运行:
vcs -sverilog -ntb_opts uvm print.sv -full64