개발/개발 공부

[밑바닥부터] 5일차 - 2장 불 연산: 가산기 아키텍처, ALU 설계

codesparkling 2025. 4. 10. 16:32

가산기 아키텍처, ALU 설계

명세

가산기(adder)부터 산술 논리 장치(ALU)까지 칩들을 계층적으로 정의한다.
칩이 무엇을 위해 설계되는지 추상화 레벨부터 살펴보고 칩을 어떻게 만드는지 자세한 구현을 학습한다.
이번 장에서 학습 하는 내용은 음수, 0이상의 수, 부호가 섞인 수 모두 정상적으로 연산할 수 있다.

가산기

가산기는 간단하게 설명하면 다음과 같다.

  • 반가산기(half-adder)
    • 두 비트를 더한다.
  • 전가산기(full-adder)
    • 세 비트를 더한다.
  • 가산기(adder)
    • 두 개의 n비트 숫자를 더한다.
  • 증분기(incrementer)
    • 특수 목적용 가산기
    • 주어진 숫자에 1을 더한다.
  1. 반가산기

    • 2진수 덧셈의 첫 단계로 두 비트를 더한다.
    • 입력(a, b)과 출력(carry, sum)에 대한 진리표
      a b carry sum
      0 0 0 0
      1 0 0 1
      0 1 0 1
      1 1 1 0
    • 인터페이스
    • API
        칩 이름: HalfAdder
        입력: a, b
        출력: carry, sum
        기능: sum = a + b의 LSB
                    carry = a + b의 MSB
  2. 전가산기

    • 세 개의 비트를 더한다.

    • 세 개의 비트를 더하는 이유는 반가산기에서 나오는 carry bit를 함께 더하기 위함이다.

    • 입력(a, b)과 출력(carry, sum)에 대한 진리표

      a b c carry sum
      0 0 0 0 0
      0 0 1 0 1
      0 1 0 0 1
      0 1 1 1 0
      1 0 0 0 1
      1 0 1 1 0
      1 1 0 1 0
      1 1 1 1 1
    • 인터페이스

    • API

        칩 이름: FullAdder
        입력: a, b, c
        출력: carry, sum
        기능: sum = a + b + c의 LSB
                    carry = a + b + c의 MSB
  3. 가산기

    • 8, 16, 32, 64 비트 같은 고정 단어 크기로 표현한다.

    • 이런 두 개의 n 비트 수를 더하는 기능의 칩을 가산기라 부른다.

    • 16비트 가산기의 인터페이스

    • API

        칩 이름: Add16
        입력: a[16], b[16]
        출력: out[16]
        기능: 두 개의 16비트 수를 더한다. 오버플로우 비트는 무시한다.
  4. 증분기

    • 주어진 숫자에 1을 더하는 칩
    • 2의 보수법에서 음수를 표현하기 위해 반전 연산 후 1을 더하는 연산 등에서 필요하다.
    • 논리 게이트 API
        칩 이름: Inc16
        입력: in[16]
        출력: out[16]
        기능: out = in + 1, 오버플로우 비트는 무시한다.

산술 논리 장치

이번에 배울 ALU는 이 책의 목적에 맞게 설계되어 일반적인 ALU와 다를 수 있다.
ALU는 본래 산술 및 논리 연산 집합을 계산하도록 설계되어 있다.
핵 ALU(우리가 만드는 ALU)는 앞으로 만들 Hack(핵)이라는 컴퓨터에 맞춰서 설계되어 있다.


이 책에서 배울 핵 ALU의 특징은 다음과 같다.

  • 정수 산술 연산만을 지원한다. (부동소수점 등 지원 X)
  • 다음 18개의 연산만을 계산하도록 설정되어 있다.
      

    먼저 핵 ALU의 인터페이스를 확인해보자.
    핵 ALU는 2의 보수법으로 표현된 정수 x, y 두 개의 16비트와 여섯 개의 제어 비트(control bit, 각각 1비트 입력)을 입력받아 계산한다. (zr과 ng에 대한 내용은 지금 챕터에서는 무시한다.)
