UVM学习——搭建简单的UVM平台


 


引言

本专栏的博客均与 UVM 的学习相关,学习参考:

 【1】UVM Tutorial

 【2】张强著,UVM实战 (卷 Ⅰ)

 【3】Download UVM (Standard Universal Verification Methodology)

本专栏的学习基本依照 资料【2】的主线,以【1】【3】资料作为参考。特别是【3】是官方的UVM手册,具有很高的可参考性以及权威性。

本文则先搭建一个简单的 UVM 平台,了解其思想和机制。

UVM 平台:Questa Sim - 64 10.6c (Win 10)


验证平台的组成有哪些?

验证的对象是前端设计工程师提交的硬件设计代码(Verilog),验证的目的就是设计各种验证case,观察前端工程师设计的电路是否符合spec里要求的各项指标以及功能。简单的验证平台结构如下图所示,driver 负责将相同的激励同时给到 DUT 和参考模型,monitor 负责接收 DUT的各个响应结果送至计分板将二者的结果进行比对,给出验证结果,pass or fail。

在 UVM 中,引入了 agent 和  sequence 的概念,因此UVM中验证平台的典型框图:

只有 driver 的验证平台

搭建最简单的验证平台

假设待分析的设计为数据转发模块:

Design

module Design(
input clk,
input rstn,
input [7:0] rxd,
input rxval,
output reg tx_en,
output reg [7:0] txd
);

always @ (posedge clk)
begin
	if(~rstn)
	begin
		txd <= 0;
		tx_en <= 0;
	end
	else
	begin
		tx_en <= rxval;
		txd <= rxd;
	end
end
endmodule

Driver

class Driver extends uvm_driver;

	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
	endfunction

	extern virtual task main_phase(uvm_phase phase);
endclass 

task Driver::main_phase(uvm_phase phase); 
	Top_tb.rxd <= 8'd0;  
	Top_tb.rx_val <= 1'b0;  
	while(~Top_tb.rstn)//等待复位完成  
	begin 
		@(posedge Top_tb.clk); 
	end
	// 随机数激励
	for(int k = 0;k<256;k++) 
	begin
		@(posedge Top_tb.clk);
		Top_tb.rxd <= $urandom_range(0,255);
		Top_tb.rx_val <= 1'b1;	
		`uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)		
	end
	// 有效信号拉低
	@(posedge Top_tb.clk);
	Top_tb.rx_val <= 1'b0;
endtask

 对于 `uvm_info 宏的使用,这里建议查阅 UVM 的使用手册,很详细:

Top_tb

`timescale 1ns/1ns
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "Driver.sv"

module Top_tb ();
reg clk;
reg rstn;
reg [7:0] rxd;
reg rx_val;
wire tx_en;
wire [7:0] txd;

Design inst_Design (.clk(clk), .rstn(rstn), .rxd(rxd), .rx_val(rx_val), .tx_en(tx_en), .txd(txd));

initial
begin
	Driver drv;
	drv = new("Driver",null);
	drv.main_phase(null);
	$finish;
end

initial clk = 0;
always #10 clk = ~clk;

initial
begin
	rstn = 1'b0;
	#138 rstn = 1'b1;
end
endmodule

在 Questa Sim 中,仅需要对 顶层仿真文件编译,不需要对各个组件编译:

`include "uvm_macros.svh"     

将对应的宏定义文件读取进来,这在编译开始之前进行的操作。

import uvm_pkg::*     

将整个uvm_pkg 导入验证平台,这样才能在自己的验证平台使用 uvm的各种库。

以上这两个操作在后续的所有验证平台的顶层都应包括进去。

仿真

编译完成后,在脚本处,执行仿真:

vsim -voptargs=+acc work.Top_tb +UVM_NO_RELNOTES

文件加载完成后 ,在脚本处 执行 run 命令,即可看到仿真结果:

加入 factory 机制

factory 机制,使用 uvm_component_utils 宏来实现。此宏会根据类型,自动创建一个实例并且这个类的 main_phase 会被自动调用。

Driver 文件作如下改动:

class Driver extends uvm_driver;

	`uvm_component_utils(Driver)
	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
		`uvm_info("Driver","new is called",UVM_LOW)
	endfunction

	extern virtual task main_phase(uvm_phase phase);
endclass 

task Driver::main_phase(uvm_phase phase);
	`uvm_info("Driver","main_phase is called",UVM_LOW)
	Top_tb.rxd <= 8'd0;  
	Top_tb.rx_val <= 1'b0;  
	while(~Top_tb.rstn)//等待复位完成  
	begin 
		@(posedge Top_tb.clk); 
	end
	// 随机数激励
	for(int k = 0;k<256;k++) 
	begin
		@(posedge Top_tb.clk);
		Top_tb.rxd <= $urandom_range(0,255);
		Top_tb.rx_val <= 1'b1;	
		`uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)		
	end
	// 有效信号拉低
	@(posedge Top_tb.clk);
	Top_tb.rx_val <= 1'b0;
endtask

顶层文件 Top_tb 改动后的结果:

一个run_test语句会创建一个my_driver的实例,并且会自动调用my_driver的main_phase。

