UVM:消息机制


前言

传统的SV经常使用 d i s p l a y ( ) 打印信息,而 U V M 含有几个特定的打印方法可以自动详细信息,无需使用 display()打印信息,而UVM含有几个特定的打印方法可以自动详细信息,无需使用 display()打印信息,而UVM含有几个特定的打印方法可以自动详细信息,无需使用display()。

1、component 消息机制

1.1. 消息打印

UVM所有的消息打印方法均来自uvm_report_object类,而uvm_component类又继承于uvm_report_object类,所以所有的component都含有消息打印的方法和设定方法

下面给出常用方法的原型,实际上所有的方法本质都是调用的uvm_report,可查看源码。

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_report_object.svh
class uvm_report_object extends uvm_object;	//...
virtual function void uvm_report( uvm_severity severity,
                                    string id,
                                    string message,
                                    int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW :
                                                    (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM,
                                    string filename = "",
                                    int line = 0,
                                    string context_name = "",
                                    bit report_enabled_checked =0);
virtual function void uvm_report_info( string id,
					 string message,
					 int verbosity = UVM_MEDIUM,
					 string filename = "",
					 int line = 0,
    					 string context_name = "",
					 bit report_enabled_checked = 0);
  virtual function void uvm_report_warning( string id,
					    string message,
    					    int verbosity = UVM_MEDIUM,
					    string filename = "",
					    int line = 0,
    					    string context_name = "",
					    bit report_enabled_checked = 0);
  virtual function void uvm_report_error( string id,
					  string message,
   					  int verbosity = UVM_LOW,
					  string filename = "",
					  int line = 0,
   					  string context_name = "",
					  bit report_enabled_checked = 0);
  virtual function void uvm_report_fatal( string id,
					  string message,
   					  int verbosity = UVM_NONE,
					  string filename = "",
					  int line = 0,
   					  string context_name = "",
					  bit report_enabled_checked = 0);  
//...
endclass

然后对各输入变量作说明

● string id:表示消息打印的ID,可用于告知消息控制方法,要对哪个消息进行控制

● string message:真正要打印的消息

● string filename :打印该消息所在文件名字

● int line:打印该消息所在文件的行号

1.1.1 int verbosity 过滤度

冗余度,或称过滤度,表示消息的过滤等级。过滤等级越高,越容易不显示该消息

依旧以parameter常量的方式表示,定义为

typedef enum{
	UVM_NONE = 0,
	UVM_LOW = 100,
	UVM_MEDIUM = 200,
	UVM_HIGH = 300,
	UVM_FULL = 400,
	UVM_DEBUG = 500
} uvm_verbosity;

每个component都有其 过滤度阈值,默认为UVM_MEDIUM,如果某个消息的过滤度 ≤ 过滤度阈值,就会打印,否则就不打印。

过滤度阈值的 继承
在uvm_component的new方法中,有这样一句

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_component.svh
function uvm_component::new (string name, uvm_component parent);
	...
	set_report_verbosity_level(parent.get_report_verbosity_level());
	...
endfunction

所以有结论子类component在创建时会继承父类component的过滤度阈值。

但注意若某ID的过滤度阈值与 该component的过滤度阈值 不同,则该ID的过滤度阈值不会被继承

例如

class my_test extends uvm_test;
	comp c1,c2;
	...
	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		set_report_id_verbosity_hier("create", UVM_NONE);
		c1 = comp::type_id::create("c1",this);
		c2 = comp::type_id::create("c2",this);
		...
	endfunction
endclass

class comp extends uvm_component;
	function new(string name,uvm_component parent);
		super.new(name,parent);
		uvm_report_info("create","comp inst is created",UVM_LOW);				//会被打印
	endfunction
	...
endclass

1.1.2. uvm_severity severity 安全级别

以parameter常量的方式表示,有UVM_INFO、UVM_WARNING、UVM_ERROR 和 UVM_FATAL,必须大写

分别对应着uvm_report_info、uvm_report_warning、uvm_report_error和uvm_report_fatal四种方法。

如果安全级别为fatal则都打印消息后,立刻停止仿真

1.1.3. 常见用法

下面给出例子

class my_driver extends uvm_driver;
	`uvm_component_utils("my_driver")
	function new(string name = "my_driver", uvm_component parent);
		super.new(name,parent);
	endfunction
	virtual task main_phase(uvm_phase phase);
		...
		uvm_report_info("data1","data is derived", UVM_LOW)				//ID为"data1",打印内容为"data is derived",安全级别为UVM_INFO,过滤级别为UVM_LOW
		...
	endtask
endclass

打印出的信息公式为:UVM_INFO 来源的sv文件(消息语句在该文件的行数)@打印时间: 索引[ID号]打印的信息

例如

UVM_INFO my_driver.sv(20)@48500000:drv[data1]data is drived

`timescale 1ns/1ps表示时延单位是1ns,时间精度是1ps。如果是这样定义的话,则INFO的打印时间就是从仿真开始经过了多少ps
1s = 1,000 ms = 1,000,000 us = 1,000,000,000 ns = 1,000,000,000,000 ps

可以使用宏进行消息打印,但是一定要注意

只有`uvm_info可以设定过滤度,其他严重度的消息宏 不可设定过滤度,且强制为UVM_NONE

不信看源码

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\macros\uvm_message_defines.svh
`define uvm_info(ID, MSG, VERBOSITY) \
   begin \
     if (uvm_report_enabled(VERBOSITY,UVM_INFO,ID)) \
       uvm_report_info (ID, MSG, VERBOSITY, `uvm_file, `uvm_line, "", 1); \
   end
`define uvm_warning(ID, MSG) \
   begin \
     if (uvm_report_enabled(UVM_NONE,UVM_WARNING,ID)) \
       uvm_report_warning (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \
   end
`define uvm_error(ID, MSG) \
   begin \
     if (uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \
       uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \
   end
//...

使用时,可配合get_type_name()以获取打印消息的组件ID,配合$sformat()将消息与变量整合

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

1.2. 消息控制

1.2.1. 过滤度阈值 控制

即对某些component的过滤度阈值进行统一控制,或是对某些component中某些ID的消息打印方法设定过滤度阈值

函数原型,注意uvm_component类在uvm_report_object类的基础上将所有的方法增加了层次回归的设定。

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_report_object.svh

//根据安全级别获取过滤度等级
function int get_report_verbosity_level(uvm_severity severity=UVM_INFO, string id="");
function int get_report_max_verbosity_level();

function void set_report_verbosity_level (int verbosity_level);							//设定本component的过滤度阈值
function void set_report_id_verbosity (string id, int verbosity);						//设定本component中id的report方法的过滤度阈值
function void set_report_severity_id_verbosity (uvm_severity severity,string id, int verbosity);	

					
//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_component.svh

function void set_report_verbosity_level_hier (int verbosity_level);					//设定本component及所有孩子的过滤度阈值

function void uvm_component::set_report_id_verbosity_hier( string id, int verbosity);	//设定本component及所有孩子的id过滤度阈值
  set_report_id_verbosity(id, verbosity);
  foreach( m_children[c] )
    m_children[c].set_report_id_verbosity_hier(id, verbosity);
endfunction;				
	
function void set_report_severity_id_verbosity_hier (uvm_severity severity,string id, int verbosity);

例子

env.i_agt.drv.get_report_verbosity_level();									//获取drv的过滤度阈值
env.i_agt.drv.set_report_verbosity_level(UVM_HIGH);							//drv的过滤度阈值设置为UVM_HIGH
env.i_agt.set_report_verbosity_level_hier(UVM_HIGH);						//i_agt及其子节点所有的过滤度阈值均被设置为UVM_HIGH

env.i_agt.set_report_id_verbosity("INFO1",UVM_HIGH);							//设置ID为"INFO1"的component的过滤度阈值为UVM_HIGH
env.i_agt.set_report_id_verbosity("INFO2",UVM_HIGH);							//获取ID为"INFO2"的component的过滤度阈值为UVM_HIGH

env.set_report_id_verbosity_hier("INFO3",UVM_HIGH);							//获取ID为"INFO3"及其子component的的过滤度阈值均为UVM_HIGH

UVM消息机制中,每个component都有相应的过滤度阈值,且不同component之间可以相互设定过滤度阈值
与factory机制是类似的,每个component都有相应的创建函数,且不同component之间可以相互重载创建函数

注意了,上述component过滤度阈值控制只适用于子component,而不适用于object!!!
尽量在connect_phase控制过滤度
先看下面代码,如果只能消除一个注释,标准UVM树各component的过滤度阈值是多少?注意object无过滤度阈值

class my_test extends uvm_test;
    env e;
	...
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "uvm_message_test build phase entered", UVM_LOW)
	  //set_report_verbosity_level(UVM_NONE);			//除了树根,UVM树全部component都为UVM_NONE
	  //set_report_verbosity_level_hier(UVM_NONE);		//除了树根,UVM树全部component都为UVM_NONE
      e = env::type_id::create("e", this);
	  //set_report_verbosity_level(UVM_NONE);			//只有uvm_test_top阈值为UVM_NONE,其他component为UVM_MEDIUM
	  //set_report_verbosity_level_hier(UVM_NONE);		//除了树根,UVM树全部component都为UVM_NONE
	  
	  //set_report_id_verbosity("BUILD",UVM_NONE);		//UVM树全部component都为UVM_MEDIUM,只有uvm_test_top中ID为"BUILD"的阈值为UVM_NONE
	  //set_report_id_verbosity_hier("BUILD",UVM_NONE);	//UVM树全部component阈值为UVM_MEDIUM,只有uvm_test_top和e的ID为"BUILD"的阈值为UVM_NONE
      `uvm_info("BUILD", "uvm_message_test build phase exited", UVM_LOW)
    endfunction
  endclass

从上面看,build_phase中在子组件实例化前后进行过滤度阈值控制,会产生不同的效果,在实际操作时非常麻烦。根本原因在于:子component会继承父component的过滤度阈值,但只有在create之后才产生子component

所以为了避免如此麻烦,建议在connect_phase进行过滤度控制。但注意connect_phase是自底向上执行的,而且第一个执行connect_phase的组件不确定

所以如果在test的connect_phase进行过滤度控制,该控制是无法在其他组件的connect_phase中的消息语句实现的。

1.2.2. 文件控制

可将打印的消息保存在日志文件中

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_report_object.svh
  function int  get_report_file_handle(uvm_severity severity, string id);
  function void set_report_default_file (UVM_FILE file);
  function void set_report_id_file (string id, UVM_FILE file);
  function void set_report_severity_file (uvm_severity severity, UVM_FILE file);
  function void set_report_severity_id_file (uvm_severity severity, string id,
                                             UVM_FILE file);
                                             
//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_component.svh 

  function void set_report_id_file_hier (string id, UVM_FILE file);
  function void set_report_severity_file_hier (uvm_severity severity, UVM_FILE file);
  function void set_report_severity_id_file_hier (uvm_severity severity, string id,
                                             UVM_FILE file);

1.2.3. 行为控制

即对消息的行为进行控制,也是通过枚举常量定义的

typedef enum
{
	UVM_NO_ACTION = 'b000000,				//无动作
	UVM_DISPLAY = 'b000001,					//显示消息
	UVM_LOG 	= 'b000010,					//写入文件
	UVM_COUNT 	= 'b000100,					//计数到某数值,并停止仿真
	UVM_EXIT 	= 'b001000,					//退出仿真
	UVM_CALL_HOOK = 'b010000,				//调用回调函数
	UVM_STOP = 'b100000						//停止仿真
} uvm_action_type;

各安全级别的默认行为如下表所示,也是通过 或 | 实现动作的合并的
在这里插入图片描述
下面给出消息打印的行为控制方法

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_report_object.svh
  function int get_report_action(uvm_severity severity, string id);
  function void set_report_severity_action (uvm_severity severity,uvm_action action);
  function void set_report_id_action (string id, uvm_action action);
  function void set_report_severity_id_action (uvm_severity severity,
                                               string id, uvm_action action);

//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_component.svh
  function void set_report_severity_action_hier (uvm_severity severity,uvm_action action);
  function void set_report_id_action_hier (string id, uvm_action action);
  function void set_report_severity_id_action_hier (uvm_severity severity,
                                               string id, uvm_action action);

例子

class comp1 extends uvm_component;
	`uvm_component_utils(comp1);
	function void build_phase(uvm_phase phase);
		f = $fopen("logfile",w);
		set_report_default_file (f);
		set_report_severity_action_hier(UVM_INFO,UVM_DISPLAY|UVL_LOG);
		set_report_severity_action_hier(UVM_ERROR,UVM_DISPLAY|UVL_LOG|UVM_COUNT);
endclass

UVM_COUNT
意思是计数结束仿真,可通过如下方法设定所有具有UVM_COUNT行为的的计数阈值,当然UVM_ERROR是默认含有UVM_COUNT行为的

function void set_report_max_quit_count(int max_count);

1.2.4. 安全等级重载

uvm_info, uvm_warning, uvm_error, uvm_fatal均可相互重载,涉及到的方法如下

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context
env.i_agt.drv.set_report_severity_override(UVM_WARNING, UVM_ERROR);	//将drv所有的uvm_warning替换为uvm_error
env.i_agt.drv.set_report_severity_id_override(UVM_WARNING, "my_driver", UVM_ERROR);	//加入了id

2. 全局消息机制(包括object和tb)

上面讲的消息打印与控制,都是在component中才可使用,那在tb模块和object类定义内部,如何打印和控制消息呢?

这与component消息机制类似。

2.1. 消息打印

实际上,在uvm_global.svh中就已经定义了所有的消息打印方法,而且是全局的哟(不是类内方法哟)。

源代码如下:

//...\questasim\verilog_src\uvm-1.2\src\base\uvm_globals.svh
function void uvm_report( uvm_severity severity,
                          string id,
                          string message,
                          int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW :
                                          (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM,
                          string filename = "",
                          int line = 0,
                          string context_name = "",
                          bit report_enabled_checked = 0);
  uvm_root top;
  uvm_coreservice_t cs;
  cs = uvm_coreservice_t::get();
  top = cs.get_root();
  top.uvm_report(severity, 					//本质上调用的是uvm_root:get()!
  	id, message, verbosity, filename, line, context_name, report_enabled_checked);
endfunction 

function void uvm_report_info(string id,
			      string message,
                              int verbosity = UVM_MEDIUM,
			      string filename = "",
			      int line = 0,
                              string context_name = "",
                              bit report_enabled_checked = 0);
function void uvm_report_warning(string id,
                                 string message,
                                 int verbosity = UVM_MEDIUM,
				 string filename = "",
				 int line = 0,
                                 string context_name = "",
                                 bit report_enabled_checked = 0);

function void uvm_report_error(string id,
                               string message,
                               int verbosity = UVM_LOW,
			       string filename = "",
			       int line = 0,
                               string context_name = "",
                               bit report_enabled_checked = 0);

function void uvm_report_fatal(string id,
	                       string message,
                               int verbosity = UVM_NONE,
			       string filename = "",
			       int line = 0,
                               string context_name = "",
                               bit report_enabled_checked = 0);

也就是说,只要引用了uvm_pkg,就可以在任意地方直接使用uvm_report_info、uvm_report_warning、uvm_report_error和uvm_report_fatal了!

不过从函数内部中可以看到,真正是uvm_root类对象top调用的那四种消息函数,继承于uvm_component的!!!

2.2. 消息控制

很遗憾,在uvm_global.svh中并未定义消息控制方法。

但是uvm_root.svh提供了非常重要的静态方法get()来获取uvm_top对象,即UVM树的树根,该树根是uvm_root类型的,而uvm_root可是继承于uvm_component类的!!

因此在tb或object类定义中,均可使用uvm_root::get()来实现全局消息控制!

此处有一点不太明白的是,uvm_root::get().set_report_verbosity_hier(UVM_NONE);本质上还是调用的uvm_report_object::set_report_verbosity_hier(UVM_NONE);,那为何此处的object内的消息就能过滤?

例如

initial begin
	uvm_root::get().set_report_verbosity_hier(UVM_NONE);
	uvm_report_info("tb","test is going to run",UVM_LOW);		//UVM_LOW > UVM_NONE会被过滤
	run_test("my_test");
	uvm_report_info("tb","test finished",UVM_LOW);				//压根就不会执行这个,因为phase机制最后一句就是$finish()
end

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Starry__/article/details/122931088
————————————————
版权声明:本文为CSDN博主「Starry丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Starry__/article/details/122931088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值