UVM入门与进阶学习笔记2——核心基类

目录

    • uvm_object
    • 域的自动化
    • copy和clone的区别
    • 比较(compare)
    • 打印(print)
    • 打包和解包(pack&unpack)


UVM入门与进阶学习笔记2——核心基类_第1张图片

uvm_object

  • UVM世界的类都是从uvm_void根类继承,实际上该类并没有成员变量和方法
  • uvm_void只是一个虚类,还在等待将来继承于它的子类去开垦。继承于它的子类中有uvm_object类和uvm_port_base类。
  • UVM世界的类库地图中除事务接口类继承于uvm_port_base其他所有类都从uvm_object类一步步继承。

uvm_object的核心方法主要提供与数据操作的相关服务copy、clone、compare、print、pack/unpack(无论是copy或clone,都需要确保在操作的过程中需要有source object和target object)。

域的自动化

  • UVM通过域的自动化使用户在注册UVM类的同时也可以声明今后会参与到对象拷贝、克隆、打印等操作的成员变量
  • 域的自动化解放了verifier,使得在使用uvm_object提供的一些预定义方法时非常便捷,而无需再实现自定义方法。
  • 用户需考虑哪些成员变量在注册UVM类时一并将它们归置到对应的域列表中,以便为稍后的域方法提供可自动实现的基础。
    UVM入门与进阶学习笔记2——核心基类_第2张图片
    UVM入门与进阶学习笔记2——核心基类_第3张图片
    UVM入门与进阶学习笔记2——核心基类_第4张图片
    注:ARG表示成员变量;FLAG表示用来标记的数据操作
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

copy和clone的区别

前者默认已经创建好了对象,只需对数据进行拷贝;后者会自动创建对象并对source object进行数据拷贝,再返回target object句柄。两者都需要对数据进行复制。

  • 进行copy时,默认进行的是深拷贝(deep copy),即会执行copy()和do_copy()
  • 拷贝的执行过程:先执行自动拷贝copy()拷贝允许拷贝的域,再执行do_copy()函数(需用户定义的回调函数),若用户没定义则不会执行额外的数据操作。
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

UVM入门与进阶学习笔记2——核心基类_第5张图片

比较(compare)

  • function bit compare (uvm_object rhs, uvm_comparer comparer=null);
  • 默认情况若不对比较的情况作出额外配置,用户可在调用compare()方法时省略第二项参数,即采用默认的比较配置。
  • 比较方法常在两个数据类中进行,若它们为同一类型,除了可以自定义数据比较之外,也可直接使用uvm_object: :compare()函数实现数据比较和消息打印
  • 在执行compare()函数时,内置的比较方法也会将比较错误输出
  • uvm_package::UVM_default_comparer最大输出的错误比较信息是1,即比较错误发生时,不会再进行后续的比较
  • 在uvm_object使用到的方法compare()、print()和pack(),如果没有指定数据操作配置对象作为参数时,会使用在uvm_pkg中例化的全局数据操作配置成员。
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

打印(print)

通过域的自动化使声明后的各个成员域在调用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入门与进阶学习笔记2——核心基类_第6张图片
如果用户不对打印的格式做出修改,那么在打印时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中的成员输出自己的打印格式。

打包和解包(pack&unpack)

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则是将串行数据解包变为原有的各自域,该操作适用于从硬件一侧接受串行数据,进行校验后还原为软件一侧对象中各自对应的成员变量
  • 该操作完成了大型标量数据的整形串发,主要面向SV与硬件和其它语言接口直接的精确通信
  • 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

你可能感兴趣的:(UVM入门与进阶,测试用例,测试覆盖率,功能测试)