UVM--config机制

1 config机制

•    在验证环境的创建过程build phase中,除了组件的实例化,配置也是必不可少的。
•    为了验证环境的复用性,通过外部的参数配置,使得环境在创建时可以根据不同参数来选择创建的组件类型、组件实例数目、组件之间的连接以及组件的运行模式等。
•    在更细致的环境调节(environment tuning)中有更多的变量需要配置,例如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); 
•    uvm_config_db# (T): :get(uvm_component cntxt, string inst_name,string field_name, inout T value); 

•    UVM的uvm_config_db使得接口的传递和获取彻底分离开来。
•    在实现接口传递的过程中需要注意:
接口传递应该发生在run_test()之前。这保证了在进入build phase之前,virtual interface已经被传递到uvm_config_db中。
•    用户应当把interface与virtual interface的声明区分开来,在传递过程中的类型应当为virtual interface, 即实际接口的句柄。

interface 传递

//interface 传递
	interface intfl; 
    logic enable= O; 
    endinterface
    class compl extends uvm_component; 
	`uvm_component_utils(compl) 
    virtual intfl vif; 
    function void build_phase(uvm_phase phase);
	if (!uvm_config_db # (virtual intfl)::get(this,"", "vif", vif)) begin 
    `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 = l; 
    'uvm_info("SETVAL", $sformatf("vif. enable is %b after set", vif.enable), UVM_LOW) 
	endfunction 
	endclass 
	
	class testl extends uvm_test;
	`uvm_component_utils(testl) 
	compl cl; 
	...
	endclass 
    intfl intf();
	initial begin
	uvm_config_db#(virtual intfl)::set(uvm_root::get(),"uvm_test_top.cl", "vif", intf);
	run_test("test1");
	end 
	/*输出结果:
     UVM_INFO @ 0: reporter [RNTST] Running test test1... 
     UVM_INFO @ 0: uvm_test_top.cl [SETVAL] vif.enable is O before set 
	 UVM_INFO @ 0: uvm_test_top.cl [SETVAL] vif.enable is 1 after set

变量传递

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

//变量配置
	 class compl extends uvm_component;
	 `uvm_component_utils(compl) 
     int vall= l; 
     string strl = "null"; 
	 ...
	 function void build_phase(uvm_phase phase);
	 `uvm_info("SETVAL",$sformatf("vall is %d before get", vall), UVM_LOW) 
	 `uvm_info("SETVAL",$sformatf("strl is %s before get",strl), UVM_LOW) 
	 `uvm_config_db #(int)::get(this,"", "vall", vall); 
     `uvm_config_db #(string)::get(this, "", "strl",strl);
     `uvm_info("SETVAL", $sformatf("vall is %d after get",vall), UVM_LOW) 
	 `uvm_info("SETVAL",$sformatf("strl is %s after get"'strl),UVM_LOW) 
	 endfunction 
	 endclass 
	 class testl extends uvm_test;
	 `uvm_component_utils(test1)
	 compl cl; 
	 ...
	 function void build_phase(uvm_phase phase) ;
	 `uvm config db#(int):: set(this, "cl", "vall", 100); 
     `uvm_config_db#(string)::set(this, "cl", "strl", "compl"); 
	 cl = compl::type_id::create("cl", this);
	 endfunction
     endclass
    //输出结果:
     UVM_INFO @ 0: uvm_test_top.cl [SETVAL] vall is 1 before get 
	 UVM_INFO @ 0: uvm_test_top.cl [SETVAL] strl is null before get 
	 UVM_INFO @ 0: uvm_test_top.cl [SETVAL] vall is 100 after get 
	 UVM_INFO @ 0: uvm_test_top.cl [SETVAL] strl is compl after get 

在test配置中, 需要配置的参数不只是数量多, 而且可能还分属于不同的组件。

那么如果对这么多层次中的变量做出类似上面的变量设置, 那会需要更多的代码, 容易出错还不易于复用, 甚至底层组件的变量被删除后, 也无法通过uvm_config_db::set()得知配置是否成功。
然而如果将每个组件中的变星加以整合, 首先放置到一个uvm_object中, 再对中心化的配置对象进行传递, 那么将会更有利于整体环境的修改维护。

//object传递
    class configl extends uvm_object;
    int vall= 1; 
    int strl= "null"; 
    `uvm_object utils(configl)	
	...
	endclass 
    class compl extends uvm_component;
	'uvm_component_utils(compl}
    configl cfg; 
    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.vallis %d afterget",cfg.vall}, UVM_LOW) 
    endfunction
    endclass 
	
	class test1 extends uvm_test;
	`uvm_componen_utils(test1)
    compl cl, c2; 
    configl cfgl, cfg2; 
    function void build_phase(uvm_phase phase);
	cfgl = configl::type_id::create("cfgl"); 
    cfg2 = configl::type_id::create ("cfg2"); 
    cfgl.vall = 30; 
    cfgl.strl="cl"; 
    cfg2.vall = 50; 
    cfg2.strl="c2"; 
    `uvm_config_db #(uvm object)::set(this,"cl", "cfg", cfgl);
	`uvm_config_db #(uvm object)::set(this,"c2", "cfg", cfg2); 
	cl = compl::type_id::create("cl", this); 
    c2 = compl::type_id::create("c2", this);
	endfunction 
	endclass
	//结果:
	输出结果:
    UVM INFO @ 0: uvm_test一top.cl [SETVAL] cfg.vall is 30 after get 
	UVM INFO @ 0: uvm_test一top.cl [SETVAL] cfg.strl is cl after get
	UVM INFO @ 0: uvm_test一top.c2 [SETVAL] cfg.vall is 50 after get
	UVM INFO @ 0: uvm_test一top.c2 [SETVAL] cfg.strl is c2 after get

总结:

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

uvm_config_db::set()通过层次和变量名,将这些信息放置到uvm_pkg唯一的全局变量uvm_pkg::uvm_resources。

全局变量uvm_resources用来存储和释放配置资源信息(resource information)。uvm_resources 是uvm_resources_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获取到,如果没有获取,是否需要采取其它措施。

以下案例涵盖本节所有重点:

interface uvm_config_if;
  logic [31:0] addr;
  logic [31:0] data;
  logic [ 1:0] op;
endinterface

package uvm_config_pkg;
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  
  class config_obj extends uvm_object;
    int comp1_var;
    int comp2_var;
    `uvm_object_utils(config_obj)
    function new(string name = "config_obj");
      super.new(name);
      `uvm_info("CREATE", $sformatf("config_obj type [%s] created", name), UVM_LOW)
    endfunction
  endclass
  
  class comp2 extends uvm_component;
    int var2;
    virtual uvm_config_if vif;  
    config_obj cfg; 
    `uvm_component_utils(comp2)
    function new(string name = "comp2", uvm_component parent = null);
      super.new(name, parent);
      var2 = 200;
      `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "comp2 build phase entered", UVM_LOW)
      //TODO-4.1
      //Please get the interface and check if it is got
        if(!uvm_config_db #(virtual uvm_config_if)::get(this,"","vif",vif))
		`uvm_error("GETVIF","no virtual interface is got")
		else
		`uvm_info("GETVIF","virtual interface is got",UVM_LOW)
       `uvm_info("GETINT", $sformatf("before config get, var2 = %0d", var2), UVM_LOW)
      //TODO-4.3
      //Please get the var2 from config_db
	   uvm_config_db # (int)::get(this,"","var2",var2);
      `uvm_info("GETINT", $sformatf("after config get, var2 = %0d", var2), UVM_LOW)
      //TODO-4.2
      //Please get the config object
	  uvm_config_db#(config_obj)::get(this,"","cfg",cfg);
      `uvm_info("GETOBJ", $sformatf("after config get, cfg.comp2_var = %0d", cfg.comp2_var), UVM_LOW)     
      
      `uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
    endfunction
  endclass

  class comp1 extends uvm_component;
    int var1;
    comp2 c2;
    config_obj cfg; 
    virtual uvm_config_if vif;
    `uvm_component_utils(comp1)
    function new(string name = "comp1", uvm_component parent = null);
      super.new(name, parent);
      var1 = 100;
      `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
      //TODO-4.1
      //Please get the interface and check if it is got
      if(!uvm_config_db #( virtual uvm_config_if)::get(this,"","vif",vif))
	    `uvm_error("GETVIF","no virtual interface is got")
		else
		`uvm_info("GETVIF","virtual interface is got",UVM_LOW)		  
      `uvm_info("GETINT", $sformatf("before config get, var1 = %0d", var1), UVM_LOW)
      //TODO-4.3
      //Please get the var1 from config_db
	  uvm_config_db#(int)::get(this,"","var1",var1);
      `uvm_info("GETINT", $sformatf("after config get, var1 = %0d", var1), UVM_LOW)
      
      //TODO-4.2
      //Please get the config object
	  uvm_config_db #(config_obj)::get(this,"","cfg",cfg);
      `uvm_info("GETOBJ", $sformatf("after config get, cfg.comp1_var = %0d", cfg.comp1_var), UVM_LOW)
      
      c2 = comp2::type_id::create("c2", this);
      `uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
    endfunction
  endclass

  class uvm_config_test extends uvm_test;
    comp1 c1;
    config_obj cfg;
    `uvm_component_utils(uvm_config_test)
    function new(string name = "uvm_config_test", uvm_component parent = null);
      super.new(name, parent);
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "uvm_config_test build phase entered", UVM_LOW)
      
      cfg = config_obj::type_id::create("cfg");
      cfg.comp1_var = 100;
      cfg.comp2_var = 200;
      //TODO-4.2
      //Please config the object to c1 and c2 by config_db
      uvm_config_db#(config_obj)::set (this,"*","cfg",cfg);
		
      //TODO-4.3
      //Please config the c1.var1=20, c2.var2=20 by config_db
      uvm_config_db#(int)::set(this,"c1","var1",20);
	  uvm_config_db#(int)::set(this,"c1.c2","var2",20);
      c1 = comp1::type_id::create("c1", this);
      `uvm_info("BUILD", "uvm_config_test build phase exited", UVM_LOW)
    endfunction
    task run_phase(uvm_phase phase);
      super.run_phase(phase);
      `uvm_info("RUN", "uvm_config_test run phase entered", UVM_LOW)
      phase.raise_objection(this);
      #1us;
      phase.drop_objection(this);
      `uvm_info("RUN", "uvm_config_test run phase exited", UVM_LOW)
    endtask
  endclass
endpackage

module uvm_config;

  import uvm_pkg::*;
  `include "uvm_macros.svh"
  import uvm_config_pkg::*;
  
  uvm_config_if if0();
  
  //TODO-4.1
  //Please set interface to the c1 and c2 in the environment
  initial begin
  uvm_config_db # (virtual uvm_config_if)::set(uvm_root::get(),"uvm_test_top","vif",if0);
    run_test(""); // empty test name
  end
endmodule

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
UVM中的config_db机制是一种方便的配置管理机制,可以在测试用例中动态地配置不同组件之间的参数。它允许用户将配置信息存储在单个数据库中,并在需要时从中检索。 config_db机制的核心是一个名为uvm_config_db的类,它提供了一些静态方法,用于将配置信息存储在数据库中、从数据库中检索配置信息和删除配置信息。每个配置信息都有一个名称和一个通用的数据类型,可以是任意类型的数据结构,包括简单的整数和字符串,以及更复杂的对象和指针。 config_db机制可以用于多种情况,例如: 1. 在测试用例中配置测试环境中的组件; 2. 在测试用例中配置测试用例本身; 3. 在测试用例中配置测试运行时环境(如时钟周期)。 下面是一个例子,展示如何使用config_db机制来配置两个组件之间的参数: ```systemverilog // 存储配置信息 uvm_config_db#(int)::set(null, "env.agent1.config", "data", 100); uvm_config_db#(string)::set(null, "env.agent2.config", "data", "hello"); // 从数据库中检索配置信息 int my_int; string my_string; uvm_config_db#(int)::get(null, "env.agent1.config", "data", my_int); uvm_config_db#(string)::get(null, "env.agent2.config", "data", my_string); ``` 在上面的例子中,我们使用uvm_config_db类的set方法将一个整数值和一个字符串值存储在了数据库中,并使用get方法从数据库中检索这些值。注意,我们使用了不同的名称("env.agent1.config"和"env.agent2.config")来区分不同的配置信息。这些名称应该在测试用例中被定义为常量或宏,以便在整个测试用例中使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创芯人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值