조합회로 시스템 설계 과정

2024. 4. 14. 03:08CS/논리설계

728x90

* 본 글은 [Introduction to Logic Design, 3rd ed. - Alan B. Marcovitz] 를 바탕으로 작성하였습니다.

 

조합회로란, 해당 시점의 출력이 그 시점에서 입력으로만 결정되는 회로를 말한다. 반대되는 개념으로는 이전의 입력도 출력에 관여하는 순차회로가 있다. 본 포스팅에서는 조합회로를 설계하는 기본적인 방법에 대해 알아보고자 한다.

 

조합회로 시스템 설계 과정

1단계: 각 입력과 출력을 2진으로 표현하라

 

일반적으로 스위치가 켜지는 위 방향을 1, 꺼지는 아래 방향을 0으로 코딩할 수 있다. 또한, 만약 필요하다면 문제를 더 자근 부문제(subproblem)으로 나눌 수 있다.

 

2단계: 설계 사양을 진리표 혹은 대수식으로 형식화하라

 

진리표란, 가능한 입력 조합에 대한 각 출력값을 나열한 표이다. 진리표는 일반적으로 n개의 입력을 받을 때 길이가 2^n이 되므로, 문제의 종류에 따라 매우 길어질 수 있는데, 이것이 위에서 언급한 부문제로 나누어야 하는 이유이다. 예를 들어, 32비트 가산기를 설계한다고 할 때, 이것을 처음부터 하는 것이 아니라 4비트 가산기를 이용할 수 있는 것이다.

 

3단계: 서술을 간단히 하라.

 

대부분의 경우는 진리표를 대수식으로 바꾸어야 한다. 일부 경우는 진리표로부터 바로 구현할 수도 있다.

4단계: 설계 목표와 제약에 근거하여 사용 가능한 부품으로 시스템을 구현하라.

 

예를 들어, 많은 수의 설계는 게이트(gate: 한 개의 출력을 갖는 회로)로 구현하게 되는데, 이러한 경우 최종 설계의 형태는 게이트로 구현한 볼록도로 나타낼 수 있다.

OR 게이트

무정의 조건