`timescale 1ns/1ns
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "Driver.sv"

module Top_tb ();
reg clk;
reg rstn;
reg [7:0] rxd;
reg rx_val;
wire tx_en;
wire [7:0] txd;

Design Inst_Design (
	.clk(clk), 
	.rstn(rstn), 
	.rxd(rxd), 
	.rx_val(rx_val), 
	.tx_en(tx_en), 
	.txd(txd)
);

initial 
begin 
	// Driver drv;		 								
	// drv = new("Driver",null);		 								
	// drv.main_phase(null);		 								
	run_test("Driver");		 								
	// $finish;		 								
end 							

initial clk = 0;
always #10 clk = ~clk;

initial
begin
	rstn = 1'b0;
	#138 rstn = 1'b1;
end
endmodule

 上图是 run_test 的使用说明。

编译后执行仿真:

发现仿真结果中,只打印到 main_phased is called,后面的随机数激励部分没有执行。此处引出了 UVM 的objection 机制。

加入objection机制

UVM中通过objection机制来控制验证平台的关闭。在每个phase中,UVM会检查是否有objection被提起 (raise_objection),如果有,那么等待这个objection被撤销(drop_objection)后停止仿真;如果没有,则马上结束当前phase。

可以简单地将drop_objection语句当成是finish函数的替代者,只是在drop_objection语句之前必须先调用 raise_objection语句,raise_objection和drop_objection总是成对出现。

加入 objection 机制的 Driver 代码:

class Driver extends uvm_driver;

	`uvm_component_utils(Driver)
	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
		`uvm_info("Driver","new is called",UVM_LOW)
	endfunction

	extern virtual task main_phase(uvm_phase phase);
endclass 

task Driver::main_phase(uvm_phase phase);
	phase.raise_objection(this);
	`uvm_info("Driver","main_phase is called",UVM_LOW)				
	Top_tb.rxd <= 8'd0;				  
	Top_tb.rx_val <= 1'b0;				  
	while(~Top_tb.rstn)//等待复位完成				  
	begin				 
		@(posedge Top_tb.clk);				 
	end				
	// 随机数激励
	for(int k = 0;k<256;k++) 
	begin
		@(posedge Top_tb.clk);
		Top_tb.rxd <= $urandom_range(0,255);
		Top_tb.rx_val <= 1'b1;	
		`uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)		
	end
	// 有效信号拉低
	@(posedge Top_tb.clk);
	Top_tb.rx_val <= 1'b0;
	phase.drop_objection(this);
endtask

编译后执行仿真:

raise_objection 语句必须在 main_phase 中第一个消耗仿真时间的语句之前。如$display语句是不消耗仿真时间的,这些语句可 以放在raise_objection之前,但是类似@(posedge top.clk)等语句是要消耗仿真时间的。按照如下的方式使用raise_objection是无法起到作用的。

Driver 类的代码修改:

class Driver extends uvm_driver;

	`uvm_component_utils(Driver)
	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
		`uvm_info("Driver","new is called",UVM_LOW)
	endfunction

	extern virtual task main_phase(uvm_phase phase);
endclass 

task Driver::main_phase(uvm_phase phase);
	@(posedge Top_tb.clk);
	phase.raise_objection(this);
	`uvm_info("Driver","main_phase is called",UVM_LOW)				
	Top_tb.rxd <= 8'd0;				  
	Top_tb.rx_val <= 1'b0;				  
	while(~Top_tb.rstn)//等待复位完成				  
	begin				 
		@(posedge Top_tb.clk);				 
	end				
	// 随机数激励
	for(int k = 0;k<256;k++) 
	begin
		@(posedge Top_tb.clk);
		Top_tb.rxd <= $urandom_range(0,255);
		Top_tb.rx_val <= 1'b1;	
		`uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)		
	end
	// 有效信号拉低
	@(posedge Top_tb.clk);
	Top_tb.rx_val <= 1'b0;
	phase.drop_objection(this);
endtask

仿真结果:

加入 virtual interface

未引入 虚拟接口 时,验证平台的端口索引是通过模块之间层级的绝对路径来索引,比如上面的Driver类内的 Top_tb.rx_val <= 1'b0; 这种接口的索引很不利于验证平台的移植。使用宏定义也可以在一定程度缓解这种问题,但是最根本的解决方案还是要引入虚拟接口。

在类内引入非虚拟接口,在编译时会报语法错误。在模块(module)内可以引入非虚拟接口。虚拟接口在实例化时需要声明 virtual 。

interface 文件:

interface Interface (input clk,input rstn);

	logic [7:0] data;
	logic val;
endinterface

接口引入的目的就是方便驱动 Driver 和 仿真顶层 Top_tb 之间更友好地(代码可移植性更高)连接。那么二者之间具体如何连接?UVM引进了config_db 机制。在config_db机制中,分为set和get两步操作。所谓set操作,读者可以简单地理解成是“寄信”,而get则相当于是“收信”。可以向驱动器 Driver 寄同类型的不同实例对应的“信”,也可以寄不同类型的“信”。对于收侧也一样。

Driver 中需要引入 build_phase 。与main_phase一样,build_phase也是UVM中内建的一个phase。当UVM启动后,会自动执行 build_phase。build_phase在new函数之后main_phase之前执行。在build_phase中主要通过config_db的 setget 操作来传递一些数据, 以及实例化成员变量等

Driver 类的改变:

class Driver extends uvm_driver;

	virtual Interface Virtual_Driver_if;
	`uvm_component_utils(Driver)
	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
		`uvm_info("Driver","new is called",UVM_LOW)
	endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("Driver", "build_phase is called", UVM_LOW);
      if(!uvm_config_db#(virtual Interface)::get(this, "", "vif", Virtual_Driver_if))
         `uvm_fatal("Driver", "virtual interface must be set for vif!!!")
   endfunction	

	extern virtual task main_phase(uvm_phase phase);
endclass 

task Driver::main_phase(uvm_phase phase);									
	phase.raise_objection(this);									
	`uvm_info("Driver","main_phase is called",UVM_LOW)													
	Virtual_Driver_if.data <= 8'd0;													  
	Virtual_Driver_if.val <= 1'b0;													  
	while(~Virtual_Driver_if.rstn)//等待复位完成													  
	begin				 
		@(posedge Virtual_Driver_if.clk);				 
	end				
	// 随机数激励
	for(int k = 0;k<256;k++) 
	begin
		@(posedge Virtual_Driver_if.clk);
		Virtual_Driver_if.data <= $urandom_range(0,255);
		Virtual_Driver_if.val <= 1'b1;	
		`uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Virtual_Driver_if.data),UVM_LOW)		
	end
	// 有效信号拉低
	@(posedge Virtual_Driver_if.clk);
	Virtual_Driver_if.val <= 1'b0;
	phase.drop_objection(this);
endtask

上面的代码用到了 uvm_fatal 。与uvm_info宏不同的是,当它打印第二个参数所示的信息后,会直接调用Verilog的finish函数来结束仿真。uvm_fatal的出现表示验证平台出现了重大问题而无法继续下去,必须停止仿真并做相应的检查。所以对于uvm_fatal来 说,uvm_info中出现的第三个参数的冗余度级别是完全没有意义的,只要是uvm_fatal打印的信息,就一定是非常关键的,所以无需设置第三个参数。

关于 uvm_config_db :

 与之有关的函数均为静态函数,所以在调用时要用 :: 操作符。 

config_db的 set 和 get 函数都有四个参数,这两个函数的第三个参数必须完全一致。

set函数的第四个参数表示要将哪个interface 通过config_db传递给my_driver,get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。

set函数的第二个参数表示的是路径索引,即在前面介绍uvm_info宏时提及的路径索引。在top_tb中通过run_test创建了一个my_driver的实例,那么 这个实例的名字是什么呢?答案是uvm_test_top:UVM通过run_test语句创建一个名字为uvm_test_top的实例。无论传递给run_test 的参数是什么,创建的实例的名字都为 uvm_test_top由于set操作的目标是my_driver,所以set函数的第二个参数就是uvm_test_top。set函数的第一个参数null以及get函数的第一和第二个参数可以暂时放在一边,后文会详细说明。

uvm_config_db#(virtual Interface)则是一个参数化的类,其参数就是要寄信的类型,这里是virtual my_if。

手册的具体说明:

Top_tb 的变动:

`timescale 1ns/1ns
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "Interface.sv"
`include "Driver.sv"


module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;

Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);

Design Inst_Design (
	.clk(clk), 
	.rstn(rstn), 
	.rxd(Input_if.data), 
	.rx_val(Input_if.val), 
	.tx_en(Output_if.data), 
	.txd(Output_if.val)
);

initial 
begin 
	// Driver drv;		 								
	// drv = new("Driver",null);		 								
	// drv.main_phase(null);		 								
	run_test("Driver");		 								
	// $finish;		 								
end 							

initial clk = 0;
always #10 clk = ~clk;

initial
begin
	rstn = 1'b0;
	#138 rstn = 1'b1;
end

initial begin
   uvm_config_db#(virtual Interface)::set(null, "uvm_test_top", "vif", Input_if);
