UVM配置之resource机制(1)

本文探讨了UVM中资源配置的重要性,特别是config_db机制如何解决命令行参数配置的不足。通过一个示例解释了uvm_resource_db的工作原理,展示了在uvm_test和uvm_env中配置uvm_agent变量时可能出现的问题。资源的set和get过程被详细阐述,揭示了由于资源按push_back方式存储可能导致的覆盖问题,并提出了uvm_config_db作为更优的解决方案。

UVM为什么会迅速成为业内标准(已经是IEEE的标准),在于UVM的TB的可复用性,用户友好性。想象一下下面的一个应用场景,我们在搭建TB时,某些case run起来需要配置某些参数,原有的思路是在TB中利用SV的系统函数比如$test $plusargs 或者 $value $plusargs来获取相应的参数,从而配置某些特定的应用场景。这样做在现在看来有两处不友好的地方,首先在run的时候需要命令行加入参数,参数的数量是如法控制的,其次如果在环境集成的时候,万一需要两个这样同样的子TB来构成上一层的环境,这个时候无法给两个TB配置不同的参数。资源配置机制(config_db机制)作为UVM重要的一个特性,很好的解决了上面的问题,下面介绍一下UVM是如何配置资源的以及获取资源的。
在我们使用UVM资源配置机制的时候,由于一些种种原因,不是使用uvm_config_db进行配置的,我们可能会看见uvm_resource_db来进行配置(一般不会使用,现在有uvm_config_db替代了),在这里我们有必要要先讲一下uvm_resource_db,以及这个配置的缺陷。看下面的例子

