SystemVerilog 기본 문법 가이드 (4부)

계속해서 SystemVerilog의 고급 기능들을 살펴보겠습니다.

19. 고급 인터페이스 활용 (Advanced Interface Usage)

인터페이스를 더 효과적으로 활용하는 방법을 알아보겠습니다.

// 모듈러 인터페이스 정의
interface axi_if #(
    parameter DATA_WIDTH = 32,
    parameter ADDR_WIDTH = 32
)(
    input logic clk,
    input logic rst_n
);
    // 인터페이스 신호
    logic [ADDR_WIDTH-1:0] addr;
    logic [DATA_WIDTH-1:0] wdata;
    logic [DATA_WIDTH-1:0] rdata;
    logic                  write;
    logic                  read;
    logic                  valid;
    logic                  ready;
    
    // 모듈러 포트 정의
    modport master (
        output addr, wdata, write, read,
        input  rdata, valid, ready
    );
    
    modport slave (
        input  addr, wdata, write, read,
        output rdata, valid, ready
    );
    
    // 클럭킹 블록 정의
    clocking cb @(posedge clk);
        default input #1step output #1ns;
        output addr, wdata, write, read;
        input  rdata, valid, ready;
    endclocking
    
    // 테스트 모듈포트 (클럭킹 블록 포함)
    modport tb (
        clocking cb
    );
    
    // 인터페이스에 태스크 정의
    task automatic write_data(input logic [ADDR_WIDTH-1:0] a, input logic [DATA_WIDTH-1:0] d);
        @(posedge clk);
        addr  <= a;
        wdata <= d;
        write <= 1'b1;
        read  <= 1'b0;
        wait(ready);
        @(posedge clk);
        write <= 1'b0;
    endtask
    
    task automatic read_data(input logic [ADDR_WIDTH-1:0] a, output logic [DATA_WIDTH-1:0] d);
        @(posedge clk);
        addr <= a;
        read <= 1'b1;
        write <= 1'b0;
        wait(valid);
        d = rdata;
        @(posedge clk);
        read <= 1'b0;
    endtask
endinterface

// 인터페이스 사용
module axi_master(
    axi_if.master axi
);
    // 마스터 로직 구현...
endmodule

module axi_slave(
    axi_if.slave axi
);
    // 슬레이브 로직 구현...
endmodule

