UVM-1.1学习(三)——`uvm_object_utils的本质

在UVM中,我们经常使用`uvm_object_utils或者`uvm_component_utils来将uvm_object/uvm_component注册,但很多同学并不清楚注册是怎么实现的,因此本文主要分析下`uvm_object_utils的注册究竟做了什么。

1 `uvm_object_utils(T)的展开

`uvm_object_utils本质上是一个宏,这个宏由另外两个宏`xxx_begin、`xxx_end组成,而`xxx_begin又是由几段功能宏组成:

`define uvm_object_utils(T) \
  `uvm_object_utils_begin(T) \
  `uvm_object_utils_end

`define uvm_object_utils_begin(T) \
   `m_uvm_object_registry_internal(T,T)  \
   `m_uvm_object_create_func(T) \
   `m_uvm_get_type_name_func(T) \
   `uvm_field_utils_begin(T) 
       
`define uvm_object_utils_end \
     end \
   endfunction \

2 `uvm_object_utils_begin(T)的子内容

2.1 `m_uvm_object_registry_internal(T,T)

先看代码:

//This is needed due to an issue in of passing down strings
//created by args to lower level macros.
`define m_uvm_object_registry_internal(T,S) \
   typedef uvm_object_registry#(T,`"S`") type_id; \
   static function type_id get_type(); \
     return type_id::get(); \
   endfunction \
   virtual function uvm_object_wrapper get_object_type(); \
     return type_id::get(); \
   endfunction

这个宏里面只做了两件事情:

  • 定义了一个参数化的类,这个参数化的类叫type_id;
  • 给class定义了两个函数,get_type()函数与get_object_type()函数。

粗略一看,这两件事情好像和uvm_object的注册没有什么关系,其实不然。对于参数化的类type_id,我们可以把它抽象成一个简单的哈希(key-value,type_id的名字也是由此而来)。由于这些宏的参数实际上就是类名T。所以它的key-value就是uvm_object的类名(class name)和类的名称(string)。随着这个宏的展开,我们相当于给class额外定义了两个函数:get_type()和get_object_type()。由于uvm_object_registry #(T,“S”)是一个singletone的class,所以get_type()和get_object_type()的函数内容一样,区别在于返回值的句柄不同。对于get_type(),返回的是type_id的句柄;对于get_object_type(),返回uvm_object_wrapper的句柄。
这里面还有一个细节,我们在上一层传递的宏参数是(T, T),但实际使用时第二个参数是被当作字符串来进行使用的。因此使用了`"S`"这样的语法。

2.1.1 uvm_object_registry(T, S)

上文中的type_id实际上是参数化的类,两个参数可以看成是哈希的key-value。在这个参数化的类的get()函数中,通过uvm_factory的register函数将它自己注册,或者说将这个哈希放到一个全局的登记表格中去了。
顺带一提另一个经常看见的函数create()。它的作用也很简单,即根据给定名字(string),在全局的登记表格中查找匹配的句柄,并利用该句柄来创建一个新的实例。
下面是摘自UVM的部分源代码:

class uvm_object_registry #(type T=uvm_object, string Tname="")
                                        extends uvm_object_wrapper;
  typedef uvm_object_registry #(T,Tname) this_type;
  ...
    local static this_type me = get();

  // Function: get
  //
  // Returns the singleton instance of this type. Type-based factory operation
  // depends on there being a single proxy instance for each registered type. 
  static function this_type get();
    if (me == null) begin
      uvm_factory f = uvm_factory::get();
      
      me = new;
      f.register(me);
    end
    return me;
  endfunction
  ...
  // Function: create
  //
  // Returns an instance of the object type, ~T~, represented by this proxy,
  // subject to any factory overrides based on the context provided by the
  // ~parent~'s full name. The ~contxt~ argument, if supplied, supercedes the
  // ~parent~'s context. The new instance will have the given leaf ~name~,
  // if provided.
  static function T create (string name="", uvm_component parent=null,
                            string contxt="");
    uvm_object obj;
    uvm_factory f = uvm_factory::get();
    if (contxt == "" && parent != null)
      contxt = parent.get_full_name();
    obj = f.create_object_by_type(get(),contxt,name);
    if (!$cast(create, obj)) begin
      string msg;
      msg = {"Factory did not return an object of type '",type_name,
        "'. A component of type '",obj == null ? "null" : obj.get_type_name(),
        "' was returned instead. Name=",name," Parent=",
        parent==null?"null":parent.get_type_name()," contxt=",contxt};
      uvm_report_fatal("FCTTYP", msg, UVM_NONE);
    end
  endfunction
  ...

uvm_object_registry比较有意思的是它利用了static method和get()函数结合,实现了singleton的效果。

2.2 `m_uvm_object_create_func(T)

这个宏里面完成的事情很简单,只是给class定义了create()函数。

`define m_uvm_object_create_func(T) \
   `ifdef UVM_CREATE_OPT \
        virtual function void call_new(); \
        endfunction \
   `else \
    function uvm_object create (string name=""); \
        T tmp; \
       `ifdef UVM_OBJECT_MUST_HAVE_CONSTRUCTOR \
          if (name=="") tmp = new(); \
          else tmp = new(name); \
       `else \
          tmp = new(); \
          if (name!="") \
            tmp.set_name(name); \
       `endif \
       return tmp; \
    endfunction \
   `endif

至此,我们有了两种方式来创建uvm_object:

 - user_object.create("user_object");
 - user_object::type_id::create("user_object");

注意第一种方式实际上只是new()的另一种写法而已。

2.3 `m_uvm_get_type_name_func(T)

这个宏里面完成的事情同样也很简单,只是给class定义了type_name变量和get_type_name()函数。

`define m_uvm_get_type_name_func(T) \
   const static string type_name = `"T`"; \
   virtual function string get_type_name (); \
     return type_name; \
   endfunction

2.4 `uvm_field_utils_begin(T)

这里面是和field automation相关的一些代码,这里就不展开进行说明了。

你可能感兴趣的:(芯片验证,uvm)