end


endmodule

编译后执行仿真:

给验证平台加入其他组件

加入 transaction

transaction 的翻译为事务。那么到底什么是事务?这其实是一个很抽象的概念。通俗来讲,可以将 transaction 理解为一次完整的激励。一般驱动器的数据激励都是基于 transaction 进行传输。

此处,参考书以以太网协议的数据包为例,做一个说明。


class Transaction extends  uvm_sequence_item;
	rand bit [47:0] dmac;
	rand bit [47:0] smac;
	rand bit [47:0] ether_type;
	rand byte 		pload[];
	rand bit [31:0] crc;

	constraint pload_cons{
		pload.size >= 46;
		pload.size <= 1500;
	}

	function bit [31:0] calc_crc();
		return 32'h0;
	endfunction

	function void post_randomize();
		crc = calc_crc;
	endfunction

	`uvm_object_utils(Transaction);

	function new (string name = "Transaction");
		super.new(name);
	endfunction
endclass 

post_randomize是SystemVerilog中提供的一个函数,当某个类的实例的randomize函数被调用后,post_randomize会紧随其后无条件 地被调用。

Transaction的基类是uvm_sequence_item。在UVM中,所有的 transaction都 要从uvm_sequence_item派生,只有从uvm_sequence_item派生的transaction才可以使用UVM中sequence机制。

这里没有使用 uvm_component_utils 宏来实现factory机制,而是使用了uvm_object_utils。从本质上来说,my_transaction与 my_driver是有区别的,在整个仿真期间,my_driver是一直存在的,my_transaction不同,它有生命周期。它在仿真的某一时间产 生,经过driver驱动,再经过reference model处理,最终由scoreboard比较完成后,其生命周期就结束了。一般来说,这种类都是派 生自uvm_object或者uvm_object的派生类,uvm_sequence_item的祖先就是uvm_object。UVM中具有这种特征的类都要使用 uvm_object_utils宏来实现。

Driver 程序:

class Driver extends uvm_driver;

	virtual Interface Virtual_Driver_if;
	`uvm_component_utils(Driver)
	function new(string name = "Driver",uvm_component parent = null);
		super.new(name,parent);
		`uvm_info("Driver","new is called",UVM_LOW)
	endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("Driver", "build_phase is called", UVM_LOW);
      if(!uvm_config_db#(virtual Interface)::get(this, "", "vif", Virtual_Driver_if))
         `uvm_fatal("Driver", "virtual interface must be set for vif!!!")
   endfunction	

	extern  task main_phase(uvm_phase phase);
	extern  task drive_one_pkt(Transaction tr);
endclass  

task Driver::main_phase(uvm_phase phase);	
	Transaction tr;							
	phase.raise_objection(this);									
	`uvm_info("Driver","main_phase is called",UVM_LOW)													
	Virtual_Driver_if.data <= 8'd0;													  
	Virtual_Driver_if.val <= 1'b0;													  
	while(~Virtual_Driver_if.rstn)//等待复位完成													  
	begin				 
		@(posedge Virtual_Driver_if.clk);				 
	end				
	// 随机数激励
	for(int k = 0;k<1;k++) 
	begin
		tr = new("tr");
		assert(tr.randomize() with{pload.size == 200;});
		drive_one_pkt(tr);
		`uvm_info("Driver",$sformatf("Randomize successfully ! "),UVM_LOW)	
	end
	// 有效信号拉低
	repeat(10) @(posedge Virtual_Driver_if.clk);
	phase.drop_objection(this);
endtask

task Driver::drive_one_pkt(Transaction tr);
	bit [47:0] tmp_data;
	bit [7:0] data_q[$];

   `uvm_info("Driver", "Random Package Data Generate Start ...", UVM_LOW);
   //push dmac to data_q
   tmp_data = tr.dmac;
   `uvm_info("Driver",$sformatf("dmac = 0x%0h",tr.dmac),UVM_LOW)
   for(int i = 0; i < 6; i++) begin
      data_q.push_back(tmp_data[7:0]);
      tmp_data = (tmp_data >> 8);
   end
   
   //push smac to data_q
   tmp_data = tr.smac;
   `uvm_info("Driver",$sformatf("smac = 0x%0h",tr.smac),UVM_LOW)
   for(int i = 0; i < 6; i++) begin
      data_q.push_back(tmp_data[7:0]);
      tmp_data = (tmp_data >> 8);
   end

   //push ether_type to data_q
   tmp_data = tr.ether_type;
   `uvm_info("Driver",$sformatf("ether_type = 0x%0h",tr.ether_type),UVM_LOW)
   for(int i = 0; i < 2; i++) begin
      data_q.push_back(tmp_data[7:0]);
      tmp_data = (tmp_data >> 8);
   end

   //push payload to data_q
   for(int i = 0; i < tr.pload.size; i++) begin
      data_q.push_back(tr.pload[i]);
      `uvm_info("Driver",$sformatf("pload[%0d] = 0x%0h",i,tr.pload[i]),UVM_LOW)
   end
   //push crc to data_q
   tmp_data = tr.crc;
   `uvm_info("Driver",$sformatf("crc = 0x%0h",tr.crc),UVM_LOW)
   for(int i = 0; i < 4; i++) 
   begin
      data_q.push_back(tmp_data[7:0]);
      tmp_data = (tmp_data >> 8);
   end
	`uvm_info("Driver", "Random Package Data Generate end ...", UVM_LOW);

   `uvm_info("Driver", "begin to drive one pkt", UVM_LOW);
   repeat(3) @(posedge Virtual_Driver_if.clk);

   while(data_q.size() > 0) 
   begin
      @(posedge Virtual_Driver_if.clk);
      Virtual_Driver_if.val <= 1'b1;
      Virtual_Driver_if.data <= data_q.pop_front(); 
   end

   repeat (10) @(posedge Virtual_Driver_if.clk);
   Virtual_Driver_if.val <= 1'b0;
   `uvm_info("Driver", "end drive one pkt", UVM_LOW);	
endtask

在main_phase中,先使用randomize将tr随机化,之后通过drive_one_pkt任务将tr的内容驱动到DUT的端口上。在drive_one_pkt 中,先将tr中所有的数据压入队列data_q中,之后再将data_q中所有的数据弹出并驱动。将tr中的数据压入队列data_q中的过程相当 于打包成一个byte流的过程。

编译后执行仿真:

加入 environment

environment 就像是一个大的容器内部包含了 计分板、参考模型、监视器、驱动器等组件。在调用 run_test时,传递的参数不再是my_driver,而是这个容器类,即让UVM自动创建这个容器类的实例。在UVM中,这个容器类称为 uvm_env。


class Environment extends  uvm_env;

	Driver drv;

	function new(string name = "env",uvm_component parent);
		super.new(name,parent);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		drv = Driver::type_id::create("drv",this);
	endfunction

	`uvm_component_utils(Environment)
endclass 

所有的 environment 应该派生自uvm_env,且与Driver一样,容器类在仿真中也是一直存在的,使用uvm_component_utils宏来实现 factory的注册。

