UVM的工厂机制(factory)

本文深入探讨了UVM中的工厂(factory)机制,阐述了其在验证环境中方便替换实例和类型的重要性。通过注册uvm_object和uvm_component,工厂能够实现无侵入式的代码复用。详细解析了注册过程,包括uvm_object_utils宏的展开,以及create方法背后的工厂创建逻辑。同时,介绍了覆盖机制,如set_type_override,强调了工厂在类型覆盖和实例覆盖中的关键作用。总结指出,正确使用工厂的注册、创建和覆盖功能是发挥其优势的关键。

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

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


前言

工厂机制是UVM的真正魅力所在,也是软件的一种设计模式,接下来我将对工厂的意义和背后机制做一个简单的说明

一、工厂(factory)的意义

factory的存在就是为了更方便的**替换**验证环境中的实例或注册了的类型,从而避免了在原有代码上的改动,便于复用。

二、工厂(factory)的运行

1.注册

uvm_object和uvm_component是factory的模具,工厂机制是为了这两个类服务。要想使用工厂机制,必须先注册

·uvm_object_ubils、·uvm_component_ubils

2.注册的背后

注册由上述两个宏完成,以·uvm_object_utils为例,把宏进行展开。

代码如下(示例):

typedef uvm_object_registry#(trans,"trans") 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   

function uvm_object create (string name=""); 
  trans tmp; 
`ifdef UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR 
  tmp = new(); 
  if (name!="") 
    tmp.set_name(name); 
`else 
  if (name=="") tmp = new(); 
  else tmp = new(name); 
