UVM learning - build a simple UVM platform


 


introduction

The blogs in this column are all related to the study of UVM . Learning reference:

 【1】UVM Tutorial

 【2】Written by Zhang Qiang, UVM Combat (Volume Ⅰ)

 【3】Download UVM (Standard Universal Verification Methodology)

The study of this column basically follows the main line of the material [2], using the materials [1] and [3] as a reference. In particular [3] is the official UVM manual, which is highly referenceable and authoritative.

This article first builds a simple UVM platform to understand its ideas and mechanisms.

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


What are the components of the verification platform?

The object of verification is the hardware design code (Verilog) submitted by the front-end design engineer. The purpose of the verification is to design various verification cases and observe whether the circuit designed by the front-end engineer meets the various indicators and functions required in the spec. The structure of the simple verification platform is shown in the figure below. The driver is responsible for giving the same stimulus to the DUT and the reference model at the same time. The monitor is responsible for receiving each response result of the DUT and sending it to the scoreboard to compare the results of the two and give the verification result. , pass or fail.

In UVM, the concepts of agent and sequence are introduced, so the typical block diagram of the verification platform in UVM:

Driver-only verification platform

Build the simplest verification platform

Suppose the design to be analyzed is a data forwarding module:

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

 For the use of the `uvm_info macro, it is recommended to refer to the UVM manual, which is very detailed:

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

In  Questa Sim , only the top-level simulation file needs to be compiled, and individual components do not need to be compiled:

`include "uvm_macros.svh"     

Read in the corresponding macro definition file, which is performed before compilation starts.

import uvm_pkg::*     

Import the entire uvm_pkg into the verification platform, so that you can use various libraries of uvm on your own verification platform.

The above two operations should be included in the top layer of all subsequent verification platforms.

simulation

After the compilation is complete, at the script, execute the simulation:

vsim -voptargs=+acc work.Top_tb +UVM_NO_RELNOTES

After the file is loaded, execute the run command at the script to see the simulation result:

Join the factory mechanism

The factory mechanism is implemented using the uvm_component_utils macro. This macro will automatically create an instance according to the type and the main_phase of this class will be called automatically.

Make the following changes to the Driver file:

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

The result after the modification of the top-level file Top_tb:

A run_test statement will create an instance of my_driver and will automatically call the main_phase of my_driver.

