2-3. Verilog의 모듈과 인스턴스

1. 모듈과 인스턴스의 개념: 디지털 시스템 설계의 핵심

디지털 시스템 설계를 건축에 비유해 보겠습니다. 건축가는 복잡한 빌딩을 설계할 때, 벽돌, 창문, 문과 같은 기본적인 구성 요소들을 정의하고, 이를 조합하여 방, 복도, 사무실과 같은 더 큰 단위인 모듈을 만듭니다. 최종적으로, 이러한 모듈들을 조합하여 전체 빌딩을 완성합니다.

Verilog에서 모듈은 이와 같은 역할을 합니다. 모듈은 디지털 회로의 기본적인 구성 블록이며, 기능과 구조를 캡슐화합니다. 모듈을 정의함으로써, 설계자는 복잡한 회로를 작은 단위로 분해하고, 재사용 가능한 부품을 만들 수 있습니다. 인스턴스는 이러한 모듈의 구체적인 실체(instance)를 생성하는 과정입니다. 모듈을 청사진으로, 인스턴스를 그 청사진을 기반으로 만들어진 건물로 비유할 수 있습니다. 동일한 모듈을 여러 번 인스턴스화하여, 여러 개의 동일한 기능을 수행하는 회로를 설계할 수 있습니다.

2. 모듈 정의 (Module Definition)

Verilog에서 모듈은 module 키워드를 사용하여 정의됩니다. 모듈 정의는 다음과 같은 요소를 포함합니다.

  1. 모듈 이름 (Module Name): 모듈을 식별하는 고유한 이름입니다.
  2. 포트 목록 (Port List): 모듈과 외부 회로 간의 연결을 정의하는 입출력 포트의 목록입니다. 포트는 input, output, inout의 세 가지 타입으로 선언될 수 있습니다.
  3. 포트 선언 (Port Declarations): 포트의 데이터 타입과 너비를 지정합니다.
  4. 로직 (Logic): 모듈의 기능을 정의하는 Verilog 코드 (예: assign 문, always 블록 등)
module and_gate (
    input a,
    input b,
    output y
);

    assign y = a & b; // AND 연산 수행

endmodule

위 예제는 두 개의 입력 ab를 받아서 AND 연산을 수행한 결과를 출력하는 간단한 and_gate 모듈을 정의합니다.

and_gate 코드 예시 아래

3. 포트 연결 (Port Connection)

모듈을 사용하기 위해서는 외부 회로(상위 모듈)에서 해당 모듈의 포트와 연결해야 합니다. 포트 연결은 두 가지 방식으로 수행할 수 있습니다.

1) 이름 기반 연결 (Named Port Connection)

이 방식은 포트 이름을 명시적으로 사용하여 연결하는 방법입니다. 포트의 순서에 관계없이, 연결되는 포트의 이름을 지정하기 때문에, 가독성이 높고 오류를 방지하는 데 유용합니다.

module top_module;
    wire input_a, input_b, output_y;

    and_gate uut (
        .a(input_a),
        .b(input_b),
        .y(output_y)
    );

    // ... 나머지 코드 ...
endmodule

uutand_gate 모듈의 인스턴스 이름입니다. .a(input_a)and_gate 모듈의 포트 atop_moduleinput_a 와이어에 연결함을 의미합니다.

2) 위치 기반 연결 (Positional Port Connection)

이 방식은 포트의 순서에 따라 연결하는 방법입니다. 모듈 정의에서 선언된 포트의 순서대로 연결해야 합니다. 간결하지만, 모듈 정의가 변경되면 연결 순서가 헷갈려 오류를 발생시킬 수 있습니다.

module top_module;
    wire input_a, input_b, output_y;

    and_gate uut (
        input_a,
        input_b,
        output_y
    );

    // ... 나머지 코드 ...
endmodule

위 예제는 위치 기반 연결을 사용하여 and_gate 모듈의 포트를 연결합니다. input_aa에, input_bb에, output_yy에 연결됩니다.

4. 모듈 인스턴스화 (Module Instantiation)

모듈 인스턴스화는 정의된 모듈의 실체(instance)를 생성하는 과정입니다. 인스턴스화 구문은 다음과 같습니다.

module_name instance_name (
    .port_name(connected_port),
    ...
);
  • module_name: 인스턴스화할 모듈의 이름
  • instance_name: 인스턴스의 고유한 이름 (모듈 내에서)
  • .port_name(connected_port): 포트 연결 (이름 기반 연결)

앞서 정의한 and_gate 모듈을 인스턴스화하는 예제를 살펴보겠습니다.

