uvm中的config机制方法总结(一)

在验证环境的创建过程build phase中,除了组件的实例化过程,配置阶段也是必不可少的。为了验证环境的复用性,通过外部的参数配置,使得环境在创建的时候可以根据参数的不同来选择创建的组件、组件的实例个数、组件之间的连接以及组件的运行模式等等。在更细致的环境调节(environment tuning)中,有更多的变量需要配置,例如for-loop的阈值、字符串名称、随机变量的生成比重等等。 无论是配置哪些参数,用户都可以在编译时间或者仿真时间来设置。对于编译时间中要调整这些变量,可以通过修改参数、或者引入预处理指令(compiler directive,例如ifdef/ifndef/else/elsif/`endif)来修改。比起重新编译而言,在仿真中可以通过变量设置来修改环境,就显得更灵活了,而UVM config机制正是提供这么做的方法。
UVM提供了uvm_config_db的配置类以及几种很方便的变量设置方法来实现在仿真时的环境控制。常见的uvm_config_db的使用方式包括有:
1.传递virtual interface到环境中。
2.设置单一变量值,例如int、string、enum等。
3.传递配置对象(config object)到环境。
下面的几段例码分别来对这几种方式进行说明。
1.interface传递
首先来看看interface的传递,通过这种方便的传递方式很好地解决了连接硬件世界和软件世界。而在之前关于SV的核心篇章中,读者们可以看到,虽然SV可以通过层次化interface的索引来完成传递,但是这种方式不利于软件环境的封装和复用。下面这种方式,使得接口的传递和获取彻底分离开来,而在后台对virtual interface的传递立下功劳的便是uvm_config_db。

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
        `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("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

从上面这个例子可以看到,接口的传递从硬件世界到UVM环境中的传递可以通过uvm_config_db来实现。在实现过程中需要注意几点:
接口的传递应该发生在run_test()之前。这保证了在进入build phase之前,virtual interface已经传递进入uvm_config_db中。
用户应当把interface与virtual interface的声明区分开来。在传递过程中的类型应当为virtual interface,即实际接口的句柄。

2.变量设置
在各个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 after get
  1. config object传递
    在实际的test配置中,需要配置的参数不单单数量多,而且还分属于不同的组件。那么,如果对这么多层次中的变量做出类似上面的单一变量设置,一方面需要更多的代码,这就容易出错,不易于阅读,另外一方面也不易于复用,毕竟底层组件的变量有添加或者减少,通过uvm_config_db::set是无法得知是否设置成功的。因此,如果将每个组件中的变量加以整合,首先放置到一个uvm_object中用于传递,那么将会更有利于整体进行配置。
  import uvm_pkg::*;
  `include "uvm_macros.svh"

  class config1 extends uvm_object;
    int val1 = 1;
    int str1 = "null";
    `uvm_object_utils(config1)
    function new(string name = "config1");
      super.new(name);
    endfunction
  endclass

  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
UVMconfig_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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值