module top_level;
    logic clk = 0;
    logic rst_n;
    
    // 클럭 생성
    always #5 clk = ~clk;
    
    // 인터페이스 인스턴스화
    axi_if #(.DATA_WIDTH(64), .ADDR_WIDTH(32)) axi_bus(.clk(clk), .rst_n(rst_n));
    
    // 모듈 인스턴스화
    axi_master master(.axi(axi_bus));
    axi_slave  slave(.axi(axi_bus));
    
    initial begin
        rst_n = 0;
        #20 rst_n = 1;
        
        // 인터페이스 태스크 직접 사용
        axi_bus.write_data(32'h1000_0000, 64'hABCD_1234_5678_9ABC);
        
        // 데이터 읽기
        logic [63:0] read_val;
        axi_bus.read_data(32'h1000_0000, read_val);
        $display("Read data: %h", read_val);
    end
endmodule

20. 디자인 파티션과 바인딩 (Design Partition and Binding)

계층적 설계와 코드 재사용을 위한 바인딩 기능입니다.

// 바인드 가능한 검증 모듈 정의
module check_protocol(
    input logic clk,
    input logic reset,
    input logic req,
    input logic ack
);
    // 프로토콜 체킹 로직...
    property req_ack_p;
        @(posedge clk) disable iff (reset)
        req |-> ##[1:3] ack;
    endproperty
    
    assert property (req_ack_p)
    else $error("Protocol violation");
endmodule

// 설계 모듈
module my_design(
    input logic clk,
    input logic reset,
    input logic start,
    output logic done
);
    logic internal_req, internal_ack;
    
    // 설계 로직...
    
endmodule

// 검증 모듈 바인딩
bind my_design check_protocol checker_inst(
    .clk(clk),
    .reset(reset),
    .req(internal_req),
    .ack(internal_ack)
);

// 또는 특정 계층 경로에 바인딩
bind top.sub.my_design check_protocol checker_inst(...);

21. 시뮬레이션 제어 (Simulation Control)

시뮬레이션 환경을 제어하는 기능입니다.

module sim_control;
    initial begin
        // 시간 단위 및 정밀도 표시
        $timeformat(-9, 3, " ns", 10);
        
        // 값 출력
        $display("Starting simulation at %t", $time);
        
        // 시뮬레이션 제어
        #100 $display("Time: %t", $time);
        
        // 파일 열기
        int file_handle;
        file_handle = $fopen("output.log", "w");
        
        // 파일에 쓰기
        $fdisplay(file_handle, "Simulation log file");
        $fwrite(file_handle, "Time: %t, Value: %d\n", $time, 42);
        
        // 파일 닫기
        $fclose(file_handle);
        
        // 파일 읽기
        file_handle = $fopen("input.txt", "r");
        if (file_handle) begin
            string line;
            while ($fgets(line, file_handle))
                $display("Read: %s", line);
            $fclose(file_handle);
        end
        
        // 시뮬레이션 제어
        #1000;
        if (error_count > 0)
            $error("Simulation failed with %0d errors", error_count);
        else
            $display("Simulation passed");
            
        // 시뮬레이션 종료
        $finish;
    end
    
    int error_count = 0;
    
    // 파형 덤프 제어
    initial begin
        $dumpfile("wave.vcd");
        $dumpvars;  // 모든 변수 덤프
    end
endmodule

22. UVM 기초 개념 (Universal Verification Methodology Basics)

UVM은 표준화된 검증 방법론입니다.

// UVM 패키지 가져오기
import uvm_pkg::*;
`include "uvm_macros.svh"

// UVM 트랜잭션 클래스
class my_transaction extends uvm_sequence_item;
    // 트랜잭션 데이터 필드
    rand bit [7:0] addr;
    rand bit [31:0] data;
    rand bit rw;  // 0: 읽기, 1: 쓰기
    
    // UVM 매크로
    `uvm_object_utils_begin(my_transaction)
        `uvm_field_int(addr, UVM_ALL_ON)
        `uvm_field_int(data, UVM_ALL_ON)
        `uvm_field_int(rw, UVM_ALL_ON)
    `uvm_object_utils_end
    
    // 생성자
    function new(string name = "my_transaction");
        super.new(name);
    endfunction
    
    // 제약 조건
    constraint addr_c {
        addr inside {[0:255]};
    }
endclass

// UVM 시퀀스
class my_sequence extends uvm_sequence #(my_transaction);
    `uvm_object_utils(my_sequence)
    
    function new(string name = "my_sequence");
        super.new(name);
    endfunction
    
    task body();
        my_transaction tx;
        repeat(10) begin
            tx = my_transaction::type_id::create("tx");
            start_item(tx);
            if (!tx.randomize())
                `uvm_error("SEQ", "Randomization failed")
            finish_item(tx);
        end
    endtask
endclass

// UVM 시퀀서
class my_sequencer extends uvm_sequencer #(my_transaction);
    `uvm_component_utils(my_sequencer)
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
endclass

// UVM 드라이버
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
    
    task run_phase(uvm_phase phase);
        my_transaction tx;
        forever begin
            seq_item_port.get_next_item(tx);
            // 트랜잭션 처리 로직
            `uvm_info("DRV", $sformatf("Got transaction: addr=%0h, data=%0h, rw=%0b", 
                       tx.addr, tx.data, tx.rw), UVM_MEDIUM)
            // DUT 인터페이스에 트랜잭션 적용
            #10; // 시뮬레이션 시간 지연
            seq_item_port.item_done();
        end
    endtask
endclass

// UVM 에이전트
class my_agent extends uvm_agent;
    `uvm_component_utils(my_agent)
    
    my_sequencer sqr;
    my_driver drv;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        sqr = my_sequencer::type_id::create("sqr", this);
        drv = my_driver::type_id::create("drv", this);
    endfunction
    
    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        drv.seq_item_port.connect(sqr.seq_item_export);
    endfunction
endclass

// UVM 환경
class my_env extends uvm_env;
    `uvm_component_utils(my_env)
    
    my_agent agt;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        agt = my_agent::type_id::create("agt", this);
    endfunction
endclass

// UVM 테스트
class my_test extends uvm_test;
    `uvm_component_utils(my_test)
    
    my_env env;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = my_env::type_id::create("env", this);
    endfunction
    
    task run_phase(uvm_phase phase);
        my_sequence seq;
        
        phase.raise_objection(this);
        
        seq = my_sequence::type_id::create("seq");
        seq.start(env.agt.sqr);
        
        #100;
        phase.drop_objection(this);
    endtask
endclass

// 최상위 모듈
module top;
    initial begin
        run_test("my_test");
    end
endmodule

이것으로 SystemVerilog 기본 문법 가이드의 4부를 마치겠습니다. 이 가이드를 통해 SystemVerilog의 기본 구문부터 고급 기능까지 폭넓게 다루었습니다. 실제 설계와 검증 작업에서는 이러한 기능들을 상황에 맞게 조합하여 사용하게 됩니다.

SystemVerilog는 하드웨어 설계와 검증을 위한 강력한 도구이며, 이러한 기본 개념을 이해하는 것이 복잡한 디지털 시스템을 효과적으로 개발하는 데 큰 도움이 될 것입니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다