• uvm_config_db——半个全局变量


      UVM中的配置机制uvm_config_db,uvm_config_db机制用于在UVM平台间传递参数。它们通常是成对出现的,set 寄信,而get函数是收信。config 机制大大提高了UVM的验证灵活性。例如module 和 class 连接通过config_db virtual interace.
     
    module tb_top
    
        initial begin
             uvm_config_db #(virtual spi_if)::set(null, "", "vif", vif)
        end
    endmodule
    
    classs spi_drv extend uvm_driver;
    
        virtual spi_if vif;
    
        uvm_config_db #(virtual spi_if)::get(this, "", "vif", vif);
    endclass
      对于config 机制只需要掌握两个原则:一是不同层次进行set,以最高层为准(test比env级要高,env比agent要高);二是同一层进行set,以最后一次set为准。对于环境变量中有大量参数需要设置时,用聚合config 变量,将所有的需要配置的变量放在一个专门的类(my_config extends uvm_object)中实现。
      config_db 机制是UVM中用于在不同component之间共享资源的一种机制,它满足了资源共享的要求,同时避免全局变量的弊端。uvm_config_db 是uvm_resource_db 的外壳。资源共享,有三个问题:
    1 资源是存放在什么地方?( uvm_resource_pool )
    2 资源以什么样的方式共享(存放)(uvm_resource#(type T) )
    3 资源是如何共享的(存取的)(uvm_resource_db #(type T) )
     
    下面然我们先看看uvm_config_db的源代码:
    文件:src/base/uvm_config_db.svh
    类:uvm_config_db,m_uvm_waiter
    The uvm_config_db parameterized class provides a convenience interface on top of uvm_resource_db to simplify the basic interface that is used for reading and writing into the resource database.UVM's configuration facility provides an alternative to using the factory to configure a verification environment.
     
    //----------------------------------------------------------------------
    // class: uvm_config_db
    //
    // All of the functions in uvm_config_db#(T) are static, so they
    // must be called using the :: operator.  For example:
    //
    //|  uvm_config_db#(int)::set(this, "*", "A");
    //
    // The parameter value "int" identifies the configuration type as
    // an int property.  
    //
    // The <set> and <get> methods provide the same API and
    // semantics as the set/get_config_* functions in <uvm_component>.
    //----------------------------------------------------------------------
    class uvm_config_db#(type T=int) extends uvm_resource_db#(T);
    
      // Internal lookup of config settings so they can be reused
      // The context has a pool that is keyed by the inst/field name.
      static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component];
    
      // Internal waiter list for wait_modified
      static local uvm_queue#(m_uvm_waiter) m_waiters[string];
    
      // function: get
      //
      // Get the value for ~field_name~ in ~inst_name~, using component ~cntxt~ as 
      // the starting search point. ~inst_name~ is an explicit instance name 
      // relative to ~cntxt~ and may be an empty string if the ~cntxt~ is the
      // instance that the configuration object applies to. ~field_name~
      // is the specific field in the scope that is being searched for.
      //
      // The basic ~get_config_*~ methods from <uvm_component> are mapped to
      // this function as:
      //
      //| get_config_int(...) => uvm_config_db#(uvm_bitstream_t)::get(cntxt,...)
      //| get_config_string(...) => uvm_config_db#(string)::get(cntxt,...)
      //| get_config_object(...) => uvm_config_db#(uvm_object)::get(cntxt,...)
    
      static function bit get(uvm_component cntxt,
                              string inst_name,
                              string field_name,
                              inout T value);
    //TBD: add file/line
        int unsigned p;
        uvm_resource#(T) r, rt;
        uvm_resource_pool rp = uvm_resource_pool::get();
        uvm_resource_types::rsrc_q_t rq;
        uvm_coreservice_t cs = uvm_coreservice_t::get();
    
        if(cntxt == null) 
          cntxt = cs.get_root();
        if(inst_name == "") 
          inst_name = cntxt.get_full_name();
        else if(cntxt.get_full_name() != "") 
          inst_name = {cntxt.get_full_name(), ".", inst_name};
     
        rq = rp.lookup_regex_names(inst_name, field_name, uvm_resource#(T)::get_type());
        r = uvm_resource#(T)::get_highest_precedence(rq);
        
        if(uvm_config_db_options::is_tracing())
          m_show_msg("CFGDB/GET", "Configuration","read", inst_name, field_name, cntxt, r);
    
        if(r == null)
          return 0;
    
        value = r.read(cntxt);
    
        return 1;
      endfunction
    
      // function: set 
      //
      // Create a new or update an existing configuration setting for
      // ~field_name~ in ~inst_name~ from ~cntxt~.
      // The setting is made at ~cntxt~, with the full scope of the set 
      // being {~cntxt~,".",~inst_name~}. If ~cntxt~ is ~null~ then ~inst_name~
      // provides the complete scope information of the setting.
      // ~field_name~ is the target field. Both ~inst_name~ and ~field_name~
      // may be glob style or regular expression style expressions.
      //
      // If a setting is made at build time, the ~cntxt~ hierarchy is
      // used to determine the setting's precedence in the database.
      // Settings from hierarchically higher levels have higher
      // precedence. Settings from the same level of hierarchy have
      // a last setting wins semantic. A precedence setting of 
      // <uvm_resource_base::default_precedence>  is used for uvm_top, and 
      // each hierarchical level below the top is decremented by 1.
      //
      // After build time, all settings use the default precedence and thus
      // have a last wins semantic. So, if at run time, a low level 
      // component makes a runtime setting of some field, that setting 
      // will have precedence over a setting from the test level that was 
      // made earlier in the simulation.
      //
      // The basic ~set_config_*~ methods from <uvm_component> are mapped to
      // this function as:
      //
      //| set_config_int(...) => uvm_config_db#(uvm_bitstream_t)::set(cntxt,...)
      //| set_config_string(...) => uvm_config_db#(string)::set(cntxt,...)
      //| set_config_object(...) => uvm_config_db#(uvm_object)::set(cntxt,...)
    
      static function void set(uvm_component cntxt,
                               string inst_name,
                               string field_name,
                               T value);
    
        uvm_root top;
        uvm_phase curr_phase;
        uvm_resource#(T) r;
        bit exists;
        string lookup;
        uvm_pool#(string,uvm_resource#(T)) pool;
        string rstate;
        uvm_coreservice_t cs = uvm_coreservice_t::get();
         
        //take care of random stability during allocation
        process p = process::self();
        if(p != null) 
              rstate = p.get_randstate();
              
        top = cs.get_root();
    
        curr_phase = top.m_current_phase;
    
        if(cntxt == null) 
          cntxt = top;
        if(inst_name == "") 
          inst_name = cntxt.get_full_name();
        else if(cntxt.get_full_name() != "") 
          inst_name = {cntxt.get_full_name(), ".", inst_name};
    
        if(!m_rsc.exists(cntxt)) begin
          m_rsc[cntxt] = new;
        end
        pool = m_rsc[cntxt];
    
        // Insert the token in the middle to prevent cache
        // oddities like i=foobar,f=xyz and i=foo,f=barxyz.
        // Can't just use '.', because '.' isn't illegal
        // in field names
        lookup = {inst_name, "__M_UVM__", field_name};
    
        if(!pool.exists(lookup)) begin
           r = new(field_name, inst_name);
           pool.add(lookup, r);
        end
        else begin
          r = pool.get(lookup);
          exists = 1;
        end
          
        if(curr_phase != null && curr_phase.get_name() == "build")
          r.precedence = uvm_resource_base::default_precedence - (cntxt.get_depth());
        else
          r.precedence = uvm_resource_base::default_precedence;
    
        r.write(value, cntxt);
    
        if(exists) begin
          uvm_resource_pool rp = uvm_resource_pool::get();
          rp.set_priority_name(r, uvm_resource_types::PRI_HIGH);
        end
        else begin
          //Doesn't exist yet, so put it in resource db at the head.
          r.set_override();
        end
    
        //trigger any waiters
        if(m_waiters.exists(field_name)) begin
          m_uvm_waiter w;
          for(int i=0; i<m_waiters[field_name].size(); ++i) begin
            w = m_waiters[field_name].get(i);
            if(uvm_re_match(uvm_glob_to_re(inst_name),w.inst_name) == 0)
               ->w.trigger;  
          end
        end
    
        if(p != null)
            p.set_randstate(rstate);
    
        if(uvm_config_db_options::is_tracing())
          m_show_msg("CFGDB/SET", "Configuration","set", inst_name, field_name, cntxt, r);
      endfunction
    
    
      // function: exists
      //
      // Check if a value for ~field_name~ is available in ~inst_name~, using
      // component ~cntxt~ as the starting search point. ~inst_name~ is an explicit
      // instance name relative to ~cntxt~ and may be an empty string if the
      // ~cntxt~ is the instance that the configuration object applies to.
      // ~field_name~ is the specific field in the scope that is being searched for.
      // The ~spell_chk~ arg can be set to 1 to turn spell checking on if it
      // is expected that the field should exist in the database. The function
      // returns 1 if a config parameter exists and 0 if it doesn't exist.
      //
    
      static function bit exists(uvm_component cntxt, string inst_name,
        string field_name, bit spell_chk=0);
        uvm_coreservice_t cs = uvm_coreservice_t::get();
    
        if(cntxt == null)
          cntxt = cs.get_root();
        if(inst_name == "")
          inst_name = cntxt.get_full_name();
        else if(cntxt.get_full_name() != "")
          inst_name = {cntxt.get_full_name(), ".", inst_name};
    
        return (uvm_resource_db#(T)::get_by_name(inst_name,field_name,spell_chk) != null);
      endfunction
    
    
      // Function: wait_modified
      //
      // Wait for a configuration setting to be set for ~field_name~
      // in ~cntxt~ and ~inst_name~. The task blocks until a new configuration
      // setting is applied that effects the specified field.
    
      static task wait_modified(uvm_component cntxt, string inst_name,
          string field_name);
        process p = process::self();
        string rstate = p.get_randstate();
        m_uvm_waiter waiter;
        uvm_coreservice_t cs = uvm_coreservice_t::get();
    
        if(cntxt == null)
          cntxt = cs.get_root();
        if(cntxt != cs.get_root()) begin
          if(inst_name != "")
            inst_name = {cntxt.get_full_name(),".",inst_name};
          else
            inst_name = cntxt.get_full_name();
        end
    
        waiter = new(inst_name, field_name);
    
        if(!m_waiters.exists(field_name))
          m_waiters[field_name] = new;
        m_waiters[field_name].push_back(waiter);
    
        p.set_randstate(rstate);
    
        // wait on the waiter to trigger
        @waiter.trigger;
      
        // Remove the waiter from the waiter list 
        for(int i=0; i<m_waiters[field_name].size(); ++i) begin
          if(m_waiters[field_name].get(i) == waiter) begin
            m_waiters[field_name].delete(i);
            break;
          end
        end 
      endtask
    
    
    endclass
    从上面可以看uvm_config_db#(type T=int) extends uvm_resource_db#(T),也是说uvm_config_db 只是对uvm_resource_db 重新封装了一次。对uvm_resource_db
    的一些功能进行了扩展,在写入操作上重载了uvm_resource_db的set 函数,在读操作上新建了一个get 函数。
    让我们来看看这两个静态函数set and get 函数(有点类似于存储器的写和读功能),首先来看,uvm_config_db 的set 函数。再看uvm_config_db 的get 函数。
    
    
  • 相关阅读:
    3.1按钮
    2.1线性布局
    2.2相对布局
    1.4Activity保存现场状态
    1.1Activity跳转与传值
    1.2Activity返回值
    1.3Activity生命周期
    WebSocket
    Jms消费者模式
    课堂实践5-31
  • 原文地址:https://www.cnblogs.com/dpc525/p/7900812.html
Copyright © 2020-2023  润新知