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

13. 문자열 처리 (String Processing)

SystemVerilog는 강력한 문자열 처리 기능을 제공합니다.

module string_example;
    string str1 = "Hello";
    string str2 = "World";
    string result;
    
    initial begin
        // 문자열 연결
        result = {str1, " ", str2};
        $display("Combined: %s", result);  // "Hello World" 출력
        
        // 문자열 비교
        if (str1 == "Hello")
            $display("Strings match");
            
        // 문자열 길이
        $display("Length: %d", str1.len());  // 5 출력
        
        // 문자열 조작
        result = str1.toupper();        // "HELLO"
        result = str1.substr(1, 3);     // "ell"
        result = str1.putc(2, "X");     // "HeXlo"
        
        // 문자열에서 문자 가져오기
        byte c = str1.getc(0);          // 'H'의 ASCII 코드 
        
        // 정수를 문자열로 변환
        int value = 12345;
        result.itoa(value);              // "12345"
        
        // 16진수 문자열로 변환
        result = $sformatf("%h", value); // "3039"
    end
endmodule

14. 프로그램 블록 (Program Block)

프로그램 블록은 테스트 코드를 설계 코드와 분리하는 데 사용됩니다.

// 프로그램 블록 정의
program automatic test;
    // 테스트 변수들
    logic [7:0] test_data;
    int error_count = 0;
    
    // 테스트 코드는 일반적으로 initial 블록에 작성
    initial begin
        // 테스트 시퀀스
        repeat (10) begin
            test_data = $random;
            check_data(test_data);
            #10;
        end
        
        $display("Test completed with %0d errors", error_count);
    end
    
    // 테스트 태스크
    task check_data(logic [7:0] data);
        if (data == 0)
            error_count++;
    endtask
endprogram

