지노랩 /JinoLab

[UVM] 3.3 드라이버(Driver) 생성 본문

UVM(Universal Verification Methodology)/3. 재사용 가능한 검증 컴포넌트 개발(Developing Reusabl

[UVM] 3.3 드라이버(Driver) 생성

지노랩/JinoLab 2025. 3. 11. 12:08

3.3 드라이버(Driver) 생성

3.3.1 드라이버의 역할

  • 드라이버는 버스 프로토콜에 따라 데이터를 DUT(Device Under Test)로 전송하는 역할을 한다.
  • 드라이버는 시퀀서(Sequencer)에서 트랜잭션을 받아 실행한다.
  • UVM에서는 모든 드라이버 클래스가 uvm_driver 클래스를 직접 또는 간접적으로 상속해야 한다.
  • 드라이버는 TLM 포트(TLM Port)를 통해 시퀀서와 통신하며, 필요한 경우 실행 단계(run-time phases)도 구현할 수 있다.

3.3.2 드라이버 생성 과정

드라이버를 생성하려면 다음 단계를 따라야 한다.

  1. uvm_driver 클래스를 상속하여 드라이버 클래스를 생성한다.
  2. UVM 매크로(uvm_component_utils)를 추가하여 UVM Factory에서 객체를 생성하고 관리할 수 있도록 한다.
  3. 시퀀서에서 데이터를 가져와 실행하는 동작을 정의한다.
  4. DUT와 연결하기 위한 가상 인터페이스(virtual interface)를 선언한다.

3.3.3 드라이버 구현 예제

아래 예제는 simple_driver 클래스를 정의하며, 이 드라이버는 simple_item 트랜잭션 타입을 사용하여 시퀀서와 통신한다.

// simple_item을 사용하는 uvm_driver 생성
class simple_driver extends uvm_driver #(simple_item);
  simple_item s_item;  // 시퀀서에서 받을 트랜잭션 데이터
  virtual dut_if vif;  // DUT와 연결할 가상 인터페이스

  // UVM Factory에서 객체를 생성할 수 있도록 매크로 추가
  `uvm_component_utils(simple_driver)

  // 생성자 (부모 클래스 uvm_driver의 생성자 호출)
  function new (string name = "simple_driver", uvm_component parent);
    super.new(name, parent);
  endfunction : new

  // build_phase: 가상 인터페이스 설정
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
      `uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".vif"});
  endfunction : build_phase

  // run_phase: 시퀀서에서 데이터를 가져와 실행
  task run_phase(uvm_phase phase);
    forever begin
      // 시퀀서에서 데이터 아이템 가져오기 (blocking 호출)
      seq_item_port.get_next_item(s_item);
      
      // 데이터 아이템 실행
      drive_item(s_item);

      // 시퀀서에 실행 완료 알림
      seq_item_port.item_done();
    end
  endtask : run_phase

  // 실제 데이터를 DUT에 전달하는 로직을 구현할 부분
  task drive_item(input simple_item item);
    // 여기에 DUT 인터페이스로 데이터를 전달하는 로직을 추가
  endtask : drive_item
endclass : simple_driver

3.3.4 코드 설명

  • Line 1: uvm_driver 클래스를 상속받아 simple_driver 클래스를 생성.
  • Line 5: uvm_component_utils 매크로를 추가하여 UVM Factory에서 객체를 인스턴스화할 수 있도록 함.
  • Line 13: uvm_config_db를 사용하여 virtual interface를 가져옴.
  • Line 22: seq_item_port.get_next_item()을 호출하여 시퀀서에서 트랜잭션을 가져옴.
  • Line 25: seq_item_port.item_done()을 호출하여 트랜잭션이 완료되었음을 시퀀서에 알림.
  • Line 30: drive_item()을 구현하여, 실제 DUT에 데이터를 전달하는 로직을 작성.

3.3.5 드라이버와 시퀀서의 연결

  • 드라이버는 TLM 포트를 통해 시퀀서와 연결되며, seq_item_port.get_next_item()을 사용하여 트랜잭션을 가져온다.
  • seq_item_port.item_done()을 호출하여 현재 트랜잭션이 완료되었음을 시퀀서에 알림.
  • 시퀀서와 드라이버 간의 연결 방법에는 여러 가지가 있으며, 이에 대한 자세한 내용은 3.5절에서 다룸.

✅ 3.3 요약

  • 드라이버는 시퀀서에서 받은 트랜잭션을 실행하여 DUT로 전달하는 역할을 수행.
  • uvm_driver 클래스를 상속받아 드라이버 클래스를 정의해야 함.
  • seq_item_port.get_next_item()을 통해 트랜잭션을 가져오고 실행.
  • 실행이 완료되면 seq_item_port.item_done()을 호출하여 시퀀서에 완료 신호 전달.
  • 가상 인터페이스(virtual interface)를 사용하여 DUT와 연결.

 

 

 


 

본 내용은
accellera에서 공개한
Universal Verification Methodology
(UVM) 1.2 User's Guide
를 바탕으로 작성된 글입니다.