UVM验证入门(3)-factory工厂机制

98 阅读8分钟

1. 单例类Singleton Class

  单例类是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在UVM库中,单例模式被广泛应用于一些管理器类(manager classes),例如uvm_root(UVM的根类)、uvm_factory(工厂类)、uvm_report_handler(报告处理器)等。

1.1 单例类的定义方法

  • 将构造函数声明为protected,以防止外部通过new直接创建实例。
  • 定义一个静态(static)成员变量来保存类的唯一实例。
  • 提供一个公共的静态方法(通常名为get)来获取该唯一实例。在这个方法中,如果实例尚未创建,则创建实例;否则返回现有实例。
class singleton_example extends uvm_object;
    // 静态实例变量
    protected 	static 		singleton_example m_inst;
   // ↑访问权限  ↑存储类别    ↑数据类型     	  ↑变量名
     
    // 私有构造函数 - 关键所在!
    protected function new(string name = "singleton_example");
        super.new(name);
        `uvm_info("SINGLETON", "Constructor called", UVM_LOW)
    endfunction
    
    // 获取实例的静态方法
    static function singleton_example get();
        if (m_inst == null) begin
            m_inst = new();  // 只有这里能调用构造函数
        end
        return m_inst;
    endfunction
endclass

  创建单例类实例时,调用get方法即可:

singleton_example obj = singleton_example::get(); //调用get方法创建对象

singleton_example obj1 = singleton_example::get(); //第二次调用,返回同一对象

1.2 单例类的优点

  • 全局访问:提供统一的全局访问点
  • 资源节约:避免重复创建相同功能的实例
  • 状态共享:便于在多个组件间共享状态信息
  • 配置集中:集中管理全局配置信息

2. 工厂机制概述与设计理念

2.1 什么是UVM工厂机制

  UVM工厂机制是一种基于类型重载的面向对象设计模式,它允许在运行时动态替换对象和组件的类型,而无需修改原始代码。这是UVM框架中实现可配置性和可重用性的核心特性。

2.2 工厂机制的设计目标

  • 灵活性:在不修改测试平台代码的情况下改变组件或对象类型
  • 可重用性:相同的测试环境可以配置不同的组件实现
  • 可维护性:通过配置而非代码修改来适应变化
  • 可扩展性:轻松添加新的组件类型而不影响现有代码

2.3 工厂机制的基本原理

  在上一章节中介绍了单例类的特性,UVM中工厂机制就是一个单例类的典型应用,如下图中为uvm factory类的部分源码,与单例类的定义一致,uvm_factory用了更严格的local属性。 在这里插入图片描述   单例类保证了在整个验证环境中只创建一个工厂,以确保统一管理。

// 传统方式 - 硬编码类型
my_driver drv = new("drv");

// 工厂方式 - 动态类型创建
my_driver drv = my_driver::type_id::create("drv");

  工厂内部建立了一张类型注册表,通过维护一个类型注册表,在运行时根据注册信息创建对象实例,并支持用派生类型替换基类型。

3. 工厂注册机制与类型声明

  工厂内部建立的类型注册表通过关联数组实现,数组的索引是注册的类型,值是 uvm_object_wrapper 类型的对象。 在这里插入图片描述

3.1 组件和对象的注册宏

  UVM提供了不同的注册宏用于组件和对象:

// 对于uvm_component派生类
`uvm_component_utils(T)                    // 非参数化组件
`uvm_component_param_utils(T)             // 参数化组件

// 对于uvm_object派生类  
`uvm_object_utils(T)                      // 非参数化对象
`uvm_object_param_utils(T)                // 参数化对象

3.2 注册宏的使用示例

// 组件注册示例
class my_driver extends uvm_driver #(my_transaction);
    `uvm_component_utils(my_driver)        // 组件注册
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
endclass

