3. 使用UVM工厂创建组件

使用UVM工厂创建组件 学习卡片

任务目标

本案例将实现一个最小UVM验证环境,演示两个核心点:一是通过uvm_component_utils宏注册组件并使用create()方法创建实例;二是利用UVM工厂的set_type_override_by_type()机制实现组件类型重载,验证重载后工厂实际创建的是新类型对象。

环境依赖

需要支持UVM-1.2或UVM-2020的仿真器(如VCS、QuestaSim、Xcelium)。以下代码基于UVM-1.2标准库编写,无需额外安装包。

完整实现代码

```systemverilog
// 文件: factory_demo.sv
`include "uvm_macros.svh"
import uvm_pkg::*;

// 基类组件:普通driver
class base_driver extends uvm_component;
    `uvm_component_utils(base_driver)
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    virtual function void print_type();
        $display("[%0t] %s: I am BASE driver", $time, get_full_name());
    endfunction
endclass

// 派生类组件:扩展driver,重载print_type
class ext_driver extends base_driver;
    `uvm_component_utils(ext_driver)
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    virtual function void print_type();
        $display("[%0t] %s: I am EXTENDED driver", $time, get_full_name());
    endfunction
endclass

// 测试顶层:创建组件并演示工厂重载
class factory_test extends uvm_test;
    `uvm_component_utils(factory_test)
    
    base_driver drv1;
    base_driver drv2;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // 1. 正常创建:drv1为base_driver类型
        drv1 = base_driver::type_id::create("drv1", this);
        
        // 2. 注册类型重载:所有base_driver创建请求改为ext_driver
        base_driver::type_id::set_type_override_by_type(
            base_driver::get_type(),
            ext_driver::get_type()
        );
        
        // 3. 重载后创建:drv2实际为ext_driver类型
        drv2 = base_driver::type_id::create("drv2", this);
    endfunction
    
    virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        $display("=== 类型检查 ===");
        drv1.print_type();
        drv2.print_type();
        
        // 使用uvm_is_a验证实际类型
        if (drv2.uvm_is_a("ext_driver"))
            $display("PASS: drv2 is ext_driver (factory override works)");
        else
            $display("FAIL: drv2 is not ext_driver");
    endfunction
endclass

// 顶层模块:启动UVM测试
module top;
    initial begin
        run_test("factory_test");
    end
endmodule
```

运行方式

```bash
# 使用QuestaSim/ModelSim示例(其他仿真器命令类似)
vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv factory_demo.sv
vsim -c -do "run -all; quit" work.top
```

验证方法与判定标准

运行仿真后,观察终端输出。满足以下条件即判定通过:

  • drv1.print_type()打印I am BASE driver,证明普通创建得到基类对象;
  • drv2.print_type()打印I am EXTENDED driver,且后续显示PASS: drv2 is ext_driver,证明工厂重载生效。

预期输出(与代码逻辑严格一致):

=== 类型检查 ===
[0] uvm_test_top.drv1: I am BASE driver
[0] uvm_test_top.drv2: I am EXTENDED driver
PASS: drv2 is ext_driver
```

关键点说明

  • 组件必须用`uvm_component_utils宏注册,工厂才能识别并创建该类型;
  • set_type_override_by_type()必须在create()之前调用,且影响后续所有匹配类型的创建请求;
  • 重载要求新类型是原类型的派生类,否则仿真器会报类型不匹配错误。