[UVM] uvm_factory & Override 완전 정리 | type_id::create, set_type_override, set_inst_override

2026. 4. 10. 20:02UVM

반응형

uvm_factory란?

UVM Factory는 컴포넌트나 오브젝트를 직접 new()로 생성하지 않고, 이름 기반으로 간접 생성하게 해주는 메커니즘입니다. 이를 통해 테스트별로 특정 클래스를 다른 클래스로 동적으로 교체(Override)할 수 있습니다. 실제 DUT에 손 대지 않고 테스트 레벨에서 동작을 바꾸는 핵심 기법입니다.

예를 들어, 일반 테스트에서는 my_driver를 쓰다가 에러 주입 테스트에서는 error_driver로 교체하고 싶을 때, 코드 수정 없이 Factory Override 한 줄로 해결할 수 있습니다.


type_id::create — Factory를 통한 생성

Factory를 활용하려면 반드시 new() 대신 type_id::create()로 인스턴스를 만들어야 합니다.

// 잘못된 방법 — Factory를 거치지 않음
my_driver drv = new("drv", this);

// 올바른 방법 — Factory를 통해 생성
my_driver drv = my_driver::type_id::create("drv", this);

type_id::create()는 내부적으로 Factory에 등록된 클래스를 찾아 인스턴스를 생성합니다. Override가 걸려 있으면 원래 클래스 대신 Override된 클래스가 생성됩니다.


uvm_component_utils / uvm_object_utils 매크로

Factory에 클래스를 등록하려면 반드시 아래 매크로를 클래스 안에 선언해야 합니다.

// uvm_component 계열 클래스
class my_driver extends uvm_driver #(my_item);
  `uvm_component_utils(my_driver)
  // ...
endclass

// uvm_object 계열 클래스
class my_item extends uvm_sequence_item;
  `uvm_object_utils(my_item)
  // ...
endclass

이 매크로들이 Factory에 클래스를 자동 등록합니다. 매크로를 빠뜨리면 Override가 동작하지 않습니다.


Override 종류

1. Type Override — 전체 교체

해당 타입의 모든 인스턴스를 교체합니다. Test의 build_phase에서 호출합니다.

class error_test extends uvm_test;
  `uvm_component_utils(error_test)

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    // my_driver 대신 error_driver를 전역으로 사용
    my_driver::type_id::set_type_override(error_driver::get_type());

    // 또는 동일한 의미:
    factory.set_type_override_by_type(
      my_driver::get_type(),
      error_driver::get_type()
    );
  endfunction
endclass

2. Instance Override — 특정 경로만 교체

경로(inst_path)를 지정해서 특정 인스턴스만 교체합니다. 와일드카드 *를 사용할 수 있습니다.

function void build_phase(uvm_phase phase);
  super.build_phase(phase);

  // env.agent0.drv 경로의 driver만 교체
  my_driver::type_id::set_inst_override(
    error_driver::get_type(),
    "env.agent0.drv"
  );

  // 또는:
  factory.set_inst_override_by_type(
    my_driver::get_type(),
    error_driver::get_type(),
    {get_full_name(), ".env.agent0.drv"}
  );
endfunction

Instance Override는 Type Override보다 우선합니다. 같은 경로에 두 가지가 모두 설정되어 있으면 Instance Override가 적용됩니다.


실전 예제 — 에러 주입 드라이버 교체

// 기본 드라이버
class my_driver extends uvm_driver #(my_item);
  `uvm_component_utils(my_driver)

  task run_phase(uvm_phase phase);
    forever begin
      my_item req;
      seq_item_port.get_next_item(req);
      // 정상 동작 구동
      drive_normal(req);
      seq_item_port.item_done();
    end
  endtask
endclass

// 에러 주입 드라이버 (my_driver 상속)
class error_driver extends my_driver;
  `uvm_component_utils(error_driver)

  task run_phase(uvm_phase phase);
    forever begin
      my_item req;
      seq_item_port.get_next_item(req);
      // 에러 조건 추가 후 구동
      inject_error(req);
      drive_normal(req);
      seq_item_port.item_done();
    end
  endtask

  task inject_error(my_item req);
    if ($urandom_range(0,9) == 0)
      req.data = ~req.data; // 10% 확률로 비트 반전
  endtask
endclass

// 테스트에서 Override 적용
class error_injection_test extends uvm_test;
  `uvm_component_utils(error_injection_test)
  my_env env;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Override 먼저 설정 — create() 호출 전에 해야 함
    my_driver::type_id::set_type_override(error_driver::get_type());
    env = my_env::type_id::create("env", this);
  endfunction
endclass

Factory Print — 등록 현황 확인

시뮬레이션에서 현재 Factory에 등록된 클래스와 Override 상태를 출력할 수 있습니다.

// 모든 등록된 컴포넌트 출력
factory.print();

// 특정 타입의 Override 결과 확인
factory.debug_create_by_type(my_driver::get_type(), "env.agent.drv");

커맨드라인에서 Override — +uvm_set_type_override

코드 수정 없이 시뮬레이터 실행 시 플러스아규먼트로도 Override를 지정할 수 있습니다.

// 실행 커맨드
// simv +UVM_TESTNAME=base_test +uvm_set_type_override=my_driver,error_driver

이 방법은 회귀 테스트 자동화에서 특히 유용합니다. CI 스크립트에서 테스트명과 Override를 동시에 제어할 수 있습니다.


핵심 정리

Factory Override를 올바르게 사용하기 위한 포인트입니다. 첫째, 반드시 type_id::create()를 써야 Override가 적용됩니다. new()로 생성하면 Override를 설정해도 무시됩니다. 둘째, Override는 create() 호출 이전에 설정해야 합니다. 셋째, Override 대상 클래스는 반드시 원본 클래스의 자식(또는 같은 계층)이어야 합니다. 넷째, `uvm_component_utils 또는 `uvm_object_utils 매크로를 빠뜨리면 Factory에 등록되지 않아 Override가 동작하지 않습니다.