UVM factory/objection/virtual interface

UVM 树形结构:

在这里插入图片描述

在这里插入图片描述


driver:

// 只有driver的验证平台
module dut(clk,rst_n,rxd,rx_dv,txd,tx_en);
input clk;
input rst_n;    // 低电平复位
input[7:0] rxd;  // 接收数据
input rx_dv;   // 接收的数据有效指示
output [7:0] txd;  // 发送数据
output tx_en;    // 发送的数据有效指示

reg[7:0] txd;
reg tx_en;
always @(posedge clk)begin
	if(!rst_n)begin
		txd <= 8'b0;
		tx_en <= 1'b0;
	end
	else begin
		txd <= rxd;  // 发送数据
		tx_en <= rx_dv;
	end
end

endmodule

定义类

classs A;
	…
endclass

实例化类

A a_inst;
a_inst = new();  // 通过new创造出A的一个实例

my_driver.sv

UVM验证平台中的类driver应该派生自类uvm_driver,一个简单的driver如下例所示:

// 定义my_driver类
class my_driver extends uvm_driver;  // my_driver是一个派生自uvm_driver的类,uvm_driver是一个派生自uvm_component的类,要指明两个uvm_component参数:name和parent
	// 一个参数是string类型的name,就是这个类的示例的名字;一个是uvm_component类型的parent,以表明这个drive在uvm整个运行树中处于什么位置drive的parent就是input_agent,而input_agent的parent就是env。
	function new(string name = "my_driver", uvm_component parent = null);
		super.new(name, parent); // 执行父类的new函数
	endfunction

	extern virtual task main_phase(uvm_phase phase);
endclass // my_driver


// main_phase是uvm_driver中预先定义好的一个任务。因此几乎可以简单地认为,实现一个driver等于实现其main_phase。driver所做的事情几乎都在main_phase中完成
task my_driver::main_phase(uvm_phase phase);
	top_tb.rxd <= 8'b0;
	top_tb.rx_dv <= 1'b0;
	while(!top_tb.rst_n)
		@(posedge top_tb.clk);

	for(int i = 0; i < 256; i++)begin  // 是向rxd上发送256个随机数据
		@(posedge top_tb.clk);
		top_tb.rxd <= $urandom_range(0, 255);  
		top_tb.rx_dv <= 1'b1;  // 并将rx_dv信号置为高电平
		`uvm_info("my_driver", "data is drived", UVM_LOW) // uvm_info宏。这个宏的功能与Verilog中display语句的功能类似
	end

	@(posedge top_tb.clk);
	top_tb.rx_dv <= 1'b0;  // 数据发送完毕后,将rx_dv信号置为低电平
endtask

本节中uvm_info宏打印的结果如下

UVM_INFO my_driver.sv(20)@48500000:drv[my_driver]data is drived
// UVM_INFO关键字:表明这是一个uvm_info宏打印的结果。除了uvm_info宏外,还有uvm_error宏、uvm_warning宏
// my_driver.sv(20):指明此条打印信息的来源,其中括号里的数字表示原始的uvm_info打印语句在my_driver.sv中的行号
// 48500000:表明此条信息的打印时间
// drv:这是driver在UVM树中的路径索引。UVM采用树形结构,对于树中任何一个结点,都有一个与其相应的字符串类型的路径索引。路径索引可以通过get_full_name函数来获取,把下列代码加入任何UVM树的结点中就可以得知当前结点的路径索引:$display("the full name of current component is: %s", get_full_name());
// [my_driver]:方括号中显示的信息即调用uvm_info宏时传递的第一个参数。
// data is drived:表明宏最终打印的信息。

top_tb.sv

对my_driver实例化并且最终搭建的验证平台如下:

// 对my_driver实例化并且最终搭建的验证平台如下:
`timescale 1ns/1ps
`include "uvm_macros.svh"  // system verilog includ写法 `include "需要引用的文件"
`include "my_driver.sv"
import uvm_pkg::*;  // 导入uvm_pkg库

module top_tb;
	reg clk;
	reg rst_n;
	reg[7:0] rxd;
	reg rx_dv;
	wire[7:0] txd;
	wire tx_en;

	dut my_dut(
		.clk(clk),
		.rst_n(rst_n),
		.rx_dv(rx_dv),
		.txd(txd),
		.tx_en(tx_en)
		);

	initial begin
		my_driver drv;  // 定义一个my_driver类,名字是drv
		drv = new("drv", null); // 实例化 其传入的名字参数为drv,在真正的验证平台中,parent参数一般不是null,这里暂且使用null。

		drv.mian_phase(null); //调用my_driver的main_phase,本节的验证平台还算不上一个完整的UVM验证平台,所以暂且传入null。
		$finish();  // Verilog中提供的函数,结束仿真
	end

	initial begin
		clk = 0;
		forever begin
			#100 clk = ~clk;
		end
	end

	initial begin
		#1000;
		rst_n = 1'b1;
	end

endmodule

运行这个例子,可以看到“data is drived”被输出了256次


加入factory机制 objection机制:

在 top_tb.sv 中显示调用 driver.sv

initial begin
	my_driver drv;  // 定义一个my_driver类,名字是drv
	drv = new("drv", null); // 实例化 其传入的名字参数为drv,在真正的验证平台中,parent参数一般不是null,这里暂且使用null。
	
	drv.main_phase(null); //调用my_driver的main_phase,本节的验证平台还算不上一个完整的UVM验证平台,所以暂且传入null。
	$finish();  // Verilog中提供的函数,结束仿真		
end

在 top_tb.sv 中隐示调用 driver.sv,需要引入UVM的factory机制。
factory机制的实现被集成在了一个宏中:uvm_component_utils。
在UVM验证平台中,只要一个类使用uvm_component_utils注册且此类被实例化了,那么这个类的main_phase就会自动被调用。

// my_driver.sv
class my_driver extends uvm_driver; /
	//factory机制的实现被集成在了一个宏中:uvm_component_utils,要在定义一个新的类时使用这个宏
	`uvm_component_utils(my_driver)  // 在UVM验证平台中,只要一个类使用uvm_component_utils注册且此类被实例化了,那么这个类的main_phase就会自动被调用。
	... ...
