#UVM# 关于UVM 中的 uvm_resource 资源配置学习

目录

一  uvm_resource_db方式

1.1 现象

1.2 解释 set 

1.3 解释 read_by_name

二 uvm_config_db方式

2.1 解释 set 

2.2 解释 get  

三 区别与联系

3.1  区别与联系

3.2  如何选择


下面介绍一下UVM是如何配置资源的以及获取资源的。

一  uvm_resource_db方式

在我们使用UVM资源配置机制的时候,由于一些种种原因,不是使用uvm_config_db进行配置的,我们可能会看见uvm_resource_db来进行配置(一般不会使用,现在有uvm_config_db替代了)。在这里我们有必要要先讲一下uvm_resource_db,以及这个配置的缺陷。

1.1 现象

//package   UVM_cmd;
program   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_ , uvm_component parent);
		      super.new(name_,parent);
		   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.precedence),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;
				 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

initial begin

run_test("my_test");

end

endprogram
//endpackage

我们在uvm_test中以及uvm_env中分别对uvm_agent中的变量A进行了配置,那么最终A的值是多少呢,30,40还是20?答案是30。

1.2 解释 set 

下面我们来分析一下为什么是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_resource_pool中有3个资源,val分别是30,40,20,按照这个顺序存放的在队列中。
分别对应rtab[“A”]以及ttab[uvm_resource#(int)]。

下面给出rtab[“A”]的元素分布,name1的值是A:

在这里插入图片描述

以上完成了资源的set。

1.3 解释 read_by_name

下面讲一下资源的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.

 1.4 解释 read_by_type

以上就是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。

二 uvm_config_db方式

 这部分我们将要详细介绍uvm_config_db机制时如何解决uvm_resource_db机制带来的弊端的
首先我们来看看uvm_config_db是如何工作的,两个核心方法set和get。

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_config_db#(int)::get(this,"",“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_config_db#(int)::set(this,"un","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_config_db#(int)::set(this,"env.un","A",30);
			  uvm_config_db#(int)::set("this","env.un","A",40);
			  env=unit_env::type_id::create("env",this);
   		   endfunction
		endclass
endpackage

2.1 解释 set 

首先调用set方法.顺序依次是:
uvm_config_db#(int)::set(this,“env.un”,“A”,30)
uvm_config_db#(int)::set(this,“env.un”,“A”,40)
uvm_config_db#(int)::set(this,“un”,“A”,20)


我们还是要追踪uvm_resource_pool中关键的变量 uvm_queues#(uvm_resource_base) rtab[string]。
第一次调用是在uvm_test中调用 uvm_config_db#(int)::set(this,“env.un”,“A”,30),会创建一个scope是uvm_test_top.env.un,name是"A",类型是int的一个资源。在例化uvn_test_top时,depth是1,那么第一个资源的优先级=default_precedence-1=999; 这是时候uvm_queues# (uvm_resource_base) rtab[string]出现元素是 rtab[“A”]

在这里插入图片描述

接着再uvm_test中调用第二次set uvm_config_db#(int)::set(this,“env.un”,“A”,40)
这个时候第二个资源的优先级依旧是999,但是插入到rtab[“A”]的方式时push_front,不是push_back(本质上调用set_override的方法)。

在这里插入图片描述
最后再uvm_env中第三次调用了set方法uvm_config_db#(int)::set(this,“un”,“A”,20) 这个时候,这个资源的优先级时998。

在这里插入图片描述

2.2 解释 get  

上面完成了3个资源的插入,在uvm_agent中调用 uvm_config_db#(int)::get(this,"",“A”,A),这样子就可以取到合适的资源(与uvm_resource_db的read_by_name机制一样,这里就不多介绍。

注:只有在build_phase中调用uvm_config_db::set方法在可以实现上述的效果,得到我们想要的结果,这里符合UVM-phase的工作机制,在使用的过程中要在build-phase中set。(当然纯粹为了学习乐趣的话,当你深入了解之后,可以尝试在别的地方set)。

三 区别与联系

3.1  区别与联系

(1) uvm_config_db是从uvm_resource_db派生而来的,它对uvm_resource_db的一些功能进行了扩展,这种扩展主要体现在对资源的写入和读取上.

(1.1) 在资源的写入操作上,它重载了uvm_resource_db的set函数;

(1.2) 在资源的读取操作上,它新建了一个称为get的函数;

(2) uvm_resource_db虽然也是一种用来共享数据的类,但是层次关系在该类中没有作用; 与uvm_config_db相比,尽管uvm_resource_db也有内建的数据库,可以通过字符串或类型来索引配置数据,但缺点是层次的缺失和因此带来的自顶向下的配置覆盖关系的缺失.

(2.1) uvm_resource_db采用的是”last write wins”,即对同一配置,最后的写入有效;

(2.2) uvm_config_db采用的是”parent wins + last write wins”(假设在env中已经有配置,而test的级别高于env).

(3) uvm_config_db与uvm_resource_db共享同一套database; 因此可能会出现通过uvm_config_db::set()往database中存入信息,但用uvm_resource_db::read_by_name()从database中读取信息;

3.2  如何选择

(1) 选取uvm_resource_db还是uvm_config_db取决于当前的setting是否需要考虑层次信息;如果会考虑层次,则采用uvm_config_db; 如果不考虑层次,则应该使用uvm_resource_db;

感谢

硅码农

分享!!! 

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值