文章目录
前言
本章内容主要对UVM实战第8章的内容做出总结
一、加入factory机制及其优点
factory机制最神奇的一点:可以自动创建一个类的实例并调用其中的函数(function)和任务(task)。举例如下:
class my_driver extends uvm_driver;
`uvm_component_utils(my_driver) //将my_driver登记在UVM内部的一张表中,即加入factory机制
function new(string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
`uvm_info("my_driver", "new is called", UVM_LOW);
endfunction
extern virtual task main_phase(uvm_phase phase);
endclass
factory机制的实现被集成在了一个宏中:uvm_component_rtils,作用如下:
- 该宏将my_driver登记在UVM内部的一张表中
- 可以根据类名创建一个my_driver的实例,如在hw_tb中run_test(“my_driver”)
- 自动调用my_driver的main_phase
二、重载
1. system verilog对重载的支持
1.1 任务与函数的重载
重载:当在父类定义一个函数/任务时,如果将其设置为virtual类型,那么就可以在子类中重载这个函数/任务。
优势:重载的最大优势是使得一个子类的指针以父类的类型传递时,其表现出的行为依然是子类的行为。
举例如下:
class bird extends uvm_object;//父类
virtual function void hungry();
$display("I am a bird, I am hungry");
endfunction
function void hungry2();
$display("I am a bird, I am hungry2");
endfunction
`uvm_object_utils(bird)
function new(string name = "bird");
super.new(name);
endfunction
endclass
class parrot extends bird;//子类
virtual function void hungry();
$display("I am a parrot, I am hungry");
endfunction
function void hungry2();
$display("I am a parrot, I am hungry2");
endfunction
`uvm_object_utils(parrot)
function new(string name = "parrot");
super.new(name);
endfunction
endclass
...
function void my_case0::print_hungry(bird b_ptr);//表示能接收的函数类型是bird
b_ptr.hungry();
b_ptr.hungry2();
endfunction
function void my_case0::build_phase(uvm_phase phase);
bird bird_inst;
parrot parrot_inst;
super.build_phase(phase);
bird_inst = bird::type_id::create("bird_inst");
parrot_inst = parrot::type_id::create("parrot_inst");
print_hungry(bird_inst);//b_ptr指向的实例是bird类型,b_ptr本身也是bird类型
print_hungry(parrot_inst);//b_ptr指向的实例是parrot类型,而b_ptr本身虽然是parrot类型,
//但是在调用hungry函数时,它被隐式地转换成了bird类型。打印结果如下:
//I am a parrot, I am hungry
//I am a bird, I am hungry2
endfunction
上述代码第40行,实际就是一个重载的过程,parrot是子类,bird是父类,parrot将bird重载,或者说parrot将bird覆盖。在这个过程中,将parrot.hungry函数覆盖了bird.hungry,因为hungry是virtual类型的,可以被覆盖。
所以,按照书中描述,parrot的指针parrot_inst是以父类(bird)的类型传递,其表现出来的行为依然是子类的行为,因为父类的hungry被子类的hungry覆盖了。
1.2 约束的重载
假如一个接收MAC功能的DUT,有多种异常情况需要测试,如preamble错误、sfd错误、CRC错误。这些错误都是异常的情况,在大部分测试用例中,它们的值应该为0。在异常的测试用例中,它们值应该为1。如何实现呢?有两种方法:
第一:在定义transaction时,约束成0,在异常的测试用例中,使用`uvm_rand_send_with重新约束,代码如下:
class my_transaction extends uvm_sequence_item;
...
constraint crc_err_cons{
crc_err == 1'b0;
}
constraint sfd_err_cons{
sfd_err == 1'b0;
}
constraint pre_err_cons{
pre_err == 1'b0;
}
...
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(dmac, UVM_ALL_ON)
`uvm_field_int(smac, UVM_ALL_ON)
`uvm_field_int(ether_type, UVM_ALL_ON)
`uvm_field_array_int(pload, UVM_ALL_ON