在my_env的定义中,最让人难以理解的是第14行drv的实例化。这里没有直接调用my_driver的new函数,而是使用了一种古怪 的方式。这种方式就是factory机制带来的独特的实例化方式。只有使用factory机制注册过的类才能使用这种方式实例化;只有使 用这种方式实例化的实例,才能使用后文要讲述的factory机制中最为强大的重载功能。验证平台中的组件在实例化时都应该使用 type_name::type_id::create的方式。

new函数有两个参数,第一个参数是实例的名字,第二个则是parent。由于my_driver在uvm_env中实例化,所以my_driver 的父结点(parent)就是my_env。通过parent的形式,UVM建立起了树形的组织结构。在这种树形的组织结构中,由run_test创建 的实例是树根(这里是my_env),并且树根的名字是固定的,为uvm_test_top,这在前文中已经讲述过;在树根之后会生长出枝 叶(这里只有my_driver),长出枝叶的过程需要在my_env的build_phase中手动实现。无论是树根还是树叶,都必须由 uvm_component或者其派生类继承而来。整棵UVM树的结构如图所示。

当加入了my_env后,整个验证平台中存在两个build_phase,一个是my_env的,一个是my_driver的。那么这两个build_phase按 照何种顺序执行呢?在UVM的树形结构中,build_phase的执行遵照从树根到树叶的顺序,即先执行my_env的build_phase,再执行 my_driver的build_phase。当把整棵树的build_phase都执行完毕后,再执行后面的phase。

my_driver在验证平台中的层次结构发生了变化,它从树根变成了树叶,所以在Top_tb中使用config_db机制传递virtual Interface时,要改变相应的路径;同时,run_test的参数也从Driver变为了Environment:

`timescale 1ns/1ns
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "Interface.sv"
`include "Transaction.sv"
`include "Driver.sv"
`include "Environment.sv"


module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;

Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);

Design Inst_Design (
	.clk(clk), 
	.rstn(rstn), 
	.rxd(Input_if.data), 
	.rx_val(Input_if.val), 
	.tx_en(Output_if.data), 
	.txd(Output_if.val)
);

initial 
begin 
	// Driver drv;		 								
	// drv = new("Driver",null);		 								
	// drv.main_phase(null);		 								
	// run_test("Driver");	
	run_test("Environment");			 								
	// $finish;		 								
end 							

initial clk = 0;
always #10 clk = ~clk;

initial
begin
	rstn = 1'b0;
	#138 rstn = 1'b1;
end

initial begin
   uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.drv", "vif", Input_if);
end


endmodule

set函数的第二个参数从uvm_test_top变为了uvm_test_top.drv,其中uvm_test_top是UVM自动创建的树根的名字,而drv则是在 my_env的build_phase中实例化drv时传递过去的名字。如果在实例化drv时传递的名字是my_drv,那么set函数的第二个参数中也应该是my_drv

加入 monitor

monitor 存在的意义就是将 DUT 输出的响应结果送入计分板,判断其响应的正确性。

验证平台中实现监测DUT行为的组件是monitor。driver负责把transaction级别的数据转变成DUT的端口级别,并驱动给DUT, monitor的行为与其相对,用于收集DUT的端口数据,并将其转换成transaction交给后续的组件如reference model、scoreboard等处理。

Monitor:


class Monitor extends  uvm_monitor;
	virtual Interface vif;
	`uvm_component_utils(Monitor)
	function new (string name = "Monitor",uvm_component parent = null);
		super.new(name,parent);
	endfunction 

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		if(!uvm_config_db #(virtual Interface)::get(this,"","vif",vif))
			`uvm_fatal("Monitor","virtual interface must be set for vif !")
	endfunction

	extern task main_phase(uvm_phase phase);
	extern task collect_one_pkt(Transaction tr);

endclass 

task Monitor::main_phase(uvm_phase phase);
	Transaction tr;
	while(1)
	begin
		tr = new("tr");
		collect_one_pkt(tr);
	end
	
endtask 

task Monitor::collect_one_pkt(Transaction tr);
	bit[7:0] data_q[$];
	int psize;
	while(1)
	begin
		@(posedge vif.clk);
		if(vif.val) break;
	end

	`uvm_info("Monitor","begin to collect one package",UVM_LOW);
	while(vif.val)
	begin
		data_q.push_back(vif.data);
		@(posedge vif.clk);
	end
	`uvm_info("Monitor",$sformatf("collect one package,size=%0d",data_q.size()),UVM_LOW);
	// pop out to tr
	for (int i=0;i<6;i++)
	begin
		tr.dmac = {tr.dmac[39:0],data_q.pop_front()};
	end
	for (int i=0;i<6;i++)
	begin
		tr.smac = {tr.smac[39:0],data_q.pop_front()};
	end
	for (int i=0;i<2;i++)
	begin
		tr.dmac = {tr.dmac[39:0],data_q.pop_front()};
	end
   psize = data_q.size() - 4;
   `uvm_info("Monitor",$sformatf("pload data size=%0d",psize),UVM_LOW);
   tr.pload = new[psize];
   //pop payload
   for(int i = 0; i < psize; i++) begin
      tr.pload[i] = data_q.pop_front();
   end
   //pop crc
   for(int i = 0; i < 4; i++) begin
      tr.crc = {tr.crc[23:0], data_q.pop_front()};
   end
   `uvm_info("Monitor", "end collect one package, print it:", UVM_LOW);
    tr.Print();	
endtask 

第一,所有的monitor类应该派生自uvm_monitor

第二,与driver类似,在my_monitor中也需要有一个virtual Interface;

第三,uvm_monitor在整个仿真中是一直存在的,所以它是一个component,要使用uvm_component_utils宏注册;

第四,由于monitor需要时刻收集数据,永不停歇,所以在main_phase中使用while(1)循环来实现这一目的。 

Transaction 部分修改:


class Transaction extends  uvm_sequence_item;
	rand bit [47:0] dmac;
	rand bit [47:0] smac;
	rand bit [15:0] ether_type;
	rand byte 		pload[];
	rand bit [31:0] crc;

	constraint pload_cons{
		pload.size >= 46;
		pload.size <= 1500;
	}

	function bit [31:0] calc_crc();
		return 32'h0;
	endfunction

	function void post_randomize();
		crc = calc_crc;
	endfunction

	`uvm_object_utils(Transaction);

	function new (string name = "Transaction");
		super.new(name);
	endfunction

	function void Print ();
		$display("dmac = 0x%0h",dmac);
		$display("smac = 0x%0h",smac);
		$display("ether type = 0x%0h",ether_type);
		for(int i=0;i<pload.size;i++)
			$display("pload[%0d] = 0x%0h",i,pload[i]);
		$display("crc = 0x%0h",crc);
	endfunction 
endclass 

增加 Print 打印输出函数。

Environment 部分修改:


class Environment extends  uvm_env;

	Driver drv;
	Monitor i_mon,o_mon;

	function new(string name = "env",uvm_component parent);
		super.new(name,parent);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		drv = Driver::type_id::create("drv",this);
		i_mon=Monitor::type_id::create("i_mon",this);
		o_mon=Monitor::type_id::create("o_mon",this);
	endfunction

	`uvm_component_utils(Environment)