endclass

task my_driver::main_phase(uvm_phase phase);
	phase.raise_objection(this);
	... ...
	phase.drop_objection(this);  // 将drop_objection语句当成是finish函数的替代者
endtask	
// top_tb.sv
module top_tb;
	... ...
	initial begin
		/*
		my_driver drv;  // 定义一个my_driver类,名字是drv
		drv = new("drv", null); // 实例化 其传入的名字参数为drv,在真正的验证平台中,parent参数一般不是null,这里暂且使用null。

		drv.main_phase(null); //调用my_driver的main_phase,本节的验证平台还算不上一个完整的UVM验证平台,所以暂且传入null。
		$finish();  // Verilog中提供的函数,结束仿真
		*/
		run_test("my_driver"); //一个run_test语句会创建一个my_driver的实例,并且会自动调用my_driver的main_phase。
	end
endmodule

输出
new is called
main_phased is called
在这里插入图片描述


加入virtual interface:

避免绝对路径的一个方法是使用宏:

// my_if.sv
// virtual interface

interface my_if(input clk, input rst_n);
	logic [7:0] data;
	logic valid;
endinterface

UVM引进了config_db机制,把top_tb中的input_if和my_driver中的vif对应起来。
在config_db机制中,分为set和get两步操作。所谓set操作,读者可以简单地理解成是“寄信”,而get则相当于是“收信”。

// top_tb.sv
module top_tb;
	... ...
	
	// 实例化接口
	my_if input_if(clk, rst_n);
	my_if output_if(clk, rst_n);
	
	// 例化DUT
	dut my_dut(
		.clk(clk),
		.rst_n(rst_n),
		.rxd(input_if.data)
		.rx_dv(input_if.valid),
		.txd(output_if.data),
		.tx_en(output_if.valid)
		);
		
	// UVM引进了config_db机制,把top_tb中的input_if和my_driver中的vif对应起来	
	// 在top_tb中执行set操作:set 寄信
	initial begin
		uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
		//uvm_config_db#(virtual 接口module名)::set( ,路径索引, , 例化的接口)?
	end
	... ...
endmodule
class my_driver extends uvm_driver; // my_driver是一个派生自uvm_driver的类,uvm_driver是一个派生自uvm_component的类,要指明两个uvm_component参数:name和parent
	
	virtual my_if vif;  // 声明vif
	... ...
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		`uvm_info("my_driver", "build_phase is called", UVM_LOW);
		if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
			`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")  // 了vm_fatal宏,
	endfunction
	
	... ...
endclass 

task my_driver::main_phase(uvm_phase phase);
	phase.raise_objection(this);
	// my_driver中,执行get操作
	super.build_phase(phase);

	`uvm_info("my_driver", "main_phase is called", UVM_LOW);
	/*
	top_tb.rxd <= 8'b0;
	top_tb.rx_dv <= 1'b0;
	*/
	vif.data <= 8'b0;
	vif.valid <= 1'b0;

	while(!vif.rst_n)  // while(!top_tb.rst_n)
		@(posedge vif.clk);  // @(posedge top_tb.clk);

	for(int i = 0; i < 256; i++)begin  // 是向rxd上发送256个随机数据
		@(posedge vif.clk);  // @(posedge top_tb.clk);
		vif.data <= $urandom_range(0, 255);   // top_tb.rxd <=
		vif.valid <= 1'b1;  // 并将rx_dv信号置为高电平  // top_tb.rx_dv <=
		`uvm_info("my_driver", "data is drived", UVM_LOW) // uvm_info宏。这个宏的功能与Verilog中display语句的功能类似
	end

	@(posedge vif.clk);  // @(posedge top_tb.clk);
	vif.valid <= 1'b0;  // top_tb.rx_dv // 数据发送完毕后,将rx_dv信号置为低电平

	phase.drop_objection(this);
endtask


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UVM中,可以使用uvm_config_db的set和get方法来设置和获取配置信息。这些方法可以用于在不同的组件之间传递数据。引用\[1\]中的代码示例展示了如何使用uvm_config_db的set方法来设置一个接口数组。在这个例子中,使用了一个for循环来遍历接口数组,并将每个接口设置到配置数据库中。引用\[2\]中的代码示例展示了set方法的另一种用法,其中第一个参数是一个环境对象,第二个参数是一个字符串,用于指定配置的位置,第三个参数是配置的名称,第四个参数是配置的值。引用\[3\]中提到,在传递虚拟接口时,可以将第一个参数设置为null,UVM会自动将其替换为uvm_root::get(),即替换为uvm_top。uvm_top是uvm_root的一个唯一实例,是UVM的树根,也是一个全局变量,可以直接使用。 #### 引用[.reference_title] - *1* [UVMinterface数组的set,get](https://blog.csdn.net/zhajio/article/details/101195556)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [uvm_config_db的set()与get()方法](https://blog.csdn.net/weixin_42294124/article/details/125016224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值