config机制
- 在验证环境的创建过程build phase中,除了组件的实例化,配置也是必不可少的。
- 为了验证环境的复用性,通过外部的参数配置,使得环境在创建时可以根据不同参数来选择创建的组件类型、组件实例数目、组件之间的连接以及组件的运行模式等。
- 在更细致的环境调节(environment tuning)中有更多的变量需要配置,例如for-loop的阈值、字符串名称、随机变量的生成比重等。
- 比起重新编译来调节变量,如果在仿真中可以通过变量设置来修改环境,那么就更灵活了,而UVM config机制正提供了这样的便捷。
- 在UVM提供了avm_config_db配类以及几种方便的变量设置方法来实现仿真时的环境控制,常见的uvm_contig_db的使用方式包括:
·传递virtual interface到环境中。
·设置单一变量值,例如int、string、enum等。
·传递配置对象(config object)到环境。 - uvm_config_db#(T)::set(uvm_uvm_component cntxt,string insstring_field name, value) ;
- uvm_config_db# (T)::get(uvm_component cntxt, string inst_name,string field_ name , inout value) ;
interface传递
- interface传递可以很好地解决了连接硬件世界和软件世界。
- 而在之前SV验证模块中,虽然SV可以通过层次化的set_interface的索引来完成了传递,但是这种方式不利于软件环境的封装和复用。
- UVM的uvm_config_db使得接口的传递和获取彻底分离开来。
- 在实现接口传递的过程中需要注意:
·接口传递应该发生在run_test()之前,这保证了进入build phase之前virtual interface已经被传递到uvm_config_db中。
·用户应当把interface与virtual interface的声明区分开来,在传递过程中的类型应当为virtual interface,即实际接口的句柄。
interface intf1;
logic enable = 0 ;
endinterface
class comp1 extends uvm_component;`
uvm component_utils (comp1)
virtual intf1 vif;
function void build phase (uvm phase phase) ;
if ( !uvm_config_db# (virtual intf1) ::get(this, "", "vif", vif)) begin //实现路径:root->test->c1->vif
'uvm_error ( "GETVIF", "no virtual interface is assigned")
end
'uvm_info ("SETVAL",$sformatf("vif.enable is $b before set", vif.enable),UVM_LOW)
vif.enable = 1;
'uvm_info("SETVAL",$sformatf ("vif.enable is 8b after set",vif.enable),UVM_LOW)
endfunction
endclass
- 底层的get要和顶层的set配对,这地方顶层set相当于建立一个查找表,左边是path,右边是value。
下面是顶层的set
class test1 extends uvm_test;
`uvm component _utils ( test1)
comp c1;
endclass
intf1 intf();
initial begin
uvm _config_db# (virtual intf1) : :set(uvm _root::get(),"uvm_test_top.c1","vif",intf);
run_test( "test1"); //实现层次结构root->test->c1->vif
end
- UVM世界中,顶层类uvm_root属于uvm_component的子类,作为顶层结构类。
- uvm_config_db# (virtual intf1) ::get(this, “”, “vif”, vif)) 这行代码在comp1类的定义中,在test类中定义句柄,当run_test(“test”)执行时,会进入各个层次的build阶段,这行代码会在root ->uvm_test_top->c1->vif
- uvm _config_db# (virtual intf1) : :set(uvm _root::get(),“uvm_test_top.c1”,“vif”,intf);在执行这行代码时,会将接口路径保存在root->uvm_test_top->c1->vif与上述的get相对应,实现接口传递。
变量设置
- 在各个test中,可以在build_phase对底层组件的变量加以配置,进而在环境例化之前完成配置,使得环境可以按照预期运行。
class comp1 extends uvm component;
`uvm_component_utils (comp1)
int val1 = 1;
string str1 = "null";
function void build phase (uvm phase phase) ;
`uvm_info("SETVAL",$sformatf ( "val1 is %d before get", val1),UVM_LOW)
`uvm_info("SETVAL",$sformatf("str1 is %s before get", str1),UVM_LOW)
`uvm config _db# (int) : : get(this, "","val1", val1);
`uvm_config _db# (string) : : get(this, "" , "str1 " , str1);
'uvm_info( "SETVA",$sformatf("val1 is %d after get", val1),UVM_LOW)
'uvm _info( "SETVAL",$sformatf( "str1 is is after get",str1),UVM_LOW)
endfunction
endclass
class test1 extends uvm test;
'uvm_component _utils (test1)
comp1 c1;
· function void build phase(uvm phase phase) ;
uvm_config_db# (int) : :set (this, "c1", "val1",100);
uvm_config_db#(string) : :set(this, "c1", "str1", "comp1" ) ;
c1 = comp1 : : type_id: : create ( "c1" , this) ;
endfunction
endclass
首先要分析set路径:root->uvm_test_top->c1->val1/str1 ; get 路径:root->uvm_test_top->c1->val1/str1
object传递
- 在test配置中,需要配置的参数不只是数量多,而且可能还分属于不同的组件。.
- 那么如果对这么多层次中的变重做出类似与上面的变脸设置,需要更多的代码,容易出错还不易于复用,甚至底层组件的变量被删除后,也无法通过uvm_config_db::set()得知配置是否成功。
- 然而如果将每个组件中的变量加以整合,首先放置到一个uvm_object中,再对中心化的配置对象进行传递,那么将会更有利于整体环境的修改维护。
class config1 extends uvm_object; //定义一个配置类继承于object
int val1 = 1;
int str1 = "null" ;
`uvm_object_utils (config1)
...
endclass
class comp1 extends uvm_component;
'uvm_component_utils (comp1)
config1 cfg ;
...
function void build_phase (uvm_phase phase) ;
uvm_object tmp; //声明了一个uvm_object 句柄
uvm_config_db# (uvm_object) : :get(this, "", "cfg" , tmp) //这地方get于set传递类型都是一个父类uvm_object
void' ($cast(cfg , tmp)) ;
uvm info ( "SETVAL",$sformatf( "cfg.val1 is %d after get" , cfg. val1), UVM_LOW)
uvm info ( "SETVAL",$sformatf( "cfg.str1 is %s after get", cfg.str1), UVM_LOW)
endfunction
endclass
class_test1 extends uvm_test;
`uvm_component_utils ( test1)
comp1 c1, c2; //声明comp1句柄
config1 cfg1, cfg2;
...
function void build phase (uvm_phase phase) ;
cfg1 = config1 : : type_id: : create ( "cfg1") ; //创建了两个配置类
cfg2 = config1 : : type_id: :create ( "cfg2 " );
cfg1. val1 = 30 ;
cfg1.str1= "c1" ;
cfg2 . val1 = 50;
cfg2 .str1= "c2";
uvm_config_db# (uvm_object)l :set(this, "c1", "cfg" , cfg1) ; //将root->uvm_test_top->c1->cfg配置成cfg1
uvm_config_db# (uvm object) :set(this, "c2", "cfg" , cfg2) ;//将root->uvm_test_top->c2->cfg配置成cfg2
c1 =comp1 : :type_id: :create ( "c1" , this) ; //创建root->uvm_test_top->c1
c2 = comp1 : : type_id: : create ( "c2", this) ;//创建root->uvm_test_top->c2
endfunction
endclass
这地方不是很好理解:
- 将变量放在一个object的子类(变量配置类)里面
- 底层:在组件子类中声明这个变量配置类,并且在build_phase中声明一个object类,获取当前类的配置类变量(底层获取配置),因为此处传递的是父类句柄(object),但配置的实例时子类,所有做一个父类到子类的转换,这样才可以调用子类的资源
- 顶层:声明组件类和配置类句柄,在build_phase进行配置类的创建和配置,然后将该配置设置到底层路径中的配置类中(注意传递类型于底层一致)。
- 从而在顶层创建组件时,调用底层的build_phase时会获取配置再创建。
在使用uvm config db:set()/ge()t时,实际发生了这些后台操作:
- uvm_config_d::set()通过层次和变量名,这些信息放置到uvm_pkg唯一的全局变量uvm_pkg::uvm_resources。
- 全局变量uvm resources用来存储和释放配置资源信息(resourceinformation) 。
- uvm_resources是uvm_resource_pool类的全局唯一实例,该实例中有两个resource数组用来存放配置信息,这两个数组中一个由层次名字索引,一个由类型索引,通过这两个关联数组可以存放通过层次配置的信息。
- 同时,底层的组件也可以通过层次或者类型来取得来自高层的配置信息。这种方式使信息的配置和获取得到剥离,便于调试复用。
- 在使用uvm_config_db:get()方法时,通过传递的参数构成索引层次,然后在uvm_resource已有的配置信息池中索引该配置,如果索引到,方法返回1,否则返回0。
建议
- 在使用set()/get()方法时,传递的参数类型应当上下保持一致。对于uvm_obiect等实例的传递,如果get类型与set类型不一致,应当首先通过Scast()完成类型转换,再对类型转换后的对象进行操作。
- Set()/get()方法传递的参数可以使用通配符“”来表示任意的层次,类似于正则表达式的用法。向时用户需要懂得“.comp1”与“*comp1”的区别,前者表示在目前层次以下所有名称为“compi”的组件,而后者表示包括当前层次及当前层次以下所有名为“comp1”的组件。’
- 在module环境中如果要使用uvm_config db:set(),则传递的第一个参数uvm_component cntxt参数一般用来表示当前的层次。如果当前层次为最高层,用户可以设置为null,也可以设置为uvm_root:get()来表示uvm_root的全局顶层实例。
- 在使用配置变量时,应当确保先进行uvm_config_db:get()操作,在获得了正确的配置值以后再便用。
- 应当尽量确保uvm_config_db:set()方法在相关配置组件创建前调用。这是因为只有先完成配置,相关组件在例化前才可以得到配置值继而正确地例化。
- 在set()方法第一个参数使用当前层次的前提下,对于同一组件的同一个变量,如果有多个高层组件对该变量进行设置,那么较高层组件的配置会覆盖较低层的配置;但是如果是同一层次组件对该变量进行多次配置时,应该遵循后面的配置会覆盖前面的配置。
- 用户应该在使用uvm config db:.get()方法时,添加便于调试的语句,例如通过UVM报告信息得知get()方法中的配置变量是否从uvm_config _db获取到,如果没有获取,是否需要采取其它措施。