endclass 

 这里实例化了两个monitor,一个用于监测DUT的输入口,一个用于监测DUT的输出口。DUT的输出口设置一个monitor没有任何疑问,但是在DUT的输入口设置一个monitor有必要吗?由于transaction是由driver产生并输出到DUT的端口上,所以driver可以直接将其交给后面的reference model。在2.1节所示的框图中,也是使用这样的策略。所以是否使用monitor,这个答案仁者见仁,智者见智。这里还是推荐使用monitor,原因是:第一,在一个大型的项目中,driver根据某一协议发送数据,而monitor根据这种协议收集数据,如果driver和monitor由不同人员实现,那么可以大大减少其中任何一方对协议理解的错误;第
二,在后文将会看到,在实现代码重用时,使用monitor是非常有必要的。

environment 中树形结构:

Top_tb 部分修改:

`timescale 1ns/1ns
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "Interface.sv"
`include "Transaction.sv"
`include "Driver.sv"
`include "Monitor.sv"
`include "Environment.sv"


module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;

Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);

Design Inst_Design (
	.clk(clk), 
	.rstn(rstn), 
	.rxd(Input_if.data), 
	.rx_val(Input_if.val), 
	.tx_en(Output_if.val), 
	.txd(Output_if.data)
);

initial 
begin 
	// Driver drv;		 								
	// drv = new("Driver",null);		 								
	// drv.main_phase(null);		 								
	// run_test("Driver");	
	run_test("Environment");			 								
	// $finish;		 								
end 							

initial clk = 0;
always #10 clk = ~clk;

initial
begin
	rstn = 1'b0;
	#138 rstn = 1'b1;
end

initial begin
   uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.drv", "vif", Input_if);
   uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.i_mon", "vif", Input_if);
   uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.o_mon", "vif", Output_if);
end


endmodule

编译后执行仿真:

# ----------------------------------------------------------------
# UVM-1.1d
# (C) 2007-2013 Mentor Graphics Corporation
# (C) 2007-2013 Cadence Design Systems, Inc.
# (C) 2006-2013 Synopsys, Inc.
# (C) 2011-2013 Cypress Semiconductor Corp.
# ----------------------------------------------------------------
# 
#   ***********       IMPORTANT RELEASE NOTES         ************
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_MUST_HAVE_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
# 
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
# 
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(215) @ 0: reporter [Questa UVM] QUESTA_UVM-1.2.3
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(217) @ 0: reporter [Questa UVM]  questa_uvm::init(+struct)
# UVM_INFO @ 0: reporter [RNTST] Running test Environment...
# UVM_INFO Driver.sv(7) @ 0: uvm_test_top.drv [Driver] new is called
# UVM_INFO Driver.sv(12) @ 0: uvm_test_top.drv [Driver] build_phase is called
# UVM_INFO Driver.sv(24) @ 0: uvm_test_top.drv [Driver] main_phase is called
# UVM_INFO Driver.sv(48) @ 150: uvm_test_top.drv [Driver] Random Package Data Generate Start ...
# UVM_INFO Driver.sv(51) @ 150: uvm_test_top.drv [Driver] dmac = 0xf4bfbad01b03
# UVM_INFO Driver.sv(59) @ 150: uvm_test_top.drv [Driver] smac = 0x26df69099fc0
# UVM_INFO Driver.sv(67) @ 150: uvm_test_top.drv [Driver] ether_type = 0xa67a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[0] = 0x4a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[1] = 0x60
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[2] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[3] = 0x24
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[4] = 0x90
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[5] = 0xaf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[6] = 0xce
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[7] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[8] = 0xb1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[9] = 0xd3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[10] = 0x45
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[11] = 0xf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[12] = 0x60
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[13] = 0x5f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[14] = 0xee
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[15] = 0x5c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[16] = 0x3e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[17] = 0xee
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[18] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[19] = 0x30
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[20] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[21] = 0xbb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[22] = 0x8b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[23] = 0x92
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[24] = 0x3b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[25] = 0x53
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[26] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[27] = 0x27
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[28] = 0xc8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[29] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[30] = 0x82
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[31] = 0x9b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[32] = 0x48
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[33] = 0x76
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[34] = 0xfb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[35] = 0x32
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[36] = 0xcc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[37] = 0xcb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[38] = 0x5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[39] = 0xc2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[40] = 0xa2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[41] = 0x6
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[42] = 0x4c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[43] = 0xe9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[44] = 0x1c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[45] = 0x79
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[46] = 0xf4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[47] = 0x65
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[48] = 0xa7
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[49] = 0x8d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[50] = 0x3d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[51] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[52] = 0xb9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[53] = 0xe4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[54] = 0x11
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[55] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[56] = 0x44
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[57] = 0xca
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[58] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[59] = 0xa1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[60] = 0xea
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[61] = 0x11
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[62] = 0xc4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[63] = 0x52
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[64] = 0xc4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[65] = 0x9a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[66] = 0x36
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[67] = 0x15
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[68] = 0x1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[69] = 0x6f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[70] = 0x62
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[71] = 0xe1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[72] = 0x79
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[73] = 0xa9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[74] = 0x75
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[75] = 0x62
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[76] = 0x89
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[77] = 0xda
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[78] = 0x56
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[79] = 0xe8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[80] = 0x3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[81] = 0xf9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[82] = 0x4f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[83] = 0x7a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[84] = 0x6d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[85] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[86] = 0x49
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[87] = 0x3e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[88] = 0xc0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[89] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[90] = 0xd4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[91] = 0xa5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[92] = 0x86
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[93] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[94] = 0x10
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[95] = 0xce
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[96] = 0xd4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[97] = 0x83
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[98] = 0xbc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[99] = 0x6e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[100] = 0x36
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[101] = 0xfc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[102] = 0xf8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[103] = 0x80
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[104] = 0xd
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[105] = 0x7b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[106] = 0xde
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[107] = 0xd1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[108] = 0x7e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[109] = 0x75
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[110] = 0xea
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[111] = 0xe0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[112] = 0xed
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[113] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[114] = 0xba
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[115] = 0x2a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[116] = 0x8a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[117] = 0x5b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[118] = 0x9a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[119] = 0x57
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[120] = 0x17
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[121] = 0x14
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[122] = 0xd0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[123] = 0x21
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[124] = 0xca
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[125] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[126] = 0x74
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[127] = 0x34
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[128] = 0x58
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[129] = 0xbc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[130] = 0x94
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[131] = 0x7e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[132] = 0x7c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[133] = 0xb3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[134] = 0xd8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[135] = 0x8b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[136] = 0xef
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[137] = 0xb5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[138] = 0x41
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[139] = 0x6c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[140] = 0x2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[141] = 0x46
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[142] = 0x71
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[143] = 0x1a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[144] = 0x9c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[145] = 0x22
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[146] = 0x27
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[147] = 0x52
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[148] = 0x26
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[149] = 0x90
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[150] = 0x43
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[151] = 0xc3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[152] = 0x1a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[153] = 0x12
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[154] = 0x87
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[155] = 0x71
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[156] = 0xf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[157] = 0x9c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[158] = 0xd6
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[159] = 0x64
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[160] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[161] = 0x3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[162] = 0xd5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[163] = 0x43
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[164] = 0x33
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[165] = 0xb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[166] = 0xf3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[167] = 0x4f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[168] = 0x22
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[169] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[170] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[171] = 0x46
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[172] = 0x17
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[173] = 0x39
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[174] = 0x20
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[175] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[176] = 0xd1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[177] = 0x2a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[178] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[179] = 0x87
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[180] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[181] = 0x69
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[182] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[183] = 0xcc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[184] = 0xa8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[185] = 0xd3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[186] = 0x4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[187] = 0xa2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[188] = 0x81
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[189] = 0x9e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[190] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[191] = 0x29
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[192] = 0x5c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[193] = 0xf9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[194] = 0xb5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[195] = 0x50
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[196] = 0x51
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[197] = 0x3c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[198] = 0x9e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[199] = 0x43
# UVM_INFO Driver.sv(80) @ 150: uvm_test_top.drv [Driver] crc = 0x0
# UVM_INFO Driver.sv(86) @ 150: uvm_test_top.drv [Driver] Random Package Data Generate end ...
# UVM_INFO Driver.sv(88) @ 150: uvm_test_top.drv [Driver] begin to drive one pkt
# UVM_INFO Monitor.sv(39) @ 250: uvm_test_top.i_mon [Monitor] begin to collect one package
# UVM_INFO Monitor.sv(39) @ 270: uvm_test_top.o_mon [Monitor] begin to collect one package
# UVM_INFO Driver.sv(100) @ 4590: uvm_test_top.drv [Driver] end drive one pkt
# UVM_INFO Driver.sv(37) @ 4590: uvm_test_top.drv [Driver] Randomize successfully ! 
# UVM_INFO Monitor.sv(45) @ 4610: uvm_test_top.i_mon [Monitor] collect one package,size=218
# UVM_INFO Monitor.sv(60) @ 4610: uvm_test_top.i_mon [Monitor] pload data size=200
# UVM_INFO Monitor.sv(70) @ 4610: uvm_test_top.i_mon [Monitor] end collect one package, print it:
# dmac = 0xd0babff47aa6
# smac = 0xc09f0969df26
# ether type = 0x0
# pload[0] = 0x4a
# pload[1] = 0x60
# pload[2] = 0x23
# pload[3] = 0x24
# pload[4] = 0x90
# pload[5] = 0xaf
# pload[6] = 0xce
# pload[7] = 0x23
# pload[8] = 0xb1
# pload[9] = 0xd3
# pload[10] = 0x45
# pload[11] = 0xf
# pload[12] = 0x60
# pload[13] = 0x5f
# pload[14] = 0xee
# pload[15] = 0x5c
# pload[16] = 0x3e
# pload[17] = 0xee
# pload[18] = 0x99
# pload[19] = 0x30
# pload[20] = 0xbf
# pload[21] = 0xbb
# pload[22] = 0x8b
# pload[23] = 0x92
# pload[24] = 0x3b
# pload[25] = 0x53
# pload[26] = 0x23
# pload[27] = 0x27
# pload[28] = 0xc8
# pload[29] = 0x9
# pload[30] = 0x82
# pload[31] = 0x9b
# pload[32] = 0x48
# pload[33] = 0x76
# pload[34] = 0xfb
# pload[35] = 0x32
# pload[36] = 0xcc
# pload[37] = 0xcb
# pload[38] = 0x5
# pload[39] = 0xc2
# pload[40] = 0xa2
# pload[41] = 0x6
# pload[42] = 0x4c
# pload[43] = 0xe9
# pload[44] = 0x1c
# pload[45] = 0x79
# pload[46] = 0xf4
# pload[47] = 0x65
# pload[48] = 0xa7
# pload[49] = 0x8d
# pload[50] = 0x3d
# pload[51] = 0xac
# pload[52] = 0xb9
# pload[53] = 0xe4
# pload[54] = 0x11
# pload[55] = 0x99
# pload[56] = 0x44
# pload[57] = 0xca
# pload[58] = 0xe5
# pload[59] = 0xa1
# pload[60] = 0xea
# pload[61] = 0x11
# pload[62] = 0xc4
# pload[63] = 0x52
# pload[64] = 0xc4
# pload[65] = 0x9a
# pload[66] = 0x36
# pload[67] = 0x15
# pload[68] = 0x1
# pload[69] = 0x6f
# pload[70] = 0x62
# pload[71] = 0xe1
# pload[72] = 0x79
# pload[73] = 0xa9
# pload[74] = 0x75
# pload[75] = 0x62
# pload[76] = 0x89
# pload[77] = 0xda
# pload[78] = 0x56
# pload[79] = 0xe8
# pload[80] = 0x3
# pload[81] = 0xf9
# pload[82] = 0x4f
# pload[83] = 0x7a
# pload[84] = 0x6d
# pload[85] = 0x6a
# pload[86] = 0x49
# pload[87] = 0x3e
# pload[88] = 0xc0
# pload[89] = 0x6a
# pload[90] = 0xd4
# pload[91] = 0xa5
# pload[92] = 0x86
# pload[93] = 0xac
# pload[94] = 0x10
# pload[95] = 0xce
# pload[96] = 0xd4
# pload[97] = 0x83
# pload[98] = 0xbc
# pload[99] = 0x6e
# pload[100] = 0x36
# pload[101] = 0xfc
# pload[102] = 0xf8
# pload[103] = 0x80
# pload[104] = 0xd
# pload[105] = 0x7b
# pload[106] = 0xde
# pload[107] = 0xd1
# pload[108] = 0x7e
# pload[109] = 0x75
# pload[110] = 0xea
# pload[111] = 0xe0
# pload[112] = 0xed
# pload[113] = 0xbf
# pload[114] = 0xba
# pload[115] = 0x2a
# pload[116] = 0x8a
# pload[117] = 0x5b
# pload[118] = 0x9a
# pload[119] = 0x57
# pload[120] = 0x17
# pload[121] = 0x14
# pload[122] = 0xd0
# pload[123] = 0x21
# pload[124] = 0xca
# pload[125] = 0x6a
# pload[126] = 0x74
# pload[127] = 0x34
# pload[128] = 0x58
# pload[129] = 0xbc
# pload[130] = 0x94
# pload[131] = 0x7e
# pload[132] = 0x7c
# pload[133] = 0xb3
# pload[134] = 0xd8
# pload[135] = 0x8b
# pload[136] = 0xef
# pload[137] = 0xb5
# pload[138] = 0x41
# pload[139] = 0x6c
# pload[140] = 0x2
# pload[141] = 0x46
# pload[142] = 0x71
# pload[143] = 0x1a
# pload[144] = 0x9c
# pload[145] = 0x22
# pload[146] = 0x27
# pload[147] = 0x52
# pload[148] = 0x26
# pload[149] = 0x90
# pload[150] = 0x43
# pload[151] = 0xc3
# pload[152] = 0x1a
# pload[153] = 0x12
# pload[154] = 0x87
# pload[155] = 0x71
# pload[156] = 0xf
# pload[157] = 0x9c
# pload[158] = 0xd6
# pload[159] = 0x64
# pload[160] = 0xac
# pload[161] = 0x3
# pload[162] = 0xd5
# pload[163] = 0x43
# pload[164] = 0x33
# pload[165] = 0xb
# pload[166] = 0xf3
# pload[167] = 0x4f
# pload[168] = 0x22
# pload[169] = 0x9
# pload[170] = 0xe5
# pload[171] = 0x46
# pload[172] = 0x17
# pload[173] = 0x39
# pload[174] = 0x20
# pload[175] = 0x99
# pload[176] = 0xd1
# pload[177] = 0x2a
# pload[178] = 0x9
# pload[179] = 0x87
# pload[180] = 0xbf
# pload[181] = 0x69
# pload[182] = 0x6a
# pload[183] = 0xcc
# pload[184] = 0xa8
# pload[185] = 0xd3
# pload[186] = 0x4
# pload[187] = 0xa2
# pload[188] = 0x81
# pload[189] = 0x9e
# pload[190] = 0xe5
# pload[191] = 0x29
# pload[192] = 0x5c
# pload[193] = 0xf9
# pload[194] = 0xb5
# pload[195] = 0x50
# pload[196] = 0x51
# pload[197] = 0x3c
# pload[198] = 0x9e
# pload[199] = 0x43
# crc = 0x0
# UVM_INFO Monitor.sv(45) @ 4630: uvm_test_top.o_mon [Monitor] collect one package,size=218
# UVM_INFO Monitor.sv(60) @ 4630: uvm_test_top.o_mon [Monitor] pload data size=200
# UVM_INFO Monitor.sv(70) @ 4630: uvm_test_top.o_mon [Monitor] end collect one package, print it:
# dmac = 0xd0babff47aa6
# smac = 0xc09f0969df26
# ether type = 0x0
# pload[0] = 0x4a
# pload[1] = 0x60
# pload[2] = 0x23
# pload[3] = 0x24
# pload[4] = 0x90
# pload[5] = 0xaf
# pload[6] = 0xce
# pload[7] = 0x23
# pload[8] = 0xb1
# pload[9] = 0xd3
# pload[10] = 0x45
# pload[11] = 0xf
# pload[12] = 0x60
# pload[13] = 0x5f
# pload[14] = 0xee
# pload[15] = 0x5c
# pload[16] = 0x3e
# pload[17] = 0xee
# pload[18] = 0x99
# pload[19] = 0x30
# pload[20] = 0xbf
# pload[21] = 0xbb
# pload[22] = 0x8b
# pload[23] = 0x92
# pload[24] = 0x3b
# pload[25] = 0x53
# pload[26] = 0x23
# pload[27] = 0x27
# pload[28] = 0xc8
# pload[29] = 0x9
# pload[30] = 0x82
# pload[31] = 0x9b
# pload[32] = 0x48
# pload[33] = 0x76
# pload[34] = 0xfb
# pload[35] = 0x32
# pload[36] = 0xcc
# pload[37] = 0xcb
# pload[38] = 0x5
# pload[39] = 0xc2
# pload[40] = 0xa2
# pload[41] = 0x6
# pload[42] = 0x4c
# pload[43] = 0xe9
# pload[44] = 0x1c
# pload[45] = 0x79
# pload[46] = 0xf4
# pload[47] = 0x65
# pload[48] = 0xa7
# pload[49] = 0x8d
# pload[50] = 0x3d
# pload[51] = 0xac
# pload[52] = 0xb9
# pload[53] = 0xe4
# pload[54] = 0x11
# pload[55] = 0x99
# pload[56] = 0x44
# pload[57] = 0xca
# pload[58] = 0xe5
# pload[59] = 0xa1
# pload[60] = 0xea
# pload[61] = 0x11
# pload[62] = 0xc4
# pload[63] = 0x52
# pload[64] = 0xc4
# pload[65] = 0x9a
# pload[66] = 0x36
# pload[67] = 0x15
# pload[68] = 0x1
# pload[69] = 0x6f
# pload[70] = 0x62
# pload[71] = 0xe1
# pload[72] = 0x79
# pload[73] = 0xa9
# pload[74] = 0x75
# pload[75] = 0x62
# pload[76] = 0x89
# pload[77] = 0xda
# pload[78] = 0x56
# pload[79] = 0xe8
# pload[80] = 0x3
# pload[81] = 0xf9
# pload[82] = 0x4f
# pload[83] = 0x7a
# pload[84] = 0x6d
# pload[85] = 0x6a
# pload[86] = 0x49
# pload[87] = 0x3e
# pload[88] = 0xc0
# pload[89] = 0x6a
# pload[90] = 0xd4
# pload[91] = 0xa5
# pload[92] = 0x86
# pload[93] = 0xac
# pload[94] = 0x10
# pload[95] = 0xce
# pload[96] = 0xd4
# pload[97] = 0x83
# pload[98] = 0xbc
# pload[99] = 0x6e
# pload[100] = 0x36
# pload[101] = 0xfc
# pload[102] = 0xf8
# pload[103] = 0x80
# pload[104] = 0xd
# pload[105] = 0x7b
# pload[106] = 0xde
# pload[107] = 0xd1
# pload[108] = 0x7e
# pload[109] = 0x75
# pload[110] = 0xea
# pload[111] = 0xe0
# pload[112] = 0xed
# pload[113] = 0xbf
# pload[114] = 0xba
# pload[115] = 0x2a
# pload[116] = 0x8a
# pload[117] = 0x5b
# pload[118] = 0x9a
# pload[119] = 0x57
# pload[120] = 0x17
# pload[121] = 0x14
# pload[122] = 0xd0
# pload[123] = 0x21
# pload[124] = 0xca
# pload[125] = 0x6a
# pload[126] = 0x74
# pload[127] = 0x34
# pload[128] = 0x58
# pload[129] = 0xbc
# pload[130] = 0x94
# pload[131] = 0x7e
# pload[132] = 0x7c
# pload[133] = 0xb3
# pload[134] = 0xd8
# pload[135] = 0x8b
# pload[136] = 0xef
# pload[137] = 0xb5
# pload[138] = 0x41
# pload[139] = 0x6c
# pload[140] = 0x2
# pload[141] = 0x46
# pload[142] = 0x71
# pload[143] = 0x1a
# pload[144] = 0x9c
# pload[145] = 0x22
# pload[146] = 0x27
# pload[147] = 0x52
# pload[148] = 0x26
# pload[149] = 0x90
# pload[150] = 0x43
# pload[151] = 0xc3
# pload[152] = 0x1a
# pload[153] = 0x12
# pload[154] = 0x87
# pload[155] = 0x71
# pload[156] = 0xf
# pload[157] = 0x9c
# pload[158] = 0xd6
# pload[159] = 0x64
# pload[160] = 0xac
# pload[161] = 0x3
# pload[162] = 0xd5
# pload[163] = 0x43
# pload[164] = 0x33
# pload[165] = 0xb
# pload[166] = 0xf3
# pload[167] = 0x4f
# pload[168] = 0x22
# pload[169] = 0x9
# pload[170] = 0xe5
# pload[171] = 0x46
# pload[172] = 0x17
# pload[173] = 0x39
# pload[174] = 0x20
# pload[175] = 0x99
# pload[176] = 0xd1
# pload[177] = 0x2a
# pload[178] = 0x9
# pload[179] = 0x87
# pload[180] = 0xbf
# pload[181] = 0x69
# pload[182] = 0x6a
# pload[183] = 0xcc
# pload[184] = 0xa8
# pload[185] = 0xd3
# pload[186] = 0x4
# pload[187] = 0xa2
# pload[188] = 0x81
# pload[189] = 0x9e
# pload[190] = 0xe5
# pload[191] = 0x29
# pload[192] = 0x5c
# pload[193] = 0xf9
# pload[194] = 0xb5
# pload[195] = 0x50
# pload[196] = 0x51
# pload[197] = 0x3c
# pload[198] = 0x9e
# pload[199] = 0x43
# crc = 0x0
# 

封装为 agent 

driver和monitor之间的联系:两者之间的代码高度相似。其本质是因为二者处理的是同一种协议,在同样一套既定的规则下做着不同的事情。由于二者的这种相似性,UVM中通常将二者封装在一起,成为 一个agent。因此,不同的agent就代表了不同的协议。


class Agent extends  uvm_agent;
	Driver  drv;
	Monitor mon;

	function new (string name , uvm_component parent);
		super.new(name,parent);
	endfunction 

	extern virtual function void build_phase(uvm_phase phase);
	extern virtual function void connect_phase(uvm_phase phase);

	`uvm_component_utils(Agent)	
