UVM入门与进阶学习笔记5——config机制


  • 为验证环境的复用性,通过外部的参数配置使环境在创建时可根据不同参数选择创建的组件类型、组件实例数目、组件之间的连接以及组件的运行模式等。
  • 在更细致的环境调节中有更多变量需配置,例如for-loop的阈值、字符串名称、随机变量的生成比重等。
  • 比起重新编译,在仿真中通过变量设置修改环境就显得更灵活,UVM config机制正是提供这么做的方法。

UVM提供uvm_config_db的配置类以及几种很方便的变量设置方法来实现在仿真时的环境控制。常见的uvm_config_db的使用方式包括:

  • 传递virtual interface到环境中
  • 设置单一变量值,例如int、string、enum等。
  • 传递配置对象(config object)到环境。
  • uvm_config_db#(T)::set(uvm_component cntxt, string inst_name, string field_name, T value); ——set顶层环境。
  • uvm_config_db#(T)::get(uvm_component cntxt, string inst_name, string field_name, inout T value); ——get:从底层环境拿出来。

interface传递

  • interface传递可很好解决连接硬件世界和软件世界
  • SV可通过层次化的interface的索引完成传递,但这种方式不利于软件环境的封装和复用。
  • UVM的uvm_config_db使得接口的传递和获取彻底分开
  • 实现接口传递的过程需注意:1、接口传递应发生在run_test()之前,保证在进入build phase之前virtual interface已被传递到uvm_config_db中;2、用户应把interface与virtual interface的声明区分开,在传递过程中的类型应为virtual interface,即实际接口的句柄
interface intf1;
	logic enable = 0;
endinterface
 
module config_interface;
import uvm_pkg::*;
`include "uvm_macros.svh"
 
class comp1 extends uvm_component;
`uvm_component_utils(comp1)
virtual intf1 vif;
function new(string name, uvm_component parent);
    super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
    if(!uvm_config_db#(virtual intf1)::get(this, "", "vif", vif)) begin
    	//指向root.test1.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 %b after set", vif.enable), UVM_LOW)
endfunction
endclass
 
class test1 extends uvm_test;
	`uvm_component_utils(test1)
	comp1 c1;
	function new(string name, uvm_component parent);
    	super.new(name, parent);
	endfunction
	function void build_phase(uvm_phase phase);
 	   c1 = comp1::type_id::create("c1", this);
	endfunction
endclass
intf1 intf();
initial begin
    uvm_config_db#(virtual intf1)::set(uvm_root::get(), 
    									"uvm_test_top.c1", "vif", intf);  
                        //注意发生在run_test()之前——root句柄、路径、名称																			
    run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] vif.enable is 0 before set
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] vif.enable is 1 after set

变量设置

在各个test中可以在build phase阶段对底层组件中的变量加以配置,进而在环境例化之前完成配置,使环境可以按照预期运行。

module config_variable;
import uvm_pkg::*;
`include "uvm_macros.svh"
 
class comp1 extends uvm_component;
	`uvm_component_utils(comp1)
	int val1 = 1;
	string str1 = "null";
	function new(string name, uvm_component parent);
    	super.new(name, parent);
	endfunction
	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("SETVAL", $sformatf("val1 is %d after get", val1), UVM_LOW)
   	 `uvm_info("SETVAL", $sformatf("str1 is %s after get", str1), UVM_LOW)
	endfunction
endclass
 
class test1 extends uvm_test;
	`uvm_component_utils(test1)
	comp1 c1;
	function new(string name, uvm_component parent);
 	   super.new(name, parent);
	endfunction
	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
initial begin
    run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 1 before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is null before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 100 after get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is comp1 afteobject

object传递

  • 在test配置中,需要配置的参数不只是数量多,而且可能还分属于不同组件。
  • 若对这么多层次中的变量做出变量的设置需要更多代码,易出错还不易于复用,甚至底层组件的变量被删除后也无法通过uvm_config_db:set()得知配置是否成功。
  • 将每个组件的变量加以整合,首先放置到uvm_object中再对中心化的配置对象进行传递,将会更有利于整体环境的修改维护
import uvm_pkg::*;
`include "uvm_macros.svh"
class config1 extends uvm_object; //注意是object
	int val1 = 1;
	int str1 = "null";  
	`uvm_object_utils(config1)
	function new(string name = "config1");
	    super.new(name);
	endfunction
endclass //将变量整合放置到uvm_object中,再对中心化的配置对象进行传递
class comp1 extends uvm_component;
	`uvm_component_utils(comp1)
	config1 cfg;  //注意这是子类
	function new(string name, uvm_component parent);
    	super.new(name, parent);
	endfunction
	function void build_phase(uvm_phase phase);
    	uvm_object tmp;  //父类
    	uvm_config_db#(uvm_object)::get(this, "", "cfg", tmp);
    	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;
	config1 cfg1, cfg2;
	function new(string name, uvm_component parent);
   		super.new(name, parent);
	endfunction
	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)::set(this, "c1", "cfg", cfg1);
    	uvm_config_db#(uvm_object)::set(this, "c2", "cfg", cfg2);
    	c1 = comp1::type_id::create("c1", this);
    	c2 = comp1::type_id::create("c2", this);
	endfunction
endclass
initial begin
    run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] cfg.val1 is 30 after get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] cfg.str1 is c1 after get
UVM_INFO @ 0: uvm_test_top.c2 [SETVAL] cfg.val1 is 50 after get
UVM_INFO @ 0: uvm_test_top.c2 [SETVAL] cfg.str1 is c2 after get

总结——在使用uvm_config_db::set()/get()时,实际发生了这些后台操作:

  • uvm_config_db::set()通过层次和变量名,将这些信息放置到uvm_pkg唯一的全局变量uvm_pkg::uvm_resources
  • uvm_resources用来存储和释放配置资源信息,它是uvm_resource_pool类的全局唯一实例,该实例中有两个resource数组用来存放配置信息,一个由层次名字索引、一个由类型索引,通过这两个关联数组可存放通过层次配置的信息。
  • 同时低层组件也可通过层次或类型取得来自高层的配置信息,这种方式使信息的配置和获取得到剥离,便于调试复用
  • 在使用uvm_config_db::get()方法时,通过传递的参数构成索引层次,然后在uvm_resource已有的配置信息池索引该配置,索引到返回1,否则返回0。

建议

  • 使用set/get()方法时传递的参数类型应上下保持一致。对uvm_object等实例的传递,若get类型与set类型不一致,应先通过$cast()完成类型转换再对类型转换后的对象进行操作。
  • set/get()方法传递的参数可使用通配符*表示任意层次,同时用户需懂得.comp1*comp1的区别,前者表示在目前层次以下所有名称为“comp1”的组件,后者表示包括当前层次及当前层次以下所有名为“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获取到,若没有,是否需要采取其他措施。
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值