module top_module;
    wire input_a, input_b, output_y;

    and_gate uut ( // uut: instance name
        .a(input_a),
        .b(input_b),
        .y(output_y)
    );

    assign input_a = 1'b1;
    assign input_b = 1'b0;

    initial begin
        $display("Output: %b", output_y); // 출력: 0
    end
endmodule

위 예제에서 top_moduleand_gate 모듈의 인스턴스 uut를 생성하고, input_ainput_b를 각각 10으로 설정합니다. 그 결과, output_y0이 됩니다.

5. 계층적 설계 (Hierarchical Design)

모듈과 인스턴스를 활용하면 계층적인 설계를 구현할 수 있습니다. 즉, 복잡한 시스템을 여러 개의 모듈로 나누고, 각 모듈을 다시 하위 모듈로 구성하는 방식으로 설계할 수 있습니다. 이는 설계의 복잡성을 관리하고, 코드의 재사용성을 높이며, 디버깅을 용이하게 합니다.

예를 들어, 4-비트 가산기를 설계한다고 가정해 봅시다. 4-비트 가산기는 여러 개의 1-비트 전가산기(full adder)를 사용하여 구현할 수 있습니다.

module full_adder (
    input a, b, cin,
    output sum, cout
);

    assign sum = a ^ b ^ cin;
    assign cout = (a & b) | (a & cin) | (b & cin);

endmodule
module ripple_carry_adder_4bit (
    input [3:0] a, b,
    input cin,
    output [3:0] sum,
    output cout
);

    wire [3:0] carry;

    full_adder fa0 (
        .a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(carry[0])
    );
    full_adder fa1 (
        .a(a[1]), .b(b[1]), .cin(carry[0]), .sum(sum[1]), .cout(carry[1])
    );
    full_adder fa2 (
        .a(a[2]), .b(b[2]), .cin(carry[1]), .sum(sum[2]), .cout(carry[2])
    );
    full_adder fa3 (
        .a(a[3]), .b(b[3]), .cin(carry[2]), .sum(sum[3]), .cout(cout)
    );

endmodule

위의 예제에서 full_adder 모듈은 1-비트 전가산기를, ripple_carry_adder_4bit 모듈은 4개의 full_adder 모듈을 사용하여 4-비트 가산기를 구현합니다. ripple_carry_adder_4bit 모듈은 full_adder 모듈의 인스턴스를 생성하고, 연결함으로써 계층적인 설계를 보여줍니다. 이는 복잡한 시스템을 작은 단위로 분해하고, 각 단위를 독립적으로 설계하고 테스트할 수 있도록 하여, 설계 과정을 간소화하고 오류 발생 가능성을 줄입니다.

ripple_carry_adder_4bit 코드 예시 아래

6. 주의사항 및 트러블 슈팅

1) 포트 연결 오류

포트 연결 시 흔히 발생하는 오류는 다음과 같습니다.

  • 포트 이름 오타: 포트 이름을 잘못 입력하면 연결이 이루어지지 않습니다. 이름 기반 연결을 사용하면 오타를 쉽게 발견할 수 있습니다.
  • 포트 순서 오류: 위치 기반 연결을 사용할 경우, 포트의 순서를 잘못 지정하면 의도하지 않은 연결이 발생합니다.
  • 데이터 타입 불일치: 연결되는 포트의 데이터 타입이 일치하지 않으면 컴파일 오류가 발생하거나, 예상치 못한 동작이 발생할 수 있습니다.

2) 모듈 인스턴스 이름 중복

동일한 모듈 내에서 인스턴스 이름이 중복되면 컴파일 오류가 발생합니다. 각 인스턴스는 고유한 이름을 가져야 합니다.

3) 계층적 설계의 복잡성

계층적 설계는 회로를 더 쉽게 관리할 수 있도록 하지만, 너무 깊은 계층 구조는 디버깅을 어렵게 만들 수 있습니다. 적절한 수준의 계층 구조를 유지하고, 각 모듈의 기능을 명확하게 정의하는 것이 중요합니다.

7. 결론

Verilog의 모듈과 인스턴스는 디지털 시스템 설계의 핵심적인 개념입니다. 모듈을 사용하여 회로를 구조화하고, 인스턴스를 통해 모듈의 여러 실체를 생성하며, 계층적 설계를 통해 복잡한 시스템을 효율적으로 설계할 수 있습니다. 포트 연결 방식, 인스턴스 이름, 계층 구조 등에 주의하여 설계하고, 오류를 방지하는 것이 중요합니다. 이 개념들을 잘 이해하고 활용하면, 보다 효율적이고 유지보수가 용이한 디지털 회로를 설계할 수 있습니다.

비슷한 글 추천

Comments (0)

No comments yet. Be the first to comment!