UVM factory 的理解

文章详细解释了在SystemVerilog的UVM框架中,如何通过`uvm_object_utils`宏和`create`方法来创建对象。它涉及到`uvm_object_registry`类,`uvm_factory`以及`create_object_by_type`和`create_object`函数的调用链,最终通过`new`关键字实例化对象。虽然在创建过程中有两次提到`new`,但实际只执行了一次实例化操作,因为`create_object`在找到正确的类型后调用`new`,确保了对象的正确创建和注册。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通常情况下我们会使用factory机制如下:(这里我们以object为例,component的原理是类似的)

class my_seq extends uvm_seqeuence_item;
  `uvm_object_utils(my_seq)
...
endclass:my_seq

然后我们就可以create:

class my_test extends uvm_test;
  ...
  task main_phase(uvm_phase phase);
  my_seq seq0;
  seq0 = my_seq::type_id::create("seq0");
  endtask:main_phase
endclass:my_test

为什么create就可以直接生成seq0这个object呢? sv中只有new的方式可以生成新的object

其背后的操作如下:

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

line1-> lines2->line6->line12,注意line12中的type_id, 其实际上是一个参数类:

uvm_object_registry#(T, `"S`")

那么我们定义的`uvm_object_utils(my_seq),在背后的代码中体现为(这里只说明uvm如何认识我们定义的新的class: my_seq)

type_def uvm_object_regsitery#(my_seq,"my_seq") type_id

同时声明了一个以my_seq作为class 和class-name作为为参数的类成员:type_id

而uvm_object_register这个参数类的定义如下,其中定义了static 函数成员create,get:

class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
                                        extends uvm_object_wrapper;
  typedef uvm_object_registry #(T,Tname) this_type;
。。。
  static function this_type get();
    if (me == null) begin
      uvm_coreservice_t cs = uvm_coreservice_t::get();                                                     
      uvm_factory factory=cs.get_factory();
      me = new;
      factory.register(me);
    end
    return me;
  endfunction
...
  static function T create (string name="", uvm_component parent=null,
                            string contxt="");
    uvm_object obj;
    uvm_coreservice_t cs = uvm_coreservice_t::get();                                                     
    uvm_factory factory=cs.get_factory();
  
    if (contxt == "" && parent != null)
      contxt = parent.get_full_name();
    obj = factory.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

注意其中的第23行,

obj = factory.create_object_by_type(get(),contxt,name);(方便引用,记为--1--)

其中,

  1. get()中包含两个操作:

1.1. new me(即为object);

1.2. factory.register(me);

factory的register操作的定义如下:

function void uvm_default_factory::register (uvm_object_wrapper obj);

  if (obj == null) begin
    uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE);
  end
  if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>") begin
    if (m_type_names.exists(obj.get_type_name()))
      uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(),
        "' already registered with factory. No string-based lookup ",
        "support for multiple types with the same type name."}, UVM_NONE);
    else 
      m_type_names[obj.get_type_name()] = obj;
  end

  if (m_types.exists(obj)) begin
    if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>")
      uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(),
                         "' already registered with factory. "}, UVM_NONE);
  end
  else begin
    m_types[obj] = 1;
    // If a named override happens before the type is registered, need to copy
    // the override queue.
    // Note:Registration occurs via static initialization, which occurs ahead of
    // procedural (e.g. initial) blocks. There should not be any preexisting overrides.
    if(m_inst_override_name_queues.exists(obj.get_type_name())) begin
       m_inst_override_queues[obj] = new;
       m_inst_override_queues[obj].queue = m_inst_override_name_queues[obj.get_type_name()].queue;
       m_inst_override_name_queues.delete(obj.get_type_name());
    end
    if(m_wildcard_inst_overrides.size()) begin
       if(! m_inst_override_queues.exists(obj)) 
            m_inst_override_queues[obj] = new;
       foreach (m_wildcard_inst_overrides[i]) begin
         if(uvm_is_match( m_wildcard_inst_overrides[i].orig_type_name, obj.get_type_name()))
            m_inst_override_queues[obj].queue.push_back(m_wildcard_inst_overrides[i]);
       end
    end

  end

endfunction

注意其中的第12行,会把obj和get_type_name()作为key-value存入关联数组m_type_names中。

而--1--的create_object_by_type的定义如下

function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type,  
                                                        string parent_inst_path="",  
                                                        string name=""); 

  string full_inst_path;

  if (parent_inst_path == "")
    full_inst_path = name;
  else if (name != "")
    full_inst_path = {parent_inst_path,".",name};
  else
    full_inst_path = parent_inst_path;

  m_override_info.delete();

  requested_type = find_override_by_type(requested_type, full_inst_path);

  return requested_type.create_object(name);

endfunction

这里第18行,还是调用create_object,不过这个函数应该是隶属于requested_type的成员,requested_type即为我们所指定的type_id,(即uvm_object_registry),故其最终调用的是

class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
                                        extends uvm_object_wrapper;
  typedef uvm_object_registry #(T,Tname) this_type;

  // Function: create_object
  //
  // Creates an object of type ~T~ and returns it as a handle to a
  // <uvm_object>. This is an override of the method in <uvm_object_wrapper>.
  // It is called by the factory after determining the type of object to create.
  // You should not call this method directly. Call <create> instead.

  virtual function uvm_object create_object(string name="");
    T obj;
`ifdef UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR
    obj = new();
    if (name!="")
      obj.set_name(name);
`else
    if (name=="") obj = new();
    else obj = new(name);
`endif
    return obj;
  endfunction

  const static string type_name = Tname;
。。。
endclass

其中地15行 最终new 产生了所需要的seq0.

其完整的调用逻辑如下

完毕

此处提出一个疑问, 如上图所示,uvm好像调用了两次new,是否多余了呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值