무정의(Don't care condition)란, 일부의 입력 조건에 따라 출력 값이 지정되지 않는 경우를 말한다. 예를 들어, 아래 진리표는 무정의 조건을 가지고 있는 것이다. 진리표에서 무정의는 X 혹은 d, phi 등의 기호를 사용한다. 이러한 조건 하에서는 f값이 무엇이 되든 상관하지 않는다.

a b f
0 0 0
0 1 1
1 0 1
1 1 X

 

무정의가 있는 시스템을 설계할 때는, 무정의 입력에 대한 출력을 어떻게 설정하는지에 따라 구현 비용의 차이가 발생할 수 있다. 실제 시스템에서는 다양한 경우로 무정의가 발생하는데, 아래는 두 가지 예시이다.

 

일어날 수 없는 입력 조합

 

앞선 포스팅(https://cascade.tistory.com/87)에서 다룬 BCD 코드에서, 4비트 수 16개 중 6개는 10진수를 표현하지 않는다. 이러한 6개의 4비트 수가 무정의 입력이 된다.

 

두 개가 연결된 시스템

 

아래와 같이 시스템 1이 시스템 2를 동작하게 하는 경우, J에 상관없이 시스템 2가 동작하는 경우가 있다. 이러한 경우, 시스템 1의 출력 J는 입력 조합에 대한 무정의이다.

이러한 시스템의 예시는 2진 메모리소자(플립플롭)가 있다.

 

진리표 작성

위에서 나열한 단계에 의하면, 설계 문제가 주어졌을 때 가장 먼저 해야 할 일은 입력을 어떻게 2진수로 코딩할지 결정하는 것이다. 그 이후 진리표를 작성하는 것인데, 이때 입력이 n비트로 코딩된다면 진리표는 2^n줄이 된다. 예를 들어, 한 자리 수를 입력받아, 아래와 같은 7-segment display에 표시하는 설계를 생각해 보자. 이 경우 한 자리 자연수는 4비트 이진수로 코딩할 수 있으며, 출력은 디스플레이의 각 segment에 대응하는 7비트 이진수가 된다.

이 경우, 디스플레이의 각 segment를 위와 같이 a~f로 나타내어, 진리표를 아래와 같이 작성할 수 있다.

 

실제 회로로 직접 구현해볼 수도 있으나, 간단한 예제이므로 pytorch의 tensor를 이용해 간단히 숫자를 입력받아 7-segment display로 표시하는 것을 연습해 보았다. 먼저, 위의 진리표를 행렬로 작성해 주었다.

TRUTH_TABLE = [
    [1, 1, 1, 1, 1, 1, 0],
    [0, 1, 1, 0, 0, 0, 0],
    [1, 1, 0, 1, 1, 0 ,1],
    [1, 1, 1, 1, 0, 0, 1],
    [0, 1, 1, 0, 0, 1, 1],
    [1, 0, 1, 1, 0, 1, 1],
    [1, 0, 1, 1, 1, 1, 1],
    [1, 1, 1, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 0, 1, 1],
]

 

그 다음, 디스플레이를 위해 7 x 4 짜리 텐서를 사용하기로 했다. 즉 8을 표시하면 아래와 같이 나오도록 할 것이다. 처음에는 모든 구역이 0으로 초기화된다.

 

시스템에 의해 나온 이진수 출력값 a~g에 의해, 켜지는 segment들을 나타내기 위해 아래 리스트를 작성하였다.

segments = [
    [(0, 1), (0, 2)],
    [(1, 3), (2, 3)],
    [(4, 3), (5, 3)],
    [(6, 1), (6, 2)],
    [(4, 0), (5, 0)],
    [(1, 0), (2, 0)],
    [(3, 1), (3, 2)],
]

 

먼저, 숫자를 입력받아, 해당 숫자에 대응하는 segment를 켠 tensor를 리턴하는 함수를 아래와 같이 작성하였다.

def number_to_display(number):
    DISPLAY = torch.zeros(7, 4)
    binary_outputs = TRUTH_TABLE[number]
    for i, output in enumerate(binary_outputs):
        if output:
            cell1, cell2 = segments[i]
            DISPLAY[cell1[0]][cell1[1]] = 1
            DISPLAY[cell2[0]][cell2[1]] = 1
    return DISPLAY

 

다음으로 각 디스플레이 텐서를 이미지로 바꾸어 저장하는 함수를 작성하였다.

def save_image(number):
    transform = transforms.ToPILImage()
    img = transform(number_to_display(number))
    img.resize((400, 700), Image.NEAREST).save('display_{}.png'.format(number))

 

전체 코드는 아래와 같다.

import numpy as np
import torch
import time
from PIL import Image
import torchvision.transforms as transforms
import torch.nn.functional as F



TRUTH_TABLE = [
    [1, 1, 1, 1, 1, 1, 0],
    [0, 1, 1, 0, 0, 0, 0],
    [1, 1, 0, 1, 1, 0 ,1],
    [1, 1, 1, 1, 0, 0, 1],
    [0, 1, 1, 0, 0, 1, 1],
    [1, 0, 1, 1, 0, 1, 1],
    [1, 0, 1, 1, 1, 1, 1],
    [1, 1, 1, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 0, 1, 1],
]


segments = [
    [(0, 1), (0, 2)],
    [(1, 3), (2, 3)],
    [(4, 3), (5, 3)],
    [(6, 1), (6, 2)],
    [(4, 0), (5, 0)],
    [(1, 0), (2, 0)],
    [(3, 1), (3, 2)],
]

def number_to_display(number):
    DISPLAY = torch.zeros(7, 4)
    binary_outputs = TRUTH_TABLE[number]
    for i, output in enumerate(binary_outputs):
        if output:
            cell1, cell2 = segments[i]
            DISPLAY[cell1[0]][cell1[1]] = 1
            DISPLAY[cell2[0]][cell2[1]] = 1
    return DISPLAY

def save_image(number):
    transform = transforms.ToPILImage()
    img = transform(number_to_display(number))
    img.resize((400, 700), Image.NEAREST).save('display_{}.png'.format(number))

for i in range(10):
    save_image(i)

 

0~9의 숫자를 디스플레이로 표시하여 저장한 결과는 아래와 같다.

 

 

반응형