// 对象注册示例
class my_transaction extends uvm_sequence_item;
    `uvm_object_utils(my_transaction)      // 对象注册
    
    rand bit [31:0] addr;
    rand bit [31:0] data;
    
    function new(string name = "my_transaction");
        super.new(name);
    endfunction
endclass

// 参数化类注册示例
class my_sequencer #(type T = my_transaction) extends uvm_sequencer #(T);
    `uvm_component_param_utils(my_sequencer #(T))  // 参数化组件注册
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
endclass

3.3 注册宏的内部机制

  在uvm源码中,注册宏展开如下:

//先将uvm_component_utils(T) 宏展开为两个宏
`define uvm_component_utils(T) \
   `m_uvm_component_registry_internal(T,T) \
   `m_uvm_get_type_name_func(T) \

//m_uvm_component_registry_internal(T,S) 展开如下
//`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

//m_uvm_get_type_name_func(T) 展开如下
//`define m_uvm_get_type_name_func(T) 
   const static string type_name = `"T`"; 
   virtual function string get_type_name (); 
     return type_name; 
   endfunction 

4. 对象创建与工厂方法

4.1 工厂创建方法

  使用工厂机制创建对象和组件:

class my_env extends uvm_env;
    `uvm_component_utils(my_env) //注册到工厂
    
    my_driver     drv;
    my_monitor    mon;
    my_sequence   seq;
    
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        // 使用工厂创建组件
        drv = my_driver::type_id::create("drv", this);
        mon = my_monitor::type_id::create("mon", this);
        
        // 使用工厂创建对象(在运行时)
        seq = my_sequence::type_id::create("seq");
    endfunction
endclass

  注册后创建实例时,my_driver为用户自定义的类,type_id为uvm_component_registry的别名,create是uvm_component_registry类预定义的方法

4.2 创建方法的参数说明

// 组件创建:需要名称和父组件指针
comp = component_type::type_id::create(string name, uvm_component parent);

// 对象创建:只需要名称
obj = object_type::type_id::create(string name);

4.3 工厂创建的优势

class base_test extends uvm_test;
    virtual function void create_components();
        // 传统方式 - 编译时绑定
        // my_driver drv = new("drv", this);
        
        // 工厂方式 - 运行时绑定,支持重载
        my_driver drv = my_driver::type_id::create("drv", this);
    endfunction
endclass

5. 类型重载机制与方法

  重载(Override)是UVM工厂机制中最重要的功能之一,它提供了运行时类型替换的强大能力,在工厂中建立了重载的队列,当需要重载时,在队列中查找重载。 在这里插入图片描述

5.1 常用的重载类型

  • 类型重载:类型重载影响所有该类型实例的创建。

//---------------------------------按类型设置重载---------------------------
// 方法原型
function void set_type_override_by_type (uvm_object_wrapper original_type, 
                                        uvm_object_wrapper override_type,
                                        bit replace=1);

// 使用示例
factory.set_type_override_by_type(
    base_driver::get_type(),      // 原始类型
    enhanced_driver::get_type(),  // 重载类型
    1                             // 替换已存在的重载
);

//---------------------------------按类型名设置重载---------------------------
// 方法原型
function void set_type_override_by_name (string original_type_name,
                                        string override_type_name,
                                        bit replace=1);

// 使用示例
factory.set_type_override_by_name(
    "base_driver",        // 原始类型名
    "enhanced_driver",    // 重载类型名
    1                     // 替换已存在的重载
);
  • 实例重载:实例重载只影响特定路径的实例创建。
//---------------------------------按类型设置实例重载---------------------------
// 方法原型
function void set_inst_override_by_type (string relative_inst_path,
                                        uvm_object_wrapper original_type,
                                        uvm_object_wrapper override_type);

// 使用示例
factory.set_inst_override_by_type(
    "env.agent.driver0",          // 实例路径
    base_driver::get_type(),      // 原始类型
    debug_driver::get_type()      // 重载类型
);

//---------------------------------按类型名设置实例重载---------------------------
// 方法原型
function void set_inst_override_by_name (string relative_inst_path,
                                        string original_type_name,
                                        string override_type_name);

// 使用示例
factory.set_inst_override_by_name(
    "env.agent.monitor",          // 实例路径
    "base_monitor",               // 原始类型名
    "coverage_monitor"            // 重载类型名
);

5.2 重载的应用场景

// 基础驱动类
class my_driver extends uvm_driver #(my_transaction);
    `uvm_component_utils(my_driver)
    // 基础功能实现
endclass

// 增强驱动类
class enhanced_driver extends my_driver;
    `uvm_component_utils(enhanced_driver)
    // 添加性能监控、错误检测等增强功能
endclass

// 错误注入驱动类  
class error_injection_driver extends my_driver;
    `uvm_component_utils(error_injection_driver)
    // 专门用于错误注入测试
endclass

// 在测试中应用重载
class error_injection_test extends uvm_test;
    virtual function void build_phase(uvm_phase phase);
        // 对特定驱动实例应用错误注入
        set_inst_override_by_type("env.agent*.drv", 
                                 my_driver::get_type(),
                                 error_injection_driver::get_type());
    endfunction
endclass

6. 实际应用与最佳实践

6.1 完整的工厂应用示例

// 基础事务类
class base_transaction extends uvm_sequence_item;
    `uvm_object_utils(base_transaction)
    rand bit [31:0] addr;
    rand bit [31:0] data;
endclass

// 扩展事务类
class extended_transaction extends base_transaction;
    `uvm_object_utils(extended_transaction)
    rand bit [7:0]  user_id;
    rand bit        priority;
endclass

// 基础序列类
class base_sequence extends uvm_sequence #(base_transaction);
    `uvm_object_utils(base_sequence)
    
    virtual task body();
        base_transaction tr;
        tr = base_transaction::type_id::create("tr");
        // 序列逻辑
    endtask
endclass

// 基础驱动类
class base_driver extends uvm_driver #(base_transaction);
    `uvm_component_utils(base_driver)
    
    virtual task run_phase(uvm_phase phase);
        forever begin
            seq_item_port.get_next_item(req);
            // 驱动逻辑
            seq_item_port.item_done();
        end
    endtask
endclass

// 测试类 - 演示工厂重载
class factory_test extends uvm_test;
    `uvm_component_utils(factory_test)
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        // 在测试开始时设置重载
        // 1. 全局类型重载 - 所有base_transaction被extended_transaction替换
        set_type_override_by_type(base_transaction::get_type(),
                                 extended_transaction::get_type());
        
        // 2. 特定组件重载 - 只有这个测试使用增强驱动
        set_type_override_by_type(base_driver::get_type(),
                                 enhanced_driver::get_type());
    endfunction
endclass

6.2 调试和报告方法

class factory_debug extends uvm_test;
    virtual function void report_phase(uvm_phase phase);
        uvm_factory factory = uvm_factory::get();
        
        `uvm_info("FACTORY", "Factory debug information:", UVM_LOW)
        
        // 打印所有已注册的类型
        factory.print();
        
        // 打印所有已设置的重载
        factory.print_overrides();
        
        // 检查特定类型是否被重载
        if (factory.find_override_by_type(base_driver::get_type(), 
                                        this.get_full_name()) != null) begin
            `uvm_info("FACTORY", "base_driver is overridden in this test", UVM_MEDIUM)
        end
    endfunction
endclass

6. 总结

  UVM工厂机制通过类型注册、动态创建和类型重载,为验证环境提供了极大的灵活性和可扩展性。掌握工厂机制的使用方法和最佳实践,对于构建可重用、可配置的验证平台至关重要。通过合理运用工厂机制,可以实现测试用例的高度定制化,而无需修改底层验证组件代码。、


上一篇:UVM验证入门(2)-uvm常用类的继承关系 下一篇:UVM验证入门(4)-TLM1.0

参考文档:UVM_Cl ass_Reference_Manual_1.0.pdf