package   UVM_cmd;
        import uvm_pkg::*'
		`include "uvm_macros.svh"
		class  unit_agent  extends uvm_agent;
		   int A=10;
		   int i;
		   local int b;
		   uvm_resource#(int) re;
		   uvm_resource_types::rsrc_q_t rq;
		   uvm_resource_pool rp;
		   `uvm_component_utils(unit_agent)

		   function new(string name);
		      super.new(name);
		   endfunction
		   
		   virtual function void build_phase(uvm_phase phase);
		      super.build_phase(phase);
			  re=uvm_resource#(int)::get_type();
			  rp=uvm_resource_pool::get();
			  rq=rp.lookup_name("abcd","A",re);
			  `uvm_info("INT",$sformatf("before the config the a is %d",A),UVM_LOW)
			  if(!uvm_resource_db#(int)::read_by_name("abcd","A",A))
			      `uvm_error("error","the read is error")
			  else
			  `uvm_info("INT",$sformatf("after the config the a is %d",A),UVM_LOW)
			  
			  `uvm_info("precedence",$sformatf("the precedence is %d",re.precednce),UVM_LOW)
			  `uvm_info("size",$sformatf("the size is %d",rq.size()),UVM_LOW)
			  
			  while(rq.size()>0)begin
			     uvm_resource_base n;
				 uvm_resource#(int) n1;
				 n-rq.pop_front();
				 if(n!=null)   begin
				    `void($cast(n1,n))
				  `uvm_info("precedence",$sformatf("the precedence is %d",n.precedence),UVM_LOW)
				  `uvm_info("precedence",$sformatf("the data is %d",n1.read()),UVM_LOW)
				 end
			  end
		   endfunction
		   
		   function int ret();
		      return b;
		   endfunction
		endclass
		
		
		class unit_agent_child extends unit_agent;
		   `uvm_component_utils(unit_agent_child)
		   function new(string name,uvm_component parent);
		      super.new(name,parent);
			  
		   endfunction
		    function void build_phase(uvm_phase phase);
		      super.build_phase(phase);
			endfunction
		endclass 

        class unit_env extends uvm_env;
           unit_agent  un;
		   unit_agent_child  un_ch;
		   `uvm_component_utils(unit_env)
		   function new(string name,uvm_component parent);
		      super.new(name,parent);
			  
		   endfunction
		    function void build_phase(uvm_phase phase);
		      super.build_phase(phase);
			  uvm_resource_db#(int)::set("abcd","A",20);
			  //un=unit_agent::type_id::create("un",this);
			  //un_ch=unit_agent_child::type_id::create("un_ch",this);
			endfunction
        endclass  		
		class my_test extends uvm_test;
		    unit_env env;;
		   `uvm_component_utils(my_test)
		   function new(string name,uvm_component parent);
		      super.new(name,parent);
			  
		   endfunction
           function void build_phase(uvm_phase phase);
		      super.build_phase(phase);
			  uvm_resource_db#(int)::set("abcd","A",30);
			  uvm_resource_db#(int)::set("abcd","A",40);
			  env=unit_env::type_id::create("env",this);
   		   endfunction
		endclass
endpackage

我们在uvm_test中以及uvm_env中分别对uvm_agent中的变量A进行了配置,那么最终A的值是多少呢,30,40还是20?
答案是30。
下面我们来分析一下为什么是30,而不是40或者20,分析完之后将会对uvm_resource_db如何工作机制非常熟悉的。
在这个机制工作的过程中主要有3个class在相互交互,这里先列出来
uvm_resource#(T):资源
uvm_resource_pool:存放资源的地方
uvm_resource_db:配置以及获取资源

首先调用uvm_resource_db::set方法

在上面我们给的这个例子中会创建类型是int,scope是“abcd”,name是A的资源,这里由于uvm_test的build_phase先执行,因此会先后创建3个资源,按照资源val的不同,分别是30,40,20。如下图,其中T1是int
在这里插入图片描述

那么这些资源放哪了,在UVM中有一个uvm_resource_pool这个类(全局唯一),专门用来存放各种配置的资源。

在uvm_resource_pool这个类中有两个非常重要的变量来存放资源

uvm_queue#(uvm_resource_base) rtab [string]

uvm_queue#(uvm_resource_base) ttab [uvm_resource_base];

set方法就是向着两个联合数组中存放资源,一个是按照name区分,一个是按照类型区分。
最终uvm_resorce_pool中有3个资源,val分别是30,40,20(按照这个顺序存放的在队列中。
分别对应rtab[“A”]以及ttab[uvm_resource#(int)],下面给出rtab[“A”]的元素分布,name1的值是A
在这里插入图片描述
以上完成了资源的set,下面讲一下资源的get,在uvm_resource_db中可以使用read_by_name来获取资源。
在agent中通过调用uvm_resource_db#(int)::read_by_name方法来从uvm_resource_pool中获取资源,那么是如何获取资源的呢?下面来讲解一下,
在上面我们以及指导rtab[“A”]存放3个资源,3个资源的scope以及type均一样,区别在于资源值val的不同,
read_by_name方法首先根据name A确定要从rtab[“A”]这个队列中找,
接着遍历这个队列下的所有资源,找到scope以及type匹配的资源放入一个队列中并且返回,这里我们返回3个资源,
下面将会遍历这3个资源,找到优先级最大的资源(这里我们没有对资源的优先级进行设置,所有3个资源的优先级完全一样,默认是1000)。
由于资源的优先级一样,这个时候会将队列的第一个元素返回,当做最终有效的资源,这个资源的val是30.所以agent中返回的值是30.
以上就是uvm_resource_db的工作机制。

因此在我们正常使用uvm_resource_db的时候,由于同类型,同scope,同name,不同val的资源是以push_back的方式放入uvm_resource_pool::rtab[name]这个队列中的,如果这些资源的优先级一样,name最先放入的资源是有效资源,这样就无法实现同一组件配置同一个资源,导致后配置的资源无法覆盖之前配置资源。当然这里可以使用uvm_resource_db::set_overrirde的方式进行配置,或者改变资源的优先级,但是这样子就显的不是那么友好,那么有没有别的方式可以直接通过set方式实现以上的弊端呢,方法是有的,就是uvm_config_db

<think>我们被要求回答关于`uvm_resource read`的使用方法。根据之前的上下文,我们知道`uvm_resource`是一个参数化的类,用于存储和访问配置数据。`read`方法是`uvm_resource`类中的一个成员函数,用于读取资源中存储的值。 ### 1. `uvm_resource::read()` 方法的作用 `read`方法用于从资源对象中获取存储的值。由于`uvm_resource`是一个参数化的类,所以`read`返回的值类型与资源参数类型一致。 ### 2. 方法原型 在UVM源代码中,`uvm_resource#(T)::read`方法的原型通常如下: ```systemverilog function T read(); ``` 其中,`T`是资源存储数据的类型。 ### 3. 使用步骤 使用`uvm_resource::read()`的一般步骤包括: 1. 获取资源对象(通过`uvm_resource_pool`或`uvm_resource_db`等方法)。 2. 检查资源对象是否为`null`(表示未找到资源)。 3. 如果不为`null`,则调用`read`方法获取值。 ### 4. 示例代码 假设我们有一个存储整数类型的资源,资源类型为`uvm_resource#(int)`。以下是如何读取该资源的值的示例: ```systemverilog // 假设我们已经知道资源的名称和作用域 string rsrc_name = "clock_period"; string scope = "uvm_test_top.env"; // 从资源池中按名称获取资源 uvm_resource_pool rp = uvm_resource_pool::get(); uvm_resource_base rsrc_base = rp.get_by_name(scope, rsrc_name); // 尝试转换为具体的资源类型 uvm_resource#(int) rsrc_int; if (rsrc_base != null) begin if ($cast(rsrc_int, rsrc_base)) begin // 调用read方法获取存储的整数值 int period = rsrc_int.read(); `uvm_info("RDVAL", $sformatf("Clock period = %0d", period), UVM_LOW) end else begin `uvm_error("RDVAL", "Resource found but type conversion failed") end end else begin `uvm_warning("RDVAL", "Resource not found") end ``` ### 5. 注意事项 - **资源存在性检查**:在调用`read`之前,必须确保资源对象非空,否则会导致空指针访问错误(在SystemVerilog中,访问空对象引用可能导致仿真错误)。 - **类型匹配**:从资源池中获取的资源对象是基类型(`uvm_resource_base`),必须通过`$cast`转换为参数化的类型(如`uvm_resource#(int)`)才能调用`read`方法。 - **资源值的修改**:`read`方法只是读取资源的值,不会修改资源。如果想要修改资源的值,可以使用`write`方法。 ### 6. 与`uvm_resource_db`的关系 `uvm_resource_db`提供了一些静态方法,可以更方便地设置和获取资源。例如,可以使用`uvm_resource_db#(int)::read_by_name`直接读取值,而不需要手动进行类型转换: ```systemverilog int period; if (uvm_resource_db#(int)::read_by_name(scope, rsrc_name, period)) begin `uvm_info("RDVAL", $sformatf("Clock period = %0d", period), UVM_LOW) end else begin `uvm_warning("RDVAL", "Resource not found") end ``` 在这种情况下,我们不需要直接操作`uvm_resource`对象,也不需要调用`read`方法,因为`read_by_name`内部已经处理了这些步骤。但是理解底层的`uvm_resource`和`read`方法仍然很重要,尤其是在需要直接操作资源对象时。 ### 7. 总结 - `uvm_resource#(T)::read()`用于获取资源中存储的值。 - 使用前需先获取资源对象并确保类型转换成功。 - 推荐优先使用`uvm_resource_db`的便捷方法(如`read_by_name`)来简化代码。 --- ### 相关问题 1. 如何设置UVM资源的值(使用`write`方法)? 2. `uvm_resource`和`uvm_config_db`在读写机制上有何异同? 3. UVM资源池(`uvm_resource_pool`)是如何管理资源的? 4. 如何遍历UVM资源池中的所有资源? [^1]: `uvm_resource_pool`存储资源并提供查询接口 [^2]: `uvm_resource_db`提供了更便捷的静态方法访问资源 [^3]: UVM源码中定义了资源类型和操作方法 [^4]: 资源的使用需注意作用域和优先级 </think>### `uvm_resource::read()` 使用方法详解 `uvm_resource::read()` 是 UVM 中用于获取资源存储值的核心方法,适用于通过 `uvm_resource_pool` 或 `uvm_resource_db` 检索到的资源对象。以下是具体使用步骤和示例: --- ### **1. 方法定义与功能** - **原型**: ```systemverilog function T read(); ``` 其中 `T` 是资源的参数化类型(如 `int`, `string`, 自定义对象等)。 - **功能**: 返回资源当前存储的值,不消耗资源(资源可被多次读取)。 --- ### **2. 使用步骤** 1. **获取资源对象** 通过 `uvm_resource_pool` 或 `uvm_resource_db` 检索资源(需指定作用域和类型)。 2. **类型转换** 将基类 `uvm_resource_base` 转换为参数化类型 `uvm_resource#(T)`。 3. **调用 `read()`** 直接从转换后的对象中读取值。 --- ### **3. 完整代码示例** #### **场景** 读取验证环境中配置的时钟频率(`int` 类型资源): ```systemverilog // 定义资源类型(通常需继承 uvm_resource) typedef uvm_resource#(int) int_rsrc; // 使用 UVM 预定义类型 class env extends uvm_env; `uvm_component_utils(env) function void build_phase(uvm_phase phase); // 1. 获取全局资源池 uvm_resource_pool rp = uvm_resource_pool::get(); // 2. 按类型检索资源(作用域为当前环境) uvm_resource_base rsrc_base = rp.get_by_type( get_full_name(), // 当前组件作用域(如 "uvm_test_top.env") int_rsrc::get_type() // 资源类型句柄 ); // 3. 类型转换并读取值 int_rsrc rsrc_int; if (rsrc_base != null && $cast(rsrc_int, rsrc_base)) begin int clk_freq = rsrc_int.read(); // 调用 read() 获取值 `uvm_info("RSRC_READ", $sformatf("Clock频率=%0d MHz", clk_freq), UVM_LOW) end else begin `uvm_error("RSRC_READ", "未找到时钟频率资源") end endfunction endclass ``` --- ### **4. 关键注意事项** 1. **资源存在性检查** `get_by_type()` 可能返回 `null`,需优先验证资源是否存在: ```systemverilog if (rsrc_base == null) // 处理资源未找到的情况 ``` 2. **类型安全** `$cast` 失败表明资源类型与实际存储类型不匹配(如预期 `int` 但存储了 `string`)。 3. **资源写入** 修改资源值需用 `write()` 方法: ```systemverilog rsrc_int.write(200); // 将时钟频率修改为 200MHz ``` 4. **便捷方法替代** 直接使用 `uvm_resource_db` 简化操作: ```systemverilog int clk_freq; uvm_resource_db#(int)::read_by_type( get_full_name(), int_rsrc::get_type(), clk_freq ); ``` --- ### **5. 典型应用场景** - 获取配置参数(如超时阈值、数据包大小) - 读取全局状态控制标志(如测试终止条件) - 跨组件传递复杂对象(如共享的覆盖率模型) --- ### **
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值