uvm_void
根类继承,实际上该类并没有成员变量和方法。uvm_void
只是一个虚类,还在等待将来继承于它的子类去开垦。继承于它的子类中有uvm_object
类和uvm_port_base
类。uvm_port_base
,其他所有类都从uvm_object
类一步步继承。uvm_object的核心方法主要提供与数据操作的相关服务:copy、clone、compare、print、pack/unpack
(无论是copy或clone,都需要确保在操作的过程中需要有source object和target object)。
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_ALL_ON:使能该域参与所有的数据操作
`uvm_field_enum(color_t, color, UVM_ALL_ON) //也可使用UVM_DEFAULT
`uvm_field_string(name, UVM_ALL_ON)
`uvm_object_utils_end
//在注册box时也声明了将来会参与到uvm_object数据操作的成员变量
//凡是声明了的成员变量,都将在数据操作时自动参与进来
//如果有一些数据没有通过域的自动化声明,它们将不会自动参与到数据的拷贝等操作
//除非用户自定义这些数据操作方法
... //省略了new函数
endclass
box b1, b2;
initial begin
b1 = new("box1");
b1.volume = 80;
b1.color = BLACK;
b2 = new();
b2.copy(b1); //copy会把b1的成员变量也拷贝给b2
//copy方法是UVM自动实现的,前提是做域的自动化声明
b1.name = "box2";
end
前者默认已经创建好了对象,只需对数据进行拷贝;后者会自动创建对象并对source object进行数据拷贝,再返回target object句柄。两者都需要对数据进行复制。
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
... //省略new函数
function void do_copy(uvm_object rhs);
ball b;
$cast(b, rhs);
$display("ball::do_copy entered...");
if(b.diameter <= 20) begin
diameter = 20; //不足20则赋为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
...
endclass
box b1, b2;
initial begin
b1 = new("box1");
b1.volume = 80;
b1.color = BLACK;
b2 = new();
b2.copy(b1);
b1.name = "box2";
$display("%s", b1.sprint());
$display("%s", b2.sprint());
end
function bit compare (uvm_object rhs, uvm_comparer comparer=null);
compare()
方法时省略第二项参数,即采用默认的比较配置。uvm_object: :compare()
函数实现数据比较和消息打印。uvm_package::UVM_default_comparer
最大输出的错误比较信息是1,即比较错误发生时,不会再进行后续的比较。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_object_utils_end
...
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 compared with b1 failure", UVM_LOW)
end
else begin
`uvm_info("COMPARE", "b2 compared with b1 success", UVM_LOW)
end
end
输出结果:
UVM_INFO @ 0:reporter [MISCMP] Miscompare for box2.volume:Ihs ='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
通过域的自动化使声明后的各个成员域在调用uvm_object::print()
函数时自动打印它们的类型、大小和数值;相比设置断点逐步调试,打印是另一种调试方式,其好处在于可让仿真继续进行,在最终回顾执行过程中从全局理解执行的轨迹和逻辑。
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_object_utils_end
...
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
如果用户不对打印的格式做出修改,那么在打印时UVM会按照uvm_default_printer
规定的格式来打印:
uvm_default_tree_printer
:可以将对象按照树状结构打印;uvm_default_line_printer
: 可以将对象打印到一行上;uvm_default_table_printer
: 可以将对象按照表格的方式打印;uvm_default_printer
:UVM环境默认的打印设置,该句柄默认指向uvm_default_table_printer
。如果用户需要自定义一些打印的属性,用户可自建一个打印机,进而通过修改其属性uvm_printer::knobs
中的成员输出自己的打印格式。
function int pack (ref bit bitstream[], input uvm_packer packer=null);
function int unpack(ref bit bitstream[], input uvm_packer packer=null);
pack
是为了将自动化声明后的域(标量)打包为比特流(bit stream),将各个散乱的数据整理到bit数据串中,类似于struct packed的整理方式,但又能充分利用数据空间,也更容易与硬件之间进行数据传递和比对。unpack
则是将串行数据解包变为原有的各自域,该操作适用于从硬件一侧接受串行数据,进行校验后还原为软件一侧对象中各自对应的成员变量。uvm_packer
可以缺省,若用户不做指定,那么打包和解包uvm_packer将会使用uvm_pkg
中例化的全局对象uvm_default_packer
。do_pack()
回调函数。class box extends uvm_object;
int volume = 120;
int height = 20;
color_t color = WHITE;
`uvm_object_utils_begin(box)
...
endclass
box b1, b2;
bit packed_bits[]; //需先定义好打包存放的比特数组
initial begin
b1 = new("box1");
b2 = new("box2");
b1.volume = 100;
b1.height = 40;
b1.color = RED;
b1.print();
b1.pack(packed_bits);
//打包好的数据存入packed_bits比特数组,存放所有经过field automation的域值
$display("packed bits stream size is %d\n", packed_bits.size());
b2.unpack(packed_bits); //从packed_bits中解包,将数据存入到各自的各个域中
b2.print();
end