factory机制

factory机制

本质

  • factory机制是UVM框架中的一个重要组件,用于创建和管理组件实例
  • 它通过注册组件类型根据类型创建实例,实现了组件的动态创建管理
  • factory机制的核心是uvm_factory类,它负责注册组件类型创建组件实例管理组件实例
  • 注册发生在编译时和初始化阶段,通过调用uvm_component_utils宏来注册组件类型

目的:

  • 实现组件的动态创建管理
  • 确保组件在树形结构中的正确位置和命名

1. Factory机制的核心概念

  • factory机制的核心是uvm_factory类,它负责注册类型管理类型重载创建实例
  • uvm_factory是一个抽象类,UVM使用uvm_default_factory作为默认实现
  • 类型注册和实例创建通过代理模式实现,使用轻量级的uvm_object_wrapper子类作为类型代理

2. uvm_factory的主要功能

uvm_factory类提供以下核心功能:

  1. 类型注册:通过register方法注册类型代理
  2. 类型重载:通过set_type_override_by_type/nameset_inst_override_by_type/name方法设置类型重载
  3. 实例创建:通过create_component_by_type/namecreate_object_by_type/name方法创建实例
  4. 类型查找:通过find_wrapper_by_name等方法查找已注册的类型

3. 类型注册机制

  • 类型注册是将组件或对象类型的代理(uvm_object_wrapper子类)注册到factory中

  • 注册过程在uvm_default_factory中通过以下成员变量实现:

    • m_types[uvm_object_wrapper]:存储已注册的类型代理
    • m_type_names[string]:存储类型名称到类型代理的映射
  • 注册流程:

    1. 组件/对象类通过宏注册生成类型代理(uvm_component_registryuvm_object_registry
    2. 类型代理通过initialize方法调用factory.register(this)完成注册
    3. factory将类型代理添加到内部数据结构中

4. 实例创建机制

  • 实例创建是根据类型代理或类型名称创建组件或对象实例
  • 创建过程:
    1. 检查是否存在实例重载
    2. 如果没有实例重载,检查是否存在类型重载
    3. 根据重载规则确定最终的类型代理
    4. 调用类型代理的create_componentcreate_object方法创建实例

5. 宏注册的实现

  • 宏注册是使用UVM提供的工具宏,简化类型注册过程
  • 对于组件类,使用uvm_component_utils(T)宏;对于对象类,使用uvm_object_utils(T)
  • 宏展开后会生成以下代码:
    • 类型代理的typedef(type_id
    • get_type()静态方法
    • get_object_type()虚方法
    • create_component/create_object方法(根据类型)
    • 类型名称声明和get_type_name()方法

宏注册的实现细节

uvm_component_utils(T)宏为例,其展开逻辑如下:

// uvm_component_utils宏的实现
`define uvm_component_utils(T) \
   `m_uvm_component_registry_internal(T,T) \
   `uvm_type_name_decl(`"T") \

// 其中m_uvm_component_registry_internal宏展开为:
`define m_uvm_component_registry_internal(T,S) \
  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(); \
    return type_id::get(); \
  endfunction \
  function uvm_component create_component(string name, uvm_component parent); \
    uvm_component tmp; \
    tmp = type_id::create(name, parent); \
    return tmp; \
  endfunction

// uvm_type_name_decl宏展开为:
`define uvm_type_name_decl(N) \
  const static string type_name = N; \
  virtual function string get_type_name(); \
    return type_name; \
  endfunction

当在组件类中使用uvm_component_utils(my_component)时,宏会展开为:

class my_component extends uvm_component;
  // 宏展开后的代码
  typedef uvm_component_registry#(my_component, "my_component") 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_component create_component(string name, uvm_component parent);
    uvm_component tmp;
    tmp = type_id::create(name, parent);
    return tmp;
  endfunction
  const static string type_name = "my_component";
  virtual function string get_type_name();
    return type_name;
  endfunction
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass

6. 注册与创建的完整流程

  1. 编译时

    • 组件/对象类使用宏注册,生成类型代理相关代码
    • 类型代理的静态初始化触发延迟注册
  2. 初始化时

    • UVM核心初始化,处理延迟注册队列
    • 类型代理调用initialize方法,完成向factory的注册
  3. 运行时

    • 通过type_id::create()或factory方法创建实例
    • factory根据重载规则确定最终类型
    • 类型代理创建并返回实例

7. 利用factory的重载的特点与方法

  • factory机制支持组件和对象类型的重载,允许在运行时替换默认类型为其他类型,实现灵活的测试配置

  • 重载分为两种类型:

    • 类型重载:对所有该类型的实例进行替换
    • 实例重载:仅对特定路径的实例进行替换
  • 重载过程是在创建实例之前通过factory的方法设置,当调用create方法时,factory会根据重载规则创建相应的类型实例

  • 内置重载方法:

    • 类型重载方法:
      • set_type_override_by_type(original_type, override_type, replace)
      • set_type_override_by_name(original_type_name, override_type_name, replace)
    • 实例重载方法:
      • set_inst_override_by_type(relative_inst_path, original_type, override_type)
      • set_inst_override_by_name(relative_inst_path, original_type_name, override_type_name)
  • 命令行重载:

    • 可以在命令行中使用-uvm_set_type_override-uvm_set_inst_override选项来设置类型和实例重载
  • 覆盖优先级

    • 类型重载:根据注册顺序,后注册的类型会覆盖先注册的类型
    • 实例重载:根据路径顺序,后设置的实例重载会覆盖先设置的实例重载
    • 命令行重载:在命令行中使用-uvm_set_type_override-uvm_set_inst_override选项来设置类型和实例重载,命令行设置的重载会覆盖程序中设置的重载
  • override机制必须满足的三个条件:

    • 原始类(被覆盖的类)和覆盖类(新的派生类)都必须使用uvm_component_utils或uvm_object_utils宏在工厂中注册
    • 原始类必须通过工厂的type_id::create()方法创建
    • 覆盖操作(调用set_type_override或set_inst_override)必须在目标对象被创建之前进行

UVM的树形结构实现

UVM的树形结构本质是通过uvm_component构造函数实现的,具体机制如下:

uvm_component具有如下变量和方法:

  • 变量

    1. m_parent:指向父组件的指针
    2. m_children:关联数组,存储子组件的指针
    3. m_children_by_handle:关联数组,根据组件句柄存储子组件的指针
  • 方法

    1. new:构造函数,用于创建组件实例
    2. m_add_child:将子组件添加到当前组件的子组件列表中

1. 构造函数的核心逻辑

uvm_component的构造函数是树形结构形成的关键,其核心代码如下:

function uvm_component::new (string name, uvm_component parent);
  uvm_root top;
  uvm_coreservice_t cs;
  
  super.new(name);
  
  // 获取核心服务和根节点
  cs = uvm_coreservice_t::get();
  top = cs.get_root();  // 获取uvm_root实例
  
  // 当parent为null时,自动设置为uvm_root
  if (parent == null) begin
    parent = top;
  end
  
  // 检查子组件名称唯一性
  if (parent.has_child(name) && this != parent.get_child(name)) begin
    // 处理名称冲突错误
  end
  
  // 设置父组件并添加到父组件的子列表中
  m_parent = parent;
  set_name(name);
  if (!m_parent.m_add_child(this)) begin
    m_parent = null;
  end
  
  // 继承父组件的域
  m_domain = parent.m_domain;
  
  // 其他初始化...
endfunction

2. 树形结构的形成过程

  1. 根节点初始化

    • uvm_root是一个特殊的uvm_component,作为整个组件树的根节点

    • 通过uvm_coreservice_t::get().get_root()获取唯一的根节点实例

    • 核心代码:

       static local uvm_root m_inst;  // 静态局部变量,存储**单例实例**
       
       function uvm_root uvm_root::new();
         super.new("**top**", null);
         // 防止创建多个根实例
         if (m_inst != null) begin
           `uvm_fatal_context("UVM/ROOT/MULTI",
           "Attempting to construct multiple roots",
           m_inst)
           return;
         end
         m_inst = this;  // 将当前实例赋值给静态变量
         // 其他初始化...
       endfunction
      
  2. 父组件设置

    • 当创建组件时不指定父组件(设为null),系统会自动将其父组件设置为uvm_root
    • 这样确保了所有组件最终都归属于同一个根节点下
    • 通常,uvm_test的parent是null,其他组件的parent都是uvm_test
  3. 子组件添加

    • 通过m_parent.m_add_child(this)当前组件添加到父组件的子组件列表

3. 树形结构的特点

  • 唯一性:每个组件在其父组件下都有唯一的名称
  • 层次化:通过点号分隔的层次化名称表示组件在树中的位置
  • 完整性:所有组件都属于同一个组件树,根节点是uvm_root
  • 可遍历性:通过get_first_childget_next_child等方法可以遍历组件树
posted @ 2026-03-03 22:24  justifice  阅读(64)  评论(0)    收藏  举报