제어 비트 의미
zx x입력을 0으로 설정한다.
zx가 1이면 x는 무조건 0이 출력되고, 0이면 x값 그대로 출력된다.
zy zx와 똑같은 기능을 하되, y에 대해 적용되는 점이 다르다.
nx 입력을 부정한다.
nx가 1이면 Not x, 0이면 x 그대로 출력한다.
ny nx와 똑같은 기능을 하지만 y에 대해 적용된다.
f f = 1 인 경우, x와 y의 더하기 연산을 수행한다. (x + y)
f = 0 인 경우, x와 y에 대해 and 연산을 수행한다. (x & y)
no 출력을 부정한다. (negate output)
no = 1인 경우, 최종 출력 결과를 비트별로 부정한다.
no = 0인 경우, 출력 결과를 그대로 유지한다.

18개의 연산을 제어 비트를 활용한 표로 나타내보자.
zx nx zy ny f no out(ALU의 출력 결과)
1 0 1 0 1 0 0
1 1 1 1 1 1 1
1 1 1 0 1 0 -1
0 0 1 1 0 0 x
1 1 0 0 0 0 y
0 0 1 1 0 1 !x
1 1 0 0 0 1 !y
0 0 1 1 1 1 -x
1 1 0 0 1 1 -y
0 1 1 1 1 1 x+1
1 1 0 1 1 1 y+1
0 0 1 1 1 0 x-1
1 1 0 0 1 0 y-1
0 0 0 0 1 0 x+y
0 1 0 0 1 1 x-y
0 0 0 1 1 1 y-x
0 0 0 0 0 0 x&y
0 1 0 1 0 1 x|y

이런 ALU의 기능(ALU 논리)을 이해하기 위해서 x = 27에 대해 x -1 함수를 계산한다고 가정해보자.
27을 의미하는 2진 코드를 입력 x에 넣는다.그리고 x - 1에서 y의 값은 계산에 영향을 미치지 않으므로 신경쓰지 않아도 된다.
x - 1에 해당하는 제어 비트를 찾아보면 001110이다.
차례로 연산을 진행해보자.

  1. zx가 0이므로 x는 27의 2진 코드 그대로 출력된다.
  2. nx가 0이므로 x에 대해 반전 연산이 일어나지 않는다.
  3. zy가 1이므로 y가 어떤 값이든 0이 된다.
  4. ny가 1이므로 y값이 반전되어 1111…1이 된다.(16비트)
    ⇒ 이 값은 2의 보수법에서 -1을 의미한다.
  5. f가 1이므로 x + y, 덧셈 연산을 진행한다.
    x + (-1)
  6. no가 0이므로 출력 반전 연산은 일어나지 않는다.

위의 연산을 모두 진행하면 결국 x + (-1) = x - 1이다.


ALU의 API를 나타내보자.

칩 이름: ALU
입력: x[16], y[16], // 두 개의 16비트 데이터 입력
            zx, // 입력 x를 0으로
            nx, // 입력 x를 반전
            zy, // 입력 y를 0으로
            ny, // 입력 y를 반전
            f, // f==1 이면 덧셈 연산, f==0 이면 and 연산
            no // 출력 out을 반전
출력: out[16], // 16비트 출력
            zr, // out==0이면 zr=1, 아니면 zr=0
            ng // out<0이면 ng=1, 아니면 ng=0
기능: if zx x=0 // 16비트 상수 0
            if nx x=!x // 비트 반전
            if zy y=0 // 16비트 상수 0
            if ny y=!y // 비트 반전
            if f out=x+y // 2의 보수법으로 정수 덧셈
            else out=x&y // 비트 And
            if no out=!out // 비트 반전
            if out=0 zr=1 else zr=0 // 16비트 동일 값 비교
            if out<0 ng=1 else ng=0 // 2의 보수법 비교
            (모든 오버플로우는 무시된다.)