본문 바로가기
개발 Tools/Verilog HDL

Verilog HDL RCA ( Ripple carry adder, 리플 케리 가산기, 파형, 16bit )

by 전컴반 2022. 2. 16.
반응형
 RCA (Ripple carry adder)

 

먼저 부호 있는 수(signed)와 없는 수(unsigned)의 구분이 필요하다. 부호가 있는 수의 덧셈에서 carry는 다 버린다.

왜냐면 carry가 있든 없든 원하는 결괏값이 똑같기 때문이다.

 

 

하지만 오버플로우가 발생하기도 하는데, 이유는 결괏값이 표현 범위를 벗어나기 때문이다. 예를 들어 8bit라면, 2의 8승으로 0~ 255까지 표현 가능하지만 부호가 있기 때문에  -127 ~ 127까지다. 이 범위의 수에서 결괏값이 벗어나면 오버플로우가 발생했다고 한다. 이때는 프로그램이 오류를 나타내고 종료한다. 어떤 오류냐 하면

양수 + 양수 = 음수

음수 + 음수 = 양수와 같은 오류가 발생한다. 

 

부호가 없는 이진수도 오버플로우가 발생한다. 8bit를 예로 들었을 때 0~255를 넘어가면 오버플로우가 발생한다.

 

 

이런 개념을 바탕에 두고 RCA를 구현해보자. 리플 케리 덧셈기는 Rippel이 파도를 뜻하는데 carry가 파도처럼 전달 전달되기 때문에 이와 같은 이름 붙었다. 하나씩 연산하기에 느리다는 단점이 있다

예를 들어보겠다. 8bit의 부호 없는 수의 덧셈을 한다면 어떻게 해야 할까??

 

반가산기는 2비트를 더하고 전가산기는 케리까지 더해서 3비트를 더한다. 그래서 전가산기 7개와 반가산기 1개로 구현할 수 있다. 물론 전가산기 8개로도 가능하다

 

16비트 RCA도 똑같다. 

 

 

DUT 코드

module top_fa (a, b, cin, s, cout);
    input [15:0] a, b;
    input cin;
    output [15:0] s;
    output cout;

    wire [15:1] c;
    
    fa u[15:0] (.a(a[15:0]), .b(b[15:0]), .cin({c[15:1], cin}), .s(s[15:0]), .cout({cout, c[15:1]}));
endmodule    


module fa(a, b, cin, s, cout);
    input a, b, cin;
    output s, cout;
    
    wire s;
    wire cout;

    assign #2 cout = a & b | b & cin | cin & a;
    assign #1 s = a^b^cin;
endmodule

 

fa에서 carray를 만드는데 2 nano지연을 주고 sum 연산 결과가 나오는데 1 nano지연이 생긴다고 가정했다.

또한 top_fa에서 중간에 carray를 wire로 선언하고 묶어줄 때, cin, cout은 c [14:0]에 해당되기 때문에 처음과 마지막만 더해서 cin, cout에 넣어줬다. 

 

test bench를 보자

 

module tb_rfa;
    wire [15:0] sum;
    wire c16;
    reg [15:0] a, b;
    
    top_fa u0 (.a(a), .b(b), .cout(c16), .cin(1'b0), .s(sum));
 
    initial begin
    a = 16'h7fff;
    b = 16'h1;
    #40 a = 16'b0; b = 16'b0;
    #40;
    for ({a,b} = 32'h0; {a, b} < 32'h2_ffff; {a,b} = {a,b} + 1)
        #40 if (a + b !== {c16, sum})
            $display ("Error!! 0d+%0d=%0d expected:%0d", a, b, sum, a+b);
    #10 $stop;
    end
    
endmodule

 

차근차근 보자, 헷갈리니 잘 봐야 한다.

initial구문에서 처음에 a와 b를 초기화한다. 하지만 이때 sum이 x로 나오는 이유는 DUT에서 fa의 module에 carry를 만드는데 #2를 줬고, sum을 만드는데 #1을 줬기 때문이다.

무슨 말이냐면, 0번째부터 14번째까지 FA가 carry를 만드는데 #2 * 15 =30 nano가 필요하고 마지막 sum을 만드는데 #1이 필요하기 때문에 31 nano가 지난 뒤에야 sum이 나온다. 아래 그림의 노란 줄이 31 nano 일 때다.

 

그다음 단계는 #40간 기다리기 때문에 처음에 줬던 a, b를 더한다. 그리고 #40이 지나면 a = 0000, b = 0000을 준다. 근데 잘 보면 sum 중간에 빈 공간이 있다. 이건 값이 바뀌고 새로 carry가 생성되는데 #2만큼 걸리기 때문이다. 

 

그리고 1씩 더하면 반복하며 sum을 하면 아래와 같은 파형이 나온다. 잘 보이진 않지만 sum은 #1씩 밀려서 출력된다.

 

 

RAC는 로직이 간단하여 저렴하지만 carry가 계산되는 시간이 걸려 느리다는 단점이 있다.

반응형

댓글