`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

 The figure above is the instruction of run_test.

Execute the simulation after compiling:

It is found that in the simulation results, only main_phased is called is printed, and the following random number excitation part is not executed. The objection mechanism of UVM is introduced here.

Add objection mechanism

In UVM, the objection mechanism is used to control the closing of the verification platform. In each phase, UVM will check whether an objection is raised (raise_objection), if so, then wait for the objection to be revoked (drop_objection) and then stop the simulation; if not, end the current phase immediately.

The drop_objection statement can simply be regarded as a substitute for the finish function, but the raise_objection statement must be called before the drop_objection statement, and raise_objection and drop_objection always appear in pairs.

Add the Driver code of the objection mechanism:

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

Execute the simulation after compiling:

The raise_objection statement must precede the first simulation-time consuming statement in main_phase . For example, $display statements do not consume simulation time, and these statements can be placed before raise_objection, but statements like @(posedge top.clk) consume simulation time. Using raise_objection as follows will not work.

Code modification of the Driver class:

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

Simulation results:

Join the virtual interface

When the virtual interface is not introduced, the port index of the verification platform is indexed by the absolute path between the modules, such as Top_tb.rx_val <= 1'b0 in the above Driver class; the index of this interface is not conducive to the verification platform transplant. The use of macro definitions can also alleviate this problem to a certain extent, but the most fundamental solution is to introduce virtual interfaces.

When a non-virtual interface is introduced into a class, a syntax error will be reported at compile time. Non-virtual interfaces can be introduced within a module. Virtual interfaces need to be declared virtual when they are instantiated.

interface file:

interface Interface (input clk,input rstn);

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

The purpose of introducing the interface is to facilitate a more friendly (higher code portability) connection between the driver and the simulation top-level Top_tb. So how are the two connected? UVM introduces the config_db mechanism. In the config_db mechanism, it is divided into two steps: set and get. The so-called set operation, readers can simply understand it as "sending a letter", while get is equivalent to "receiving a letter". You can send "letters" corresponding to different instances of the same type, or different types of "letters" to the driver. The same is true for the receiving side.

Driver needs to introduce build_phase. Like main_phase, build_phase is also a phase built into UVM. When UVM starts, build_phase will be executed automatically. build_phase is executed after the new function and before main_phase. In the build_phase, some data is mainly passed through the set and get operations of config_db, and member variables are instantiated .

Changes to the Driver class:

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

The above code uses uvm_fatal. Different from the uvm_info macro, when it prints the information shown by the second parameter, it will directly call the finish function of Verilog to end the simulation. The appearance of uvm_fatal indicates that the verification platform has a major problem and cannot continue. The simulation must be stopped and corresponding checks must be made. So for uvm_fatal, the redundancy level of the third parameter in uvm_info is completely meaningless. As long as it is the information printed by uvm_fatal, it must be very critical, so there is no need to set the third parameter.

About uvm_config_db:

The functions related to it are all static functions, so the :: operator   should be used when calling .

Both the set and get functions of config_db have four parameters, and the third parameter of these two functions must be exactly the same.

The fourth parameter of the set function indicates which interface is to be passed to my_driver through config_db, and the fourth parameter of the get function indicates which member variable of my_driver to pass the obtained interface to.

The second parameter of the set function represents the path index, which is the path index mentioned in the introduction of the uvm_info macro. An instance of my_driver is created through run_test in top_tb, so what is the name of this instance? The answer is uvm_test_top: UVM creates an instance named uvm_test_top through the run_test statement . Regardless of the parameters passed to run_test, the name of the created instance is  uvm_test_top . Since the target of the set operation is my_driver, the second parameter of the set function is uvm_test_top . The first parameter null of the set function and the first and second parameters of the get function can be temporarily put aside, which will be described in detail later.

uvm_config_db#(virtual Interface) is a parameterized class, and its parameter is the type of letter to be sent, here is virtual my_if.

Specific instructions from the manual:

Changes in 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

Execute the simulation after compiling:

Add other components to the verification platform

join transaction

The translation of transaction is transaction. So what exactly is a transaction? This is actually a very abstract concept. In layman's terms, a transaction can be understood as a complete incentive. The data incentives of general drives are transmitted based on transaction.

Here, the reference book takes the data packet of the Ethernet protocol as an example to make an explanation.


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 is a function provided in SystemVerilog. When the randomize function of an instance of a certain class is called, post_randomize will be followed unconditionally.

The base class of Transaction is uvm_sequence_item. In UVM, all transactions must be derived from uvm_sequence_item, and only transactions derived from uvm_sequence_item can use the sequence mechanism in UVM.

The uvm_component_utils macro is not used here to implement the factory mechanism, but uvm_object_utils is used . In essence, my_transaction is different from my_driver. During the entire simulation period, my_driver always exists, and my_transaction is different. It has a life cycle. It is generated at a certain time in the simulation, driven by the driver, processed by the reference model, and finally compared by the scoreboard, its life cycle ends. Generally speaking, this class is derived from uvm_object or uvm_object, and the ancestor of uvm_sequence_item is uvm_object. Classes with this feature in UVM must be implemented using the uvm_object_utils macro.

Driver program:

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

In the main_phase, first use randomize to randomize tr, and then drive the content of tr to the port of DUT through the drive_one_pkt task. In drive_one_pkt, all the data in tr is first pushed into the queue data_q, and then all the data in data_q is popped and driven. The process of pushing the data in tr into the queue data_q is equivalent to the process of packing into a byte stream.

Execute the simulation after compiling:

Join the environment

The environment is like a large container that contains components such as scoreboards, reference models, monitors, and drivers. When calling run_test, the passed parameter is no longer my_driver, but this container class, that is, let UVM automatically create an instance of this container class. In UVM, this container class is called 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 

All environments should be derived from uvm_env, and like Driver, the container class always exists in the simulation, and the uvm_component_utils macro is used to realize the registration of the factory.

In the definition of my_env, the most incomprehensible thing is the instantiation of drv on line 14. Here instead of calling the new function of my_driver directly, a weird way is used. This method is the unique instantiation method brought by the factory mechanism. Only classes registered using the factory mechanism can be instantiated in this way ; only instances instantiated in this way can use the most powerful overloading function in the factory mechanism to be described later. Components in the verification platform should use the type_name::type_id::create method when instantiating.

The new function has two parameters, the first parameter is the name of the instance, and the second is the parent. Since my_driver is instantiated in uvm_env, the parent of my_driver is my_env. In the form of parent, UVM has established a tree-shaped organizational structure. In this tree-shaped organizational structure, the instance created by run_test is the root of the tree (my_env here), and the name of the root of the tree is fixed, which is uvm_test_top, which has been described in the previous article; it will grow after the root of the tree Branches and leaves (only my_driver here), the process of growing branches and leaves needs to be implemented manually in the build_phase of my_env. Whether it is the root or the leaf, it must be inherited from uvm_component or its derived class. The structure of the whole UVM tree is shown in the figure.

After adding my_env, there are two build_phases in the entire verification platform, one for my_env and one for my_driver. So in what order are these two build_phases executed? In the tree structure of UVM, the execution of build_phase follows the order from the root of the tree to the leaves, that is, the build_phase of my_env is executed first, and then the build_phase of my_driver is executed. After the build_phase of the whole tree is executed, the subsequent phase is executed.

The hierarchical structure of my_driver in the verification platform has changed, it has changed from a tree root to a leaf, so when using the config_db mechanism in Top_tb to pass the virtual Interface, the corresponding path must be changed; at the same time, the parameter of run_test has also changed from Driver to 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

The second parameter of the set function has changed from uvm_test_top to uvm_test_top .drv , where uvm_test_top is the name of the tree root automatically created by UVM, and drv is the name passed when instantiating drv in the build_phase of my_env. If the name passed when instantiating drv is my_drv, then the second parameter of the set function should also be my_drv

join monitor

The significance of the existence of the monitor is to send the response result output by the DUT to the scoreboard to judge the correctness of the response.

The component in the verification platform that monitors DUT behavior is monitor. The driver is responsible for converting the transaction-level data into the DUT port level, and driving it to the DUT. The monitor behaves opposite to it, and is used to collect the DUT port data, convert it into a transaction, and hand it over to subsequent components such as reference model, scoreboard, etc. deal with.

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 

First, all monitor classes should be derived from uvm_monitor ;

Second, similar to the driver, there also needs to be a virtual Interface in my_monitor;

Third, uvm_monitor exists throughout the simulation, so it is a component that needs to be registered with the uvm_component_utils macro;

Fourth, since the monitor needs to collect data all the time and never stops, the while (1) loop is used in the main_phase to achieve this purpose. 

Transaction part modification:


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 

Added Print function.

Environment part modification:


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 

 Two monitors are instantiated here, one for monitoring the input port of the DUT and one for monitoring the output port of the DUT. There is no doubt about setting a monitor at the output port of the DUT, but is it necessary to set a monitor at the input port of the DUT? Since the transaction is generated by the driver and output to the port of the DUT, the driver can directly hand it over to the reference model behind. In the block diagram shown in Section 2.1, this strategy is also used. So whether to use monitor, the answer is different for different people. Here is still recommended to use monitor, the reason is: first, in a large-scale project, the driver sends data according to a certain protocol, and the monitor collects data according to this protocol, if the driver and monitor are implemented by different people, then it can be greatly reduced Any party's understanding of the protocol is wrong; second
, as we will see later, it is very necessary to use monitor when implementing code reuse.

The tree structure in environment:

Top_tb part modified:

`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