endclass 

function void Agent::build_phase(uvm_phase phase);	
	super.build_phase(phase);
	if (is_active == UVM_ACTIVE)
	begin
		drv = Driver::type_id::create("drv",this);
	end
	mon = Monitor::type_id::create("mon",this);
endfunction	

function void Agent::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
endfunction

所有的agent都要派生自uvm_agent类,且其本身是一个component,应该使用uvm_component_utils 宏来实现factory注册。

is_active是uvm_agent的一 个成员变量,从UVM的源代码中可以找到它的原型如下:

这个枚举变量仅有两个值:UVM_PASSIVE和UVM_ACTIVE。在uvm_agent中,is_active的值默认为UVM_ACTIVE,在这种模 式下,是需要实例化driver的。那么什么是UVM_PASSIVE 模式呢?以本章的DUT为例,如图2-5所示,在输出端口上不需要驱动任 何信号,只需要监测信号。在这种情况下,端口上是只需要monitor的,所以driver可以不用实例化。

在把driver和monitor封装成agent后,在env中需要实例化agent,而不需要直接实例化driver和monitor了:


class Environment extends  uvm_env;

	// Driver drv;
	// Monitor i_mon,o_mon;
	Agent i_agt,o_agt;

	function new(string name = "env",uvm_component parent);
		super.new(name,parent);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		i_agt = Agent::type_id::create("i_agt",this);
		o_agt = Agent::type_id::create("o_agt",this);
		i_agt.is_active = UVM_ACTIVE;
		o_agt.is_active = UVM_PASSIVE;
	endfunction

	`uvm_component_utils(Environment)
endclass 

完成i_agt和o_agt的声明后,在my_env的build_phase中对它们进行实例化后,需要指定各自的工作模式是active模式还是passive 模式。现在,整棵UVM树变为了如所示形式。

由于agent的加入,driver和monitor的层次结构改变了,在top_tb中使用config_db设置virtual my_if时要注意改变路径:

在加入了my_agent后,UVM的树形结构越来越清晰。首先,只有uvm_component才能作为树的结点,像my_transaction这种使 用uvm_object_utils宏实现的类是不能作为UVM树的结点的。其次,在my_env的build_phase中,创建i_agt和o_agt的实例是在 build_phase中;在agent中,创建driver和monitor的实例也是在build_phase中。按照前文所述的build_phase的从树根到树叶的执行顺序,可以建立一棵完整的UVM树。UVM要求UVM树最晚在build_phase时段完成,如果在build_phase后的某个phase实例化一个 component:


class Environment extends  uvm_env;

	// Driver drv;
	// Monitor i_mon,o_mon;
	Agent i_agt,o_agt;

	function new(string name = "env",uvm_component parent);
		super.new(name,parent);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		// i_agt = Agent::type_id::create("i_agt",this);
		// o_agt = Agent::type_id::create("o_agt",this);
		// i_agt.is_active = UVM_ACTIVE;
		// o_agt.is_active = UVM_PASSIVE;
	endfunction

	virtual task main_phase(uvm_phase phase);
		i_agt = Agent::type_id::create("i_agt",this);
		o_agt = Agent::type_id::create("o_agt",this);
		i_agt.is_active = UVM_ACTIVE;
		o_agt.is_active = UVM_PASSIVE;
    endtask

	`uvm_component_utils(Environment)
