[카테고리:] 미분류

  • 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