Execute the simulation after compiling:

# ----------------------------------------------------------------
# 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
# 

encapsulated as agent 

The connection between driver and monitor: the codes between the two are highly similar. The essence is that the two deal with the same protocol and do different things under the same set of established rules. Due to the similarity between the two, the two are usually packaged together in UVM to become an agent. Therefore, different agents represent different protocols.


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

All agents must be derived from the uvm_agent class, and itself is a component. The uvm_component_utils  macro should be used to implement factory registration.

is_active is a member variable of uvm_agent, its prototype can be found from the source code of UVM as follows:

This enumeration variable has only two values: UVM_PASSIVE and UVM_ACTIVE. In uvm_agent, the value of is_active is UVM_ACTIVE by default. In this mode, the driver needs to be instantiated. So what is UVM_PASSIVE mode? Take the DUT in this chapter as an example, as shown in Figure 2-5, there is no need to drive any signal on the output port, only to monitor the signal. In this case, only the monitor is needed on the port, so the driver does not need to be instantiated.

After encapsulating the driver and monitor into an agent, the agent needs to be instantiated in the env instead of the driver and monitor directly:


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 

After completing the declaration of i_agt and o_agt, after instantiating them in the build_phase of my_env, you need to specify whether the respective working modes are active mode or passive mode. Now, the whole UVM tree becomes as shown.

Due to the addition of agent, the hierarchical structure of driver and monitor has changed. When using config_db in top_tb to set virtual my_if, pay attention to changing the path:

After adding my_agent, the tree structure of UVM becomes clearer. First of all, only uvm_component can be used as a node of the tree. Classes like my_transaction implemented using the uvm_object_utils macro cannot be used as nodes of the UVM tree . Secondly, in the build_phase of my_env, the instances of i_agt and o_agt are created in the build_phase; in the agent, the instances of driver and monitor are also created in the build_phase. A complete UVM tree can be built according to the execution order of the build_phase from the root to the leaves described above. UVM requires the UVM tree to be completed at the latest in the build_phase period. If a component is instantiated in a certain phase after the build_phase:


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 

As shown above, if the instantiation work in the build_phase of my_env is moved to the main_phase, UVM will give the following error message:

So can instantiated actions only be performed in build_phase? the answer is negative. In fact, you can also perform instantiation actions in the new function. For example, the driver and monitor can be instantiated in the new function of my_agent:

It is customary in UVM to complete the instantiation work in build_phase. Therefore, instantiation is strongly recommended to be done only in build_phase.

add reference model

The reference model is used to complete the same function as DUT. The output of the reference model is received by the scoreboard for comparison with the output of the DUT. If the DUT is very complex, then the reference model will also be quite complex:



Will be updated according to learning progress...

Guess you like

Origin blog.csdn.net/qq_43045275/article/details/130025366