5-4. 실습: 가산기 설계 (게이트 레벨, 데이터플로우, 동작 레벨)
1. 가산기의 중요성 및 모델링 개요
가산기는 디지털 시스템의 기본적인 연산 블록 중 하나로, 두 개 이상의 숫자를 더하는 기능을 수행합니다. CPU, GPU, DSP 등 거의 모든 디지털 장치에서 산술 연산을 담당하며, 더 나아가 주소 계산, 메모리 접근, 신호 처리 등 다양한 분야에서 핵심적인 역할을 합니다. 이러한 중요성 때문에 가산기는 회로 설계의 기본이며, 설계 시 성능(속도, 전력 소비)과 면적을 최적화하는 것이 중요합니다.
가산기를 설계하는 과정은 디지털 회로 설계의 다양한 모델링 기법을 이해하고 비교하는 좋은 실습 예시가 됩니다. Verilog와 같은 하드웨어 기술 언어(HDL)를 사용하여 가산기를 설계할 때, 게이트 레벨, 데이터플로우 레벨, 동작 레벨의 세 가지 주요 모델링 스타일을 활용할 수 있습니다. 각 모델링 스타일은 회로를 표현하는 방식, 추상화 수준, 그리고 설계의 유연성에 차이를 보입니다. 본 실습에서는 이러한 세 가지 모델링 방식을 사용하여 가산기를 설계하고, 각 방식의 특징을 비교 분석해 보겠습니다.
2. 가산기의 종류
가산기는 일반적으로 반가산기(Half Adder), 전가산기(Full Adder), 그리고 병렬 가산기(Parallel Adder)로 분류됩니다.
- 반가산기: 두 개의 1비트 입력 (
A,B)을 더하여 합(Sum)과 자리올림(Carry)을 출력합니다. - 전가산기: 두 개의 1비트 입력 (
A,B)과 이전 단계의 자리올림 입력 (Cin)을 더하여 합(Sum)과 자리올림 (Cout)을 출력합니다. - 병렬 가산기: 여러 개의 전가산기를 연결하여 여러 비트의 숫자를 더합니다. 가장 일반적인 형태는
리플 캐리 가산기(Ripple Carry Adder)입니다.
이번 실습에서는 1비트 전가산기를 다양한 모델링 기법으로 설계하고, 이를 기반으로 4비트 병렬 가산기를 구성하는 과정을 살펴보겠습니다.
3. 게이트 레벨 모델링
게이트 레벨 모델링은 회로를 기본 논리 게이트(AND, OR, NOT, XOR 등)의 연결로 표현하는 방식입니다. 이 방식은 회로의 물리적인 구조와 가장 가깝게 연결되어 있어, 회로의 동작을 세밀하게 제어하고 이해하는 데 유용합니다. 하지만, 회로가 복잡해질수록 설계 및 유지보수가 어려워진다는 단점이 있습니다.
1) 1비트 전가산기 설계
1비트 전가산기는 두 개의 입력 비트 A와 B, 그리고 이전 자리올림 비트 Cin을 더하여 합 S와 다음 자리올림 비트 Cout을 출력합니다. 진리표는 다음과 같습니다.
| A | B | Cin | S | Cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
위 진리표를 바탕으로, S와 Cout의 논리식을 도출할 수 있습니다.
S = A XOR B XOR CinCout = (A AND B) OR (Cin AND (A XOR B))
이 논리식을 바탕으로 Verilog 코드를 작성하면 다음과 같습니다.
module full_adder_gate (
input A, B, Cin,
output S, Cout
);
wire xor_ab, and_ab, and_cin_xor_ab;
xor #(1) xor1 (xor_ab, A, B);
xor #(1) xor2 (S, xor_ab, Cin);
and #(1) and1 (and_ab, A, B);
and #(1) and2 (and_cin_xor_ab, Cin, xor_ab);
or #(1) or1 (Cout, and_ab, and_cin_xor_ab);
endmodule
위 코드에서 xor, and, or는 Verilog에서 제공하는 기본 게이트의 인스턴스입니다. #을 사용하여 각 게이트의 딜레이를 지정할 수 있습니다. 각 게이트의 연결을 명시적으로 표현함으로써, 회로의 구조를 직관적으로 파악할 수 있습니다.
2) 4비트 병렬 가산기 설계
4비트 병렬 가산기는 4개의 1비트 전가산기를 연결하여 4비트의 두 수를 더합니다. 각 비트의 합을 계산하고, 이전 비트의 자리올림을 다음 비트의 입력으로 연결합니다.
module ripple_carry_adder_gate (
input [3:0] A, B,
input Cin,
output [3:0] S,
output Cout
);
wire [3:0] carry;
full_adder_gate fa0 (A[0], B[0], Cin, S[0], carry[0]);
full_adder_gate fa1 (A[1], B[1], carry[0], S[1], carry[1]);
full_adder_gate fa2 (A[2], B[2], carry[1], S[2], carry[2]);
full_adder_gate fa3 (A[3], B[3], carry[2], S[3], Cout);
endmodule
위 코드에서는 full_adder_gate 모듈의 인스턴스를 4개 생성하고, 각 전가산기의 자리올림 출력을 다음 전가산기의 입력으로 연결합니다. 첫 번째 전가산기의 Cin은 외부 입력으로, 마지막 전가산기의 Cout은 최종 자리올림 출력입니다.
4. 데이터플로우 레벨 모델링
데이터플로우 레벨 모델링은 회로를 데이터의 흐름과 연산의 관점에서 설명하는 방식입니다. assign 문을 사용하여 입력 신호로부터 출력 신호까지의 데이터 흐름을 직접적으로 표현합니다. 게이트 레벨 모델링에 비해 추상화 수준이 높고, 회로의 동작을 이해하기 쉬우며, 코드가 간결해지는 장점이 있습니다.
1) 1비트 전가산기 설계
1비트 전가산기의 논리식을 직접 assign 문으로 표현할 수 있습니다.
module full_adder_dataflow (
input A, B, Cin,
output S, Cout
);
assign S = A ^ B ^ Cin;
assign Cout = (A & B) | (Cin & (A ^ B));
endmodule
위 코드에서 ^는 XOR 연산, &는 AND 연산, |는 OR 연산을 나타냅니다. 데이터플로우 레벨에서는 논리식을 직접적으로 표현하므로, 회로의 동작을 파악하기 쉽습니다.
2) 4비트 병렬 가산기 설계
4비트 병렬 가산기는 1비트 전가산기를 모듈로 사용하거나, 데이터플로우 레벨에서 각 비트의 연산을 개별적으로 표현할 수 있습니다.
module ripple_carry_adder_dataflow (
input [3:0] A, B,
input Cin,
output [3:0] S,
output Cout
);
wire [3:0] carry;
assign S[0] = A[0] ^ B[0] ^ Cin;
assign carry[0] = (A[0] & B[0]) | (Cin & (A[0] ^ B[0]));
assign S[1] = A[1] ^ B[1] ^ carry[0];
assign carry[1] = (A[1] & B[1]) | (carry[0] & (A[1] ^ B[1]));
assign S[2] = A[2] ^ B[2] ^ carry[1];
assign carry[2] = (A[2] & B[2]) | (carry[1] & (A[2] ^ B[2]));
assign S[3] = A[3] ^ B[3] ^ carry[2];
assign Cout = (A[3] & B[3]) | (carry[2] & (A[3] ^ B[3]));
endmodule
위 코드에서는 각 비트의 합과 자리올림을 개별적으로 계산하는 assign 문을 사용했습니다. 게이트 레벨 모델링보다 코드가 간결하며, 각 비트의 연산 관계를 쉽게 파악할 수 있습니다.
5. 동작 레벨 모델링
동작 레벨 모델링은 회로의 동작을 always 블록과 절차적 할당문을 사용하여 표현하는 방식입니다. 이 방식은 회로의 동작 알고리즘에 집중하며, 회로의 복잡한 동작을 간결하게 표현할 수 있습니다. 하지만, 하드웨어의 병렬성을 명시적으로 표현하기 어렵고, 시뮬레이션 결과가 실제 하드웨어의 동작과 다를 수 있다는 단점이 있습니다.
1) 1비트 전가산기 설계
동작 레벨 모델링에서는 always 블록과 case 문 또는 if-else 문을 사용하여 전가산기의 기능을 구현할 수 있습니다.
module full_adder_behavioral (
input A, B, Cin,
output reg S, Cout
);
always @(*) begin
case ({A, B, Cin})
3'b000: begin S <mark class="highlight"><strong><u> 0; Cout </u></strong></mark> 0; end
3'b001: begin S <mark class="highlight"><strong><u> 1; Cout </u></strong></mark> 0; end
3'b010: begin S <mark class="highlight"><strong><u> 1; Cout </u></strong></mark> 0; end
3'b011: begin S <mark class="highlight"><strong><u> 0; Cout </u></strong></mark> 1; end
3'b100: begin S <mark class="highlight"><strong><u> 1; Cout </u></strong></mark> 0; end
3'b101: begin S <mark class="highlight"><strong><u> 0; Cout </u></strong></mark> 1; end
3'b110: begin S <mark class="highlight"><strong><u> 0; Cout </u></strong></mark> 1; end
3'b111: begin S <mark class="highlight"><strong><u> 1; Cout </u></strong></mark> 1; end
default: begin S <mark class="highlight"><strong><u> 0; Cout </u></strong></mark> 0; end // Default case for completeness
endcase
end
endmodule
위 코드에서 always @(*)는 입력 신호가 변경될 때마다 블록 내의 코드를 실행합니다. case 문을 사용하여 입력 조합에 따른 S와 Cout의 값을 정의합니다.
2) 4비트 병렬 가산기 설계
4비트 병렬 가산기는 동작 레벨 모델링을 사용하여 각 비트의 연산을 순차적으로 처리하도록 구현할 수 있습니다.
module ripple_carry_adder_behavioral (
input [3:0] A, B,
input Cin,
output reg [3:0] S,
output reg Cout
);
always @(*) begin
S[0] = A[0] ^ B[0] ^ Cin;
wire carry0 = (A[0] & B[0]) | (Cin & (A[0] ^ B[0]));
S[1] = A[1] ^ B[1] ^ carry0;
wire carry1 = (A[1] & B[1]) | (carry0 & (A[1] ^ B[1]));
S[2] = A[2] ^ B[2] ^ carry1;
wire carry2 = (A[2] & B[2]) | (carry1 & (A[2] ^ B[2]));
S[3] = A[3] ^ B[3] ^ carry2;
Cout = (A[3] & B[3]) | (carry2 & (A[3] ^ B[3]));
end
endmodule
위 코드에서는 각 비트의 합과 자리올림을 계산하고, 이를 다음 비트의 입력으로 사용하는 과정을 순차적으로 표현했습니다. 동작 레벨 모델링은 회로의 기능을 명확하게 이해하는 데 도움을 주지만, 하드웨어의 병렬성을 고려하지 않으므로, 실제 하드웨어의 성능과는 차이가 있을 수 있습니다.
6. 모델링 스타일 비교
세 가지 모델링 스타일 (게이트 레벨, 데이터플로우 레벨, 동작 레벨)을 비교하면 다음과 같습니다.
| 특징 | 게이트 레벨 | 데이터플로우 레벨 | 동작 레벨 |
|---|---|---|---|
| 추상화 수준 | 낮음 | 중간 | 높음 |
| 표현 방식 | 기본 게이트 연결 | 데이터 흐름, 논리식 | always 블록, 절차적 할당 |
| 코드 복잡도 | 높음 (복잡한 회로) | 중간 | 낮음 |
| 가독성 | 낮음 | 중간 | 높음 |
| 설계 유연성 | 낮음 | 중간 | 높음 |
| 하드웨어 구현 | 실제 하드웨어 구조에 근접 | 데이터 흐름에 최적화 | 하드웨어 병렬성 고려 어려움 |
| 설계/디버깅 용이성 | 어려움 | 보통 | 쉬움 |
각 모델링 스타일은 장단점이 있으며, 설계 목표와 회로의 복잡도에 따라 적절한 모델링 스타일을 선택하는 것이 중요합니다. 예를 들어, 회로의 동작을 정밀하게 제어하고 싶거나, 물리적 구조를 직접적으로 파악해야 하는 경우에는 게이트 레벨 모델링이 유용합니다. 회로의 기능을 빠르게 구현하고 싶거나, 코드의 가독성을 높이고 싶다면 데이터플로우 또는 동작 레벨 모델링이 적합합니다. 실제 회로 설계에서는 이러한 모델링 스타일을 혼합하여 사용하는 경우가 많습니다.
7. 실습 결과 시뮬레이션
Verilog 코드를 작성한 후에는 시뮬레이션을 통해 설계의 정확성을 검증해야 합니다. 시뮬레이션 툴을 사용하여 가산기의 입력에 다양한 값을 인가하고, 출력 결과를 확인하여 설계가 의도대로 동작하는지 검증합니다. 시뮬레이션 파형을 통해, 각 모델링 스타일의 동작 방식을 비교하고, 자리올림 전파 지연 (Ripple Carry Delay)과 같은 성능 관련 요소를 분석할 수 있습니다.
// Testbench 예시 (gate_level)
module adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] S;
wire Cout;
// Instantiate the adder module
ripple_carry_adder_gate uut (
.A(A),
.B(B),
.Cin(Cin),
.S(S),
.Cout(Cout)
);
initial begin
// Initialize inputs
A = 4'b0000;
B = 4'b0000;
Cin = 0;
#10; // Wait for 10 time units
// Test case 1
A = 4'b0001;
B = 4'b0010;
Cin = 0;
#10;
// Test case 2
A = 4'b1111;
B = 4'b0001;
Cin = 1;
#10;
// Add more test cases here...
$finish; // End the simulation
end
// Optional: Display outputs
initial begin
$monitor("A=%b, B=%b, Cin=%b, S=%b, Cout=%b", A, B, Cin, S, Cout);
end
endmodule
위는 gate_level로 설계된 ripple_carry_adder_gate를 테스트하기 위한 간단한 테스트벤치 예시입니다. 테스트벤치는 입력 신호에 테스트 값을 인가하고, 출력 신호를 관찰하여 설계의 정확성을 검증합니다. initial 블록 내에서 시뮬레이션 시간을 설정하고, 다양한 입력 조합을 테스트합니다. monitor 문을 사용하여 시뮬레이션 결과를 출력할 수 있습니다.
8. 결론
본 실습에서는 가산기를 설계하는 과정을 통해 게이트 레벨, 데이터플로우 레벨, 동작 레벨의 세 가지 Verilog 모델링 기법을 비교 분석했습니다. 각 모델링 스타일은 회로를 표현하는 방식, 추상화 수준, 그리고 설계의 유연성에 차이를 보이며, 설계 목표와 회로의 복잡도에 따라 적절한 모델링 스타일을 선택하는 것이 중요합니다. 실제 회로 설계에서는 이러한 모델링 스타일을 혼합하여 사용하여, 설계 효율성을 높이고 성능을 최적화하는 것이 일반적입니다.

비슷한 글 추천
2-3. Verilog의 모듈과 인스턴스
모듈 정의, 포트 연결, 모듈 인스턴스화 방법을 설명합니다. 계층적 설계를 위한 핵심 개념을 다룹니다.
2-2. Verilog 연산자
Verilog에서 제공하는 다양한 연산자(산술, 논리, 비트 단위, 관계, 축소 등)를 종류별로 설명하고 예제를 통해 이해를 돕습니다.
4-5. MNIST 손글씨 숫자 인식: PyTorch 실습
MNIST 손글씨 숫자 인식 문제를 PyTorch를 이용하여 해결하는 실습 과정을 상세히 설명합니다.
1-2. Docker 설치 및 기본 사용법
Docker를 설치하고 기본적인 명령어(run, pull, ps, stop, rm)를 사용하여 컨테이너를 생성, 실행, 관리하는 방법을 익힙니다. 간단한 예제를 통해 실습합니다.
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.