endclass 

如上所示,将在my_env的build_phase中的实例化工作移动到main_phase中,UVM会给出如下错误提示:

那么是不是只能在build_phase中执行实例化的动作呢?答案是否定的。其实还可以在new函数中执行实例化的动作。如可以在 my_agent的new函数中实例化driver和monitor:

UVM中约定俗成的还是在build_phase中完成实例化工作。因此,强烈建议仅在build_phase中完成实例化。

加入reference model

reference model用于完成和DUT相同的功能。reference model的输出被scoreboard 接收,用于和DUT的输出相比较。DUT如果很复杂,那么reference model也会相当复杂:



根据学习进度会更新……

  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
UVM测试平台是一种基于SystemVerilog的测试方法,它可以实现不同阶段的测试功能。搭建UVM测试平台的过程主要包括UVM框架和测试环境的编写,以及仿真工具的设置和调试。 首先,需要安装和配置仿真工具,例如Questsim,以确保仿真环境能够正常运行。在安装好仿真工具后,需要编写UVM框架,这包括事务和通信机制的定义,以及阶段的规范和任务。这些规范和任务可以通过定义宏参数的方式指定,以实现代码的灵活性和可重用性。 接着,需要编写测试环境,这包括测试集合、测试向量和检查点等。测试向量可以通过定义随机变量的方式生成,以实现更加全面和有效的测试。同时,需要定义检查点,以确保仿真结果的正确性和可靠性。 在搭建UVM测试平台的过程中,我们也可能会遇到一些问题。例如,当我们编写UVM测试程序时,会遇到一些语法和语义错误。为了解决这些问题,我们需要仔细查看日志和调试信息,以定位代码中的错误,并进行相应的修正。此外,我们还可能会面临一些性能和稳定性方面的问题。为了解决这些问题,我们可以考虑通过设置波形形式和时序分析器,以优化UVM测试平台的性能和稳定性。 总之,搭建UVM测试平台是一个比较复杂和耗时的过程,需要我们具备一定的技术和经验。只有通过持续不断的学习和实践,才能够掌握UVM测试方法,并且不断提高测试的效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在路上-正出发

哈哈,多少是个心意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值