`endif 
  return tmp; 
endfunction 

const static string type_name = "trans"; 
virtual function string get_type_name (); 
  return type_name; 
endfunction  

function void __m_uvm_field_automation (uvm_object tmp_data__, 
                                  int what__, 
                                  string str__); 
begin 
  trans local_data__; /* Used for copy and compare */ 
  typedef trans ___local_type____; 
  string string_aa_key; /* Used for associative array lookups */ 
  uvm_object __current_scopes[$]; 
  if(what__ inside {UVM_SETINT,UVM_SETSTR,UVM_SETOBJ}) begin 
     if(__m_uvm_status_container.m_do_cycle_check(this)) begin 
         return; 
     end 
     else 
         __current_scopes=__m_uvm_status_container.m_uvm_cycle_scopes; 
  end 
  super.__m_uvm_field_automation(tmp_data__, what__, str__); 
  /* Type is verified by uvm_object::compare() */ 
  if(tmp_data__ != null) 
    /* Allow objects in same hierarchy to be copied/compared */ 
    if(!$cast(local_data__, tmp_data__)) return;  

  end 
endfunction 

上述代码显示,通过宏做了以下几步:
1、定义了type_id类型,类型为uvm_object_registry。
2、定义了get_type、get_object_type、create、get_type_name、 __m_uvm_field_automation四个静态方法(component没有最后一个和create)****
解释:
1、uvm_object_registry和uvm_component_registry为uvm_object_wrapper的子类,uvm_object_wrapper有三个函数(creat_object、creat_component、get_type_name),uvm_object_registry在此基础上新增了create,set_type_overvide, set_inst_override,get四个方法
2、如上图代码所示,通过定义get_type和get_object_type会调用type_id的get函数,get函数会调用uvm_factory::register对type_id(也就是代理类)进行注册。注册后,type_id的create就可以通过factory::create_object_by_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

3.create的背后

注册好的object或component也就有了三种create方式,分别是利用uvm_object_wrapper的create_object,利用uvm_object_registry的create,利用工厂的create_object_by_type,但是背后实际都是由factory的create_object_by_type完成,工厂会根据代理类的type或者name来创建type句柄并返回

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

在create之前工厂还会看里面的代理类是否被override,根据被覆盖的type创建。
覆盖方法:
set_type_override_by_type (uvm_object_wrapper original_type,
uvm_object_wrapper override_type,bit replace=1);factory
set_type_override_by_name (string original_type_name,
string override_type_name, bit replace=1);factory
set_type_override (uvm_object_wrapper override_type, bit replace=1);registry
set_inst_override(uvm_object_wrapper override_type,string inst_path,
uvm_component parent=null);registry
实际registry的override背后也由factory执行

 static function void set_inst_override(uvm_object_wrapper override_type,
                                         string inst_path,
                                         uvm_component parent=null);
    string full_inst_path;
    uvm_coreservice_t cs = uvm_coreservice_t::get();                                                     
    uvm_factory factory=cs.get_factory();
    
    if (parent != null) begin
      if (inst_path == "")
        inst_path = parent.get_full_name();
      else
        inst_path = {parent.get_full_name(),".",inst_path};
    end
    factory.set_inst_override_by_type(get(),override_type,inst_path);
  endfunction

总结

以上就是我总结的factory机制,覆盖是factroy最有优势的地方。要想使用factory机制,必须要先注册。通过注册、创建、覆盖即可发挥出factory的全部优势。
create方法和override的方法有很多,但背后都有由actory实现,选择其中一种使用即可,我推荐采用registry的方法,因为相比于factory更加简单。
create: T::type_id::create();
set_type_override: T1::type_id::set_type_override(T2::get_type());

### UVM 工厂机制的工作原理与实现方式 UVM(Universal Verification Methodology)中的工厂机制是一种强大的工具,允许用户动态地替换对象类型而不改变其原始代码逻辑。这种灵活性使得测试平台更加通用和可扩展。 #### 1. **UVM Factory 的核心概念** UVM 工厂是一个全局存在的“机构”,负责管理所有已注册的类及其实例化过程。任何希望利用工厂机制的类都必须先完成注册操作[^3]。一旦某个类被成功注册到工厂中,它就可以通过 `create` 方法而非传统的 `new` 方法来实例化对象。这种方式不仅简化了对象创建流程,还支持运行时的对象类型重载(Override),从而增强了设计的灵活性[^2]。 #### 2. **Factory Mechanism 实现的关键要素** ##### (a) 类注册 为了使某特定类可以参与工厂机制开发者需将其显式注册至工厂数据库。通常情况下,在定义此类时会调用宏命令如 `uvm_object_utils()` 或者 `uvm_component_utils()` 来自动执行这一任务。这些宏内部实现了必要的元数据记录工作以便后续查找匹配合适的派生类实例。 ```cpp class my_class extends uvm_object; `uvm_object_utils(my_class) function new(string name="my_class"); super.new(name); endfunction : new endclass : my_class ``` 上述代码片段展示了如何声明并注册一个新的基于 `uvm_object` 的子类给 UVM framework 使用[^4]。 ##### (b) 对象创建 – Create vs New 当采用标准的新建语法 (`new`) 创建组件或事务项时,返回的具体类型始终固定不变;然而如果改用由工厂提供的接口(`create`) 则可能依据当前设置而获得完全不同的衍生版本作为结果[^5]: ```cpp // Traditional instantiation using 'new' my_base_class obj = new(); // Dynamic creation via the factory's 'create' method. my_base_class overridden_obj = my_base_class::type_id::create("overridden_instance_name", parent_comp); ``` 这里需要注意的是第二个参数代表父级组件指针,对于顶层组件来说传入 null 即可。 ##### (c) Type Override 和 Name Override 两种主要形式可用于指定哪些基底类别应该替换成其他替代品: - **Type Override**: 配置整个模拟期间有效的一般性映射关系。 ```tcl set_type_override_by_type(base_t, derived_t) ``` - **Instance Override**: 局限于某些具体命名路径下的个别实体才生效 ```tcl set_inst_override_by_type(parent_path.base_t, inst_name, derived_t) ``` 这两种策略均依赖先前讨论过的预先登记步骤才能正常运作[^1]。 #### 3. **调试辅助功能** 除了基本的功能外,UVM 还提供了若干实用程序帮助我们确认预期行为是否达成目标状态之一便是打印出完整的环境树形图谱: ```cpp uvm_top.print_topology(); ``` 此指令将会输出当前加载好的全部层次结构连同各节点名称以及它们所属种类等细节信息便于排查潜在错误点或者验证设定准确性. --- ### 结论 综上所述,UVM Factories 提供了一种优雅的方法让工程师能够在不修改原有架构的前提下轻松调整实际部署的内容物; 它们背后隐藏着一套复杂却井然有序的操作规程涵盖了从初始准备到最后应用落地各个环节. ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值