// 모듈과 프로그램 연결
module top;
    // 클럭 생성
    logic clk = 0;
    always #5 clk = ~clk;
    
    // DUT 인스턴스화
    counter dut (
        .clk(clk),
        .reset(1'b0),
        .count()
    );
    
    // 테스트 프로그램 인스턴스화
    test t1();
endmodule

15. 태스크와 함수 (Tasks and Functions)

태스크와 함수는 코드 재사용을 위한 중요한 요소입니다.

module task_function_example;
    logic [7:0] data, result;
    
    // 함수 정의 - 즉시 값 반환, 딜레이 불가
    function logic [7:0] add_one(input logic [7:0] val);
        return val + 1;
    endfunction
    
    // 자동 함수 - 함수 호출 간 로컬 변수가 유지되지 않음
    function automatic int factorial(input int n);
        if (n <= 1)
            return 1;
        else
            return n * factorial(n-1);  // 재귀 호출
    endfunction
    
    // 태스크 정의 - 시간 지연 가능, 반환값 없음
    task automatic process_data(input logic [7:0] in_data, output logic [7:0] out_data);
        #10; // 시간 지연 (10 시간 단위)
        out_data = in_data * 2;
    endtask
    
    // 기본 인수를 가진 태스크
    task display_value(input logic [7:0] val = 8'hFF);
        $display("Value: %h", val);
    endtask
    
    initial begin
        data = 8'h10;
        
        // 함수 호출
        result = add_one(data);
        $display("Result: %h", result);  // 0x11 출력
        
        // 재귀 함수 호출
        $display("5! = %0d", factorial(5));  // 120 출력
        
        // 태스크 호출
        process_data(data, result);
        $display("After task: %h", result);  // 0x20 출력
        
        // 기본 인수를 사용한 태스크 호출
        display_value();       // 기본값 0xFF 사용
        display_value(8'h42);  // 명시적 값 0x42 사용
    end
endmodule

16. 어서션 (Assertions)

어서션은 설계의 동작을 검증하는 강력한 도구입니다.

module assertion_example(
    input logic clk,
    input logic reset,
    input logic req,
    input logic ack,
    input logic [7:0] data
);
    // 즉시 어서션 (Immediate Assertion)
    always_comb begin
        // 데이터가 특정 범위 내에 있는지 확인
        assert(data inside {[0:100]})
        else $error("Data out of range: %d", data);
    end
    
    // 병행 어서션 (Concurrent Assertion)
    // req 신호 후 1~3 클럭 내에 ack 신호가 와야 함
    property req_ack_protocol;
        @(posedge clk) disable iff (reset)
        req |-> ##[1:3] ack;
    endproperty
    
    // 어서션 인스턴스화
    assert property (req_ack_protocol)
    else $error("Protocol violation: ack not received within 3 cycles after req");
    
    // 병행 커버 포인트 (Concurrent Cover)
    cover property (@(posedge clk) req ##1 ack)
    $info("Req-Ack sequence covered");
    
    // 시퀀스 정의 (Sequence)
    sequence data_seq;
        data == 8'h55 ##1 data == 8'hAA;
    endsequence
    
    // 시퀀스 기반 어서션
    assert property (@(posedge clk) data_seq)
    else $error("Expected data sequence not detected");
endmodule

17. 랜덤화 (Randomization)

랜덤화는 효과적인 검증을 위한 핵심 기능입니다.

class RandomPacket;
    // 랜덤화할 변수
    rand bit [7:0] addr;
    rand bit [31:0] data;
    rand bit [1:0] prio;
    
    // 제약 조건
    constraint valid_addr {
        addr inside {[10:20], [30:40]};  // 주소는 10-20 또는 30-40 범위 내
    }
    
    constraint data_c {
        data < 100;            // 데이터는 100보다 작음
        data % 2 == 0;         // 데이터는 짝수
    }
    
    // 우선순위에 따른 제약 조건
    constraint prio_c {
        (prio == 0) -> data < 30;    // 우선순위 0이면 데이터 < 30
        (prio == 1) -> data < 60;    // 우선순위 1이면 데이터 < 60
        (prio == 2) -> data < 90;    // 우선순위 2이면 데이터 < 90
    }
    
    // 배타적 제약 조건(DIST)
    rand bit [1:0] mode;
    constraint mode_dist {
        mode dist {0 := 40, 1 := 40, 2 := 20};  // 0,1은 각각 40%, 2는 20% 확률
    }
    
    function void post_randomize();
        $display("Randomized: addr=%0d, data=%0d, prio=%0d, mode=%0d", 
                 addr, data, prio, mode);
    endfunction
endclass

module rand_example;
    initial begin
        RandomPacket pkt = new();
        
        // 랜덤화 실행
        repeat (5) begin
            if (pkt.randomize())  // 랜덤화 성공하면 true 반환
                $display("Randomization succeeded");
            else
                $display("Randomization failed");
        end
        
        // 특정 필드를 고정하고 랜덤화
        if (pkt.randomize() with {addr == 15; prio == 2;})
            $display("Constrained randomization succeeded");
            
        // 인라인 제약 조건
        if (pkt.randomize() with {data > 50; data < 80;})
            $display("Inline constraint succeeded");
    end
endmodule

18. 커버리지 (Coverage)

커버리지는 검증의 완성도를 측정하는 데 사용됩니다.

module coverage_example(
    input logic clk,
    input logic reset,
    input logic [1:0] mode,
    input logic [7:0] data
);
    // 함수적 커버리지
    covergroup cg_modes @(posedge clk);
        option.per_instance = 1;  // 인스턴스별 통계
        
        // 커버 포인트 - mode 신호 커버
        cp_mode: coverpoint mode {
            bins mode_0 = {0};
            bins mode_1 = {1};
            bins mode_2 = {2};
            bins mode_3 = {3};
            bins mode_trans[] = (0,1,2,3 => 0,1,2,3);  // 모든 전환 커버
        }
        
        // 데이터 범위 커버
        cp_data: coverpoint data {
            bins low = {[0:63]};
            bins mid = {[64:127]};
            bins high = {[128:255]};
        }
        
        // 크로스 커버리지 - mode와 data의 조합
        cross_mode_data: cross cp_mode, cp_data;
    endcovergroup
    
    // 커버그룹 인스턴스화
    cg_modes cg = new();
    
    // 명시적 커버 그룹 샘플링도 가능
    always @(posedge clk) begin
        if (!reset)
            cg.sample();  // 명시적 샘플링
    end
    
    // 코드 커버리지는 컴파일러 지시문으로 제어됨
    // 라인 커버리지, 조건 커버리지, FSM 커버리지, 토글 커버리지 등
endmodule

코멘트

답글 남기기

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