Verilog 함수 설명: 구문, 예제 및 태스크와의 차이점

目次

1. Verilog 함수란? (기본 개념 및 역할)

Verilog HDL (Hardware Description Language)은 디지털 회로를 설계하고 시뮬레이션하는 데 사용되는 하드웨어 기술 언어입니다. 이 언어의 기능 중 함수는 특정 연산을 모듈화하고 재사용 가능하게 해주는 메커니즘입니다. Verilog 함수를 이해하면 코드 가독성과 유지 보수성이 향상될 뿐만 아니라 보다 효율적인 회로 설계가 가능합니다 이 글에서는 Verilog 함수의 기본 개념과 실제 설계에서 어떻게 활용되는지 설명합니다.

함수란?

Verilog 함수특정 계산이나 연산을 수행하고 단일 값을 반환하는 블록입니다. 함수를 사용하면 중복 코드를 줄이고 회로 기술 더 간단하게 만들 수 있습니다.

함수의 주요 특징

  • 하나 이상의 입력을 지정할 수 있음 (input만 허용)
  • 출력은 하나만 존재 (함수의 반환값)
  • 시간 지연(e.g., #10)은 허용되지 않음
  • 함수는 항상 조합 논리를 기술해야 함
  • 함수는 always 블록 밖에서 정의되며 즉시 평가됨(태스크와 다름)

Verilog 함수를 사용해야 할 경우

Verilog 함수는 주로 다음 상황에서 사용됩니다:

1. 조합 논 기술

함수는 입력에 따라 즉시 결과를 반환하므로 조합 논리에서 자주 사용됩니다. 예시: 덧셈, 뺄셈, 인코더, 디코더 및 기타 산술 연산.

2. 코드 재사용성 향상

자주 사용되는 로직을 함수로 요약하면 중복 코드를 없앨 수 있습니다. 예시: 복잡한 조건식을 함수로 만들어 모듈 내부 가독성을 높임.

3. 설계 오류 감소

계산이나 논리 연산을 하나의 함수에 집중시켜 두면 코드를 수정할 때 실수를 줄일 수 있습니다. 예시: CRC(순환 중복 검사) 계산이나 패리티 검사.

함수와 태스크의 차이점

Verilog에는 태스크(task) 라는 또 다른 구조가 있습니다. 함수와 태스크는 비슷하지만 중요한 차이점이 있습니다.
Item함수작업
출력하나만다중 허용
번역할 HTML 스니펫을 제공해 주세요. 텍스트를 한국어로 번역해 드리겠습니다.
Local Variables허용됨허용됨
지연 (#10)허용되지 않음허용
사용법은 always 내부허용허용되지 않음
Invocationfunction_name(arguments)task_name(arguments);

함수를 사용해야 할 경우

  • 즉시 계산 결과가 필요할 때
  • 지연이 포함되지 않은리일 때
  • 단일 반환값만 때

태스크를 사용해야 할 경우

  • 프로세스에 지연이 포함될 때(e.g., #10)
  • 여러 개의 출력이 필요할 때
  • 시뮬레이션/디버그 목적(e.g., 로그 출력)

요약

  • Verilog 함수입력을 받아 단일 값을 반환하는 함수입니다.
  • 조합 논리를 기술하는 데 적합하며 지연을 포함할 수 없습니다.
  • 중복 코드를 줄이고 가독성을 높이는 데 유용합니다.
  • 함수와 태스크는 차이가 있으므로 사용 목적에 맞게 선택해야 합니다.

2. Verilog 함수 작성 방법 [Beginner-Friendly Example]

앞 절에서 Verilog 함수의 기본 개념을 살펴보았습니다. 여기서는 실제 구문과 Verilog 함수를 실무에 적용하는 방법을 자세히 다룹니다.

함수의 기본 구문

Verilog 함수는 다음과 같은 일반 구문으로 작성합니다:
function [output_bit_width] function_name;
    input [input_bit_width] input1, input2, ...;
    begin
        function_name = expression;
    end
endfunction

핵심 포인트

  • function 키워드로 선언
  • 반환값은 함수와 동일한 이름의 변수에 할당
  • 입력은 input으로 선언(output이나 inout은 사용 불가)
  • 계산은 begin ... end 내부에서 수행
  • always 블록 밖에서 함수 정의

Ver 함수의 간단한 예시

다음 예시는 8비트 덧셈을 수행하는 함수를 보여줍니다:
module example;
    function [7:0] add_function;
        input [7:0] a, b;
        begin
            add_function = a + b;
        end
    endfunction

    reg [7:0] x, y, sum;

    initial begin
        x = 8'b00001100; // 12
        y = 8'b00000101; // 5
        sum = add_function(x, y);
        $display("Sum: %d", sum); // Sum: 17
    end
endmodule

설명

  • add_function은 두 개의 8비트 입력(ab)을 받아 그 합을 반환합니다.
  • 함수는 sum = add_function(x, y와 같이 호출되어 결과를 sum에 할당합니다. *initial블록은$display`를 사용하여 결과를 출력합니다.

함수에서 입력 및 출력 선언

입력 선언

Verilog 함수는 input 인자만 받을 수 있습니다.
function [7:0] my_function;
    input [7:0] in1, in2;
    begin
        my_function = in1 & in2; // AND operation
    end
endfunction
Note: 함수에서는 output을 선언할 수 없습니다. 반환값은 항상 함수와 같은 이름을 가진 변수입니다.

조건문을 포함한 함수

함수 내부에서도 if 또는 case 문을 사용할 수 있습니다.
function [3:0] max_function;
    input [3:0] a, b;
    begin
        if (a > b)
            max_function = a;
        else
            max_function = b;
    end
endfunction
이 함수는 ab 중 더 큰 값을 반환합니다.

요약

  • Verilog 함수는 function 키워드로 정의되며 단일 값을 반환합니다.
  • 입력자만 허용됩니다 (output 없음).
  • 반환값은 함수와 같은 이름을 가진 변수에 할당됩니다.
  • ifcase 문을 조건 로직에 사용할 수 있습니다.

3. Verilog 함수 사용 방법 [With Practical Code Examples]

이전 섹션에서는 기본 문법과 Verilog 함수 작성 방법을 배웠습니다. 여기서는 실전 설계에 함수를 적용하는 방법을 실제 예시와 함께 설명합니다.

함수 호출 방법

Verilog 함수는 일반 변수 할당처럼 function_name(arg1, arg2, ...) 형식으로 호출됩니다. 다음 예시는 8비트 XOR 함수를 정의하고 모듈 내부에서 사용하는 예시입니다:
module function_example;
    function [7:0] xor_function;
        input [7:0] a, b;
        begin
            xor_function = a ^ b;
        end
    endfunction

    reg [7:0] x, y, result;

    initial begin
        x = 8'b11001100;
        y = 8'b10101010;
        result = xor_function(x, y); // calling the function
        $display("XOR Result: %b", result); // XOR Result: 01100110
    end
endmodule

핵심 포인트

  • 함수는 variable = function(arguments); 형태로 호출됩니다.
  • always 또는 initial 블록 내부에서 사용할 수 있습니다.
  • 함수는 조합 논리로 동작합니다.

조합 논리에서 함수 사용

Verilog 함수는 항상 즉시 평가되기 때문에 조합 논리 구축에 유용합니다. 다음 예시는 함수를 이용해 구현한 2-to-4 디코더줍니다:
module decoder_example;
    function [3:0] decoder;
        input [1:0] sel;
        begin
            case (sel)
                2'b00: decoder = 4'b0001;
                2'b01: decoder = 4'b0010;
                2'b10: decoder = 4'b0100;
                2'b11: decoder = 4'b1000;
                default: decoder = 4'b0000;
            endcase
        end
    endfunction

    reg [1:0] select;
    wire [3:0] decoded_output;

    assign decoded_output = decoder(select); // using the function

    initial begin
        select = 2'b01;
        #10; // add delay to observe simulation changes
        $display("Decoded Output: %b", decoded_output); // Decoded Output: 0010
    end
endmodule

설명

  • decoder 함수는 2비트 입력을 4비트 디코더 출력으로 변환합니다
  • 입력에 따라 출력을 결정하기 위해 case 문을 사용합니다
  • assign 를 사용해 함수 출력을 decoded_output에 매핑합니다 → 이 함수는 조합 논리의 일부로 동작합니다

Functions vs. always Blocks [Comparison Table]

Verilog 함수와 always 블록은 모두 로직을 기술하는 데 사용되지만, 목적과 제한 사항이 다.
Item함수항상 블록
정의 위치외부 always 블록always
입력inputregwire
출력하나의 값만여러 값을 업데이트할 수 있습니다
지연 (#10)허용되지 않음허용
상태 유지허용되지 않음허용
Main Usage조합 논리순차 논리 또는 이벤트 기반 처리

핵심 가이드라인

  • 한 논리 연산(조합 논리)을 단순화하기 위해 함수를 사용하세요
  • 상태를 유지하는 회로(예: 플립플롭)에는 always 블록을 사용하세요
  • 지연(#10 등)이 필요하면 함수 대신 always 사용하세요

요약: Verilog 함수 사용 방법

function_name(arguments) 로 함수를 호출합니다 ✅ 함수는 조합 논리에 가장 적합하며 always 블록과 다릅니다 ✅ 유연한 로직을 기술하기 위해 case 또는 if 문을 사용합니다 ✅ 디코더, 산술 연산 등 다양한 용도에 유용합니다

4. Verilog 함수의 실용적인 적용 (디코더 및 ALU 설계)

지금까지 Verilog 함수의 기본 문법과 사용법을 배웠습니다. 이번 섹션에서는 디코더와 ALU(산술 논리 연산 장치)를 예시로 실제 디지털 회로 설계에 함수를 적용하는 방법을 살펴보겠습니다.

디코더 구현 (2-to-4 디코더) 함수

디코더는 소수의 입력 비트를 다수의 출력 비트로 변환하는 회로입니다. 예를 들어, 2-to-4 디코더는 2비트 입력을 4비트 출력으로 변환합니다. 함수를 사용해 이를 구현해 보겠습니다:
module decoder_example;
    function [3:0] decoder;
        input [1:0] sel;
        begin
            case (sel)
                2'b00: decoder = 4'b0001;
                2'b01: decoder = 4'b0010;
                2'b10: decoder = 4'b0100;
                2'b11: decoder = 4'b1000;
                default: decoder = 4'b0000;
            endcase
        end
    endfunction

    reg [1:0] select;
    wire [3:0] decoded_output;

    assign decoded_output = decoder(select); // using the function

    initial begin
        select = 2'b00; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b01; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b10; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b11; #10;
        $display("Decoded Output: %b", decoded_output);
    end
endmodule

ALU 구현 (덧셈, 뺄셈, AND OR) 함수

ALU(Arithmetic Logic Unit)는 CPU의 핵심 회로로, 덧셈, 뺄셈, AND, OR 등 산술 및 논리 연산을 수행합니다. 여기서는 Verilog 함수를 이용해 간단한 8비트 ALU를 설계합니다:
module alu_example;
    function [7:0] alu;
        input [7:0] a, b;
        input [1:0] op; // 2-bit control signal
        begin
            case (op)
                2'b00: alu = a + b; // Addition
                2'b01: alu = a - b; // Subtraction
                2'b10: alu = a & b; // AND
                2'b11: alu = a | b; // OR
                default: alu = 8'b00000000;
            endcase
        end
    endfunction

    reg [7:0] x, y;
    reg [1:0] opcode;
    wire [7:0] result;

    assign result = alu(x, y, opcode); // using the function

    initial begin
        x = 8'b00001100; // 12
        y = 8'b00000101; // 5

        opcode = 2'b00; #10;
        $display("Addition Result: %d", result); // 12 + 5 = 17

        opcode = 2'b01; #10;
        $display("Subtraction Result: %d", result); // 12 - 5 = 7

        opcode = 2'b10; #10;
        $display("AND Result: %b", result); // AND operation

        opcode = 2'b11; #10;
        $display("OR Result: %b", result); // OR operation
    end
endmodule

요약

함수는 디코더와 ALU와 같은 조합 논리 회로에서 효과적으로 사용할 수 있습니다case 문을 사용하면 유연한 동작 설명이 가능합니다함수는 가독성을 높이고 설계를 보다 재사용 가능하게 합니다함수는 조합 논리에는 적합하지만 순차 회로에는 적합하지 않습니다(지연을 포함할 수 없기 때문)

5. Verilog 함수 사용 시 중요한 고려 사항

Verilog 함수는 코드 가독성과 재사용성을 높여 주는 강력한 도구이지만, 몇 가지 제한 사항이 있습니다. 이 섹션에서는 함수를 사용할 때 알아두어야 할 핵심 포인트를 설명합니다.

재귀 호출은 허용되지 않음

Verilog 함수에서는 재귀 호출이 금지됩니다. 즉, 함수는 자신의 본문 안에서 스스로를 호출할 수 없습니다.

❌ NG 예시: 재귀 함수

function [3:0] factorial;
    input [3:0] n;
    begin
        if (n == 0)
            factorial = 1;
        else
            factorial = n * factorial(n - 1); // ❌ Recursive call not allowed
    end
endfunction
이 코드는 시뮬레이션 오류를 발생시킵니다.

✅ 해결책: 대신 루프 사용

재귀가 필요하다면 always 블록이나 태스크 내부의 루프를 사용하세요.
task factorial_task;
    input [3:0] n;
    output [15:0] result;
    integer i;
    begin
        result = 1;
        for (i = 1; i <= n; i = i + 1)
            result = result * i;
    end
endtask
프를 사용하면 재귀를 피할 수 있습니다.

시간 지연(#10)은 함수 내부에서 사용할 수 없음

Verilog 함수는 즉시 평가되며(조합 논리처럼 동작), #10과 같은 시간 지연을 포함할 수 없습니다.

❌ NG 예시: 함수 내부의 지연

function [7:0] delay_function;
    input [7:0] in;
    begin
        #10; // ❌ Delay not allowed inside functions
        delay_function = in + 1;
    end
endfunction
이 코드는 컴파일 오류를으킵니다.

✅ 해결책: 대신 always 블록 사용

지연이 필요하다면 함수 대신 always 블록이나 태스크를 사용하세요.
task delay_task;
    input [7:0] in;
    output [7:0] out;
    begin
        #10;
        out = in + 1;
    end
endtask
요약하면, 지연이 포함된 연산은 태스크를 사용합니다.

함수와 태스크 선택

Verilog에는 함수태스크가 모두 존재합니다. 겉보기는 비슷하지만 사용 목적이 다르므로 상황에 맞게 선택해야 합니다.
Item함수작업
출력하나만다중 허용
입력inputinputoutput
Local Variables허용허용
지연 (#10)허용되지 않음허용
사용법은 always 내부허용허용되지 않음
Invocationfunction_name(arguments)task_name(arguments);

함수 사용 시기

✅ 즉시 계산 결과가 필요할 때(예: 덧셈, 뺄셈, 논리 연산) ✅ 지연이 없는 조합 논리를 기술할 때 ✅ 반환값이 하나만 필요할 때

태스크 사용기

✅ 지연(#10 등)이 필요할 때 ✅ 다중 출력이 필요 때 ✅ 시레이션/디버그 작업(모니터링, 출력 등)일 때

함수는 always 블록 내부에 정의할 수 없음

Verilog 함수는 always 블록 내부에 정의될 수 없습니다. 함수는 always 블록 밖에서 정의하고, 필요할 때 호출해야 합니다.

❌ NG 예시: always 블록 내부에 함수 정의

always @(a or b) begin
    function [7:0] my_function; // ❌ Not allowed inside always
        input [7:0] x, y;
        begin
            my_function = x + y;
        end
    endfunction
end
이 코드는 컴파일 오류를 발생시킵니다.

✅ 올바른 예시

함수를 always 블록 밖에 정의하고 내부에서 호출하세요:
function [7:0] add_function;
    input [7:0] x, y;
    begin
        add_function = x + y;
    end
endfunction

always @(a or b) begin
    result = add_function(a, b); // ✅ call the function
end
Verilog 함수에는 여러 제한이 있습니다재귀 호출 금지 (대신 루프나 태스크 사용) ✅ 지연(#10) 사용 금지 (대신 always나 태스크 사용) ✅ always 블록 내부에 정의할 수 없음 (외부에 정의해야 함) ✅ 반환값은 하나만 (여러 출력이 필요하면 태스크 사용) ✅ 상황에 맞게 함수와 태스크를 적절히 사용하세요

6. [FAQ] Verilog 함수에 대한 자주 묻는 질문

지금까지 우리는 Verilog 함수의 기본, 고급 사용법 및 중요한 고려사항을 다루었습니다. 이 섹션에서는 자주 묻는 질문과 답변을 요약합니다.

함수와 태스크의 차이점은 무엇인가요?

Q. Verilog 함수와 태스크의 차이점은 무엇이며, 어느 것을 사용해야 하나요?

. 함수는 “즉시 단일 값을 반환”해야 할 때 사용하고, 태스크는 “여러 출력이나 지연이 포함된 연산”이 필요할 때 사용합니다.**

Item함수작업
죄송합니다만, 번역할 HTML 스니펫이 제공되지 않았습니다. 번역이 필요한 HTML 코드를 알려주시면 바로 한국어로 번역해 드리겠습니다.하나만다중 허용
죄송합니다만, 번역할 HTML 코드를 제공해 주시겠어요? 코드를 받으면 바로 한국어로 번역해 드리겠습니다.inputinputoutput
Local Variables허용됨허용됨
지연 (#10)허용되지 않음허용
always허용됨허용되지 않음
Invocationfunction_name(arguments)task_name(arguments);

함수 사용 시기

✅ 즉시 계산 결과가 필요할 때 (예: 덧셈, 뺄셈, 논리 연산) ✅ 지연 없는 조합 논리를 기술할 때 ✅ 반환값이 하나만 필요할 때

태스크 사용 시기

✅ 지연이 필요할 때 (예: #10) ✅ 여러 출력이 필요할 때 ✅ 시뮬레이션용 디버그/모니터링 코드를 작성할 때

함수 내부에서 reg를 사용할 수 있나요?

Q. 함수 안에 reg 변수를 선언할 수 있나요?

A. 함수 안에서는 reg를 사용할 수 없으며, 대신 integer를 사용할 수 있습니다.

Verilog 함수에서는 reg 타입 변수를 선언할 수 없으며, 계산을 위해 integer를 사용할 수 있습니다.

✅ 올바른 예시 (integer 사용)

function [7:0] multiply;
    input [3:0] a, b;
    integer temp;
    begin
        temp = a * b;
        multiply = temp;
    end
endfunction

언제 함수를 사용해야 하나요?

Q. 어떤 상황에서 함수를 사용하는 것이 적절한가요?

A. 함수는 “단순 산술 연산” 및 “조합 논리”에 가장 적합합니다.

함수가 유용한 예시 산술 연산 (덧셈, 뺄셈, 논리) 디코더 및 인코더 비교 (최대/최소값 찾기) 오류 검사 (예: 패리티 검사) 그러나 함수는 플립플롭이 포함된 순차 회로에는 적합하지 않습니다.

한 함수가 다른 함수를 호출할 수 있나요?

Q. Verilog 함수가 내부에서 다른 함수를 호출할 수 있나요?

A. 예, 함수는 다른 함수를 호출할 수 있지만 의존성에 주의해야 합니다.

function [7:0] add;
    input [7:0] a, b;
    begin
        add = a + b;
    end
endfunction

function [7:0] double_add;
    input [7:0] x, y;
    begin
        double_add = add(x, y) * 2; // calling another function
    end
endfunction

함수와 always 블록 중 어떻게 선택해야 하나요?

Q. 함수와 always 블록 중 어느 것을 사용할지 어떻게 결정하나요?

A. 함수는 “조합 논리”에 사용하고, always 블록은 “순차 논리”에 사용합니다.

Item함수항상 블록
지연 (#10)허용되지 않음허용
상태 유지허용되지 않음허용됨
주요 사용조합 논리 (즉시 계산)순차 논리 (플립플롭, 카운터)
예를 들어, 덧셈을 수행할 때:

✅ 함수 (조합 논리)

function [7:0] add;
    input [7:0] a, b;
    begin
        add = a + b;
    end
endfunction

✅ always 블록 (순차 논리)

always @(posedge clk) begin
    sum <= a + b; // works as a flip-flop
end

요약

함수는 단순 연산 및 조합 논리에 가장 적합함수와 태스크의 차이를 이해하고 적절히 사용always록은 순차 논리에, 함수는 조합 논리에 사용함수는 지연(#10)이나 배열을 포함할 수 없으므로 태스크나 모듈을 사용