uvm_factory——户部尚书

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、工厂机制

工厂机制负责管理uvm世界中所有object、component的注册覆盖以及create前覆盖类的查找

二、相关类(uvm_default_factory、uvm_*_registry、uvm_factory_override)

uvm_default_factory :定义了注册、设置覆盖、创建、查找覆盖等方法。
protected uvm_object_wrapper m_type_names[string]:类似于哈希表,保存对象类型的名称和类型的映射关系。
protected bit m_types[uvm_object_wrapper]:1表示该类型已被注册。
protected uvm_factory_override m_type_overrides[$]:队列,用于存储对象类型的覆盖规则。

uvm_object_registry#(type T = uvm_object,string Tname=‘’):作为工厂注册的基本单元,可创建类型T的对象。
const static string type_name = Tname:每个代理类都有唯一的type_name。
function string get_type_name:返回唯一的名字type_name。
local static this_type me = get():每个代理类都只有唯一的实例me。
static function this_type get():返回唯一的实例me。
function uvm_object create_object (string name):创建名字为name的T的对象,用工厂机制创建对象的最后一步。
static function T create (string name=“”):使用工厂机制创建对象。
static function void set_type_override (uvm_object_wrapper override_type,bit replace=1):调用工厂机制进行类型覆盖
static function void set_inst_override:调用工厂机制进行实例覆盖

uvm_factory_override:
uvm_object_wrapper orig_type:源类型
uvm_object_wrapper ovrd_type:覆盖类型
string orig_type_name:源类型对应的type_name
string ovrd_type_name:覆盖类型对应的type_name

三、源代码分析

1.注册

放入m_type_name中,以提高类型查找的效率,避免重复注册。
a:在uvm_component_utils内声明了类型为uvm_component_registry的type_id,然后调用type_id内的get函数。

`define uvm_component_utils(T) \
   `m_uvm_component_registry_internal(T,T) \
   `m_uvm_get_type_name_func(T) \
   `define m_uvm_component_registry_internal(T,S) \
   
 // `m_uvm_component_registry_internal(T,T) \
 typedef uvm_component_registry #(T,`"S`") type_id; \
 static function type_id get_type(); \
   return type_id::get(); \
 endfunction \
 virtual function uvm_object_wrapper get_object_type(); \

b:在type_id内的get函数中创建了uvm_component_registry的对象,调用register对其进行注册。

  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

c:注册时,先检查是否已经注册过,有的话发出警告。如果没有则将registry放到m_type_name中,m_type设为1表明已经注册。

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;

2.覆盖

分为类型覆盖和实例覆盖,背后都由工厂完成。(以set_type_override_by_type为例)
a:先检查original_type 和 override_type是否相同,参数类type_name为‘’且没有get_type_name函数,所以这里进行了区分。

function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      bit replace=1);
  bit replaced;
 
  // check that old and new are not the same
  if (original_type == override_type) begin
    if (original_type.get_type_name() == "" || original_type.get_type_name() == "<unknown>")
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical"}, UVM_NONE);
    else
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical: ",
                                    original_type.get_type_name()}, UVM_NONE);
  end
 
  // register the types if not already done so, for the benefit of string-based lookup
  if (!m_types.exists(original_type))
    register(original_type); 
 
  if (!m_types.exists(override_type))
    register(override_type); 

b:看m_type_override中能否找到original_type,若能说明之前已经被替换过,将replaced赋值为1,将覆盖规则进行更新。

  // check for existing type override
  foreach (m_type_overrides[index]) begin
    if (m_type_overrides[index].orig_type == original_type ||
        (m_type_overrides[index].orig_type_name != "<unknown>" &&
         m_type_overrides[index].orig_type_name != "" &&
         m_type_overrides[index].orig_type_name == original_type.get_type_name())) begin
      string msg;
      msg = {"Original object type '",original_type.get_type_name(),
             "' already registered to produce '",
             m_type_overrides[index].ovrd_type_name,"'"};
      if (!replace) begin
        msg = {msg, ".  Set 'replace' argument to replace the existing entry."};
        uvm_report_info("TPREGD", msg, UVM_MEDIUM);
        return;
      end
      msg = {msg, ".  Replacing with override to produce type '",
                  override_type.get_type_name(),"'."};
      uvm_report_info("TPREGR", msg, UVM_MEDIUM);
      replaced = 1;
      m_type_overrides[index].orig_type = original_type; 
      m_type_overrides[index].orig_type_name = original_type.get_type_name(); 
      m_type_overrides[index].ovrd_type = override_type; 
      m_type_overrides[index].ovrd_type_name = override_type.get_type_name(); 
    end
  end

c:若replaced=0说明没有找到,该规则为新的,将其push_back到m_type_override。

  // make a new entry
  if (!replaced) begin
    uvm_factory_override override;
    override = new(.orig_type(original_type),
                   .orig_type_name(original_type.get_type_name()),
                   .full_inst_path("*"),
                   .ovrd_type(override_type));
 
    m_type_overrides.push_back(override);
  end

3.创建

由工厂机制进行创建(以create举例)

a:type_id中有create函数,通过调用factory的create_*_by_type来创建名字为‘name’的对象。

  static function T create(string name, uvm_component parent, 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_component_by_type(get(),contxt,name,parent);
    if (!$cast(create, obj)) begin
      string msg;
      msg = {"Factory did not return a component 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

b:工厂中先调用find_override_by_type获取覆盖类,在调用覆盖类中的creat_*进行创建。

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

c:在find_override_by_type中,先遍历m_type_override看是否有覆盖规则。
如果有,递归调用find_override_by_type,直到找不到替代规则时返回当前request_type。(递归的原因是覆盖类可能也 会被其他类覆盖,所以递归到最上面一层)
如果没有,说明没有被覆盖,所以直接返回当前request_type。
在这里插入图片描述

# 总结
本文介绍了工厂机制管理uvm_*_registry的逻辑。
register是指将registry放入m_type_name中,一个类一个registry,防止多次注册。
override是指将覆盖规则override放入m_factory_override中,用于在create前检查。
create中new操作是在registry中完成,然而在new前需要在工厂内调用find_override_by_type寻找覆盖类,若找到则有覆盖registry创建。
  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值