본문 바로가기

JK 입력식으로 동기 카운터 만들기

원하는 상태 변화에서 거꾸로 필요한 J·K 입력을 찾는 여기표를 만들고, 무관 조건을 넣은 카르노 맵으로 2비트 동기 카운터의 입력식을 이끌어 냅니다. 한 에지에서 모든 비트를 이전 값으로 함께 계산해야 하는 이유를 잘못된 구현과 비교하고, 동기 리셋과 실제 부품의 차이를 다룹니다.

래치·플립플롭·클록의 JK 표는 J와 K가 주어졌을 때 다음 상태가 무엇인지 알려 줍니다. 그런데 회로를 설계할 때는 질문이 거꾸로입니다. 원하는 다음 상태가 정해져 있고, 그 상태를 만들려면 J와 K에 무엇을 넣어야 하는지를 찾아야 합니다. 이 글에서는 이 거꾸로 된 표를 만들고, 부울 대수와 카르노 맵의 무관 조건을 이용해 2비트 동기 카운터의 입력식을 설계합니다.

원하는 전이에서 입력을 거꾸로 찾는다

두 비트 Q1Q0Q_1Q_0가 같은 상승 에지에서 함께 바뀌며 00, 01, 10, 11을 지나 다시 00으로 돌아가는 동기 카운터를 만들려고 합니다. 플립플롭 하나가 지금의 값 Q에서 다음 값 Q+Q^+로 가려면 J와 K가 무엇이어야 하는지를 정리한 표를 여기표(excitation table)라고 합니다.

QQ+Q^+JK이유
000X유지(00)나 reset(01)이면 0이 그대로이다
011Xset(10)이나 반전(11)이면 1이 된다
10X1reset(01)이나 반전(11)이면 0이 된다
11X0유지(00)나 set(10)이면 1이 그대로이다

X는 0을 넣든 1을 넣든 그 전이가 똑같이 일어난다는 뜻의 무관 조건입니다. 예를 들어 0에서 0으로 가려면 J만 0이면 되고, K가 0이면 유지, 1이면 reset이 되어 어느 쪽이든 결과가 0입니다. X는 값을 아무렇게나 둔다거나 회로에 0도 1도 아닌 신호를 넣는다는 뜻이 아니며, 식을 줄일 때 0과 1 가운데 편한 쪽으로 고를 수 있다는 뜻입니다. 이 표를 카운터의 네 가지 전이에 적용하면 다음과 같습니다.

Q1Q0Q_1Q_0Q1+Q0+Q_1^+Q_0^+J1J_1K1K_1J0J_0K0K_0
00010X1X
01101XX1
1011X01X
1100X1X1

무관 조건으로 입력식을 줄인다

입력 네 개를 각각 Q1Q_1을 행, Q0Q_0을 열로 하는 2 × 2 카르노 맵에 놓습니다. 아래 표의 괄호 안 두 값은 그 행에서 Q0=0Q_0=0, Q0=1Q_0=1일 때의 값입니다.

입력Q1=0Q_1=0 행Q1=1Q_1=1 행묶음과 식
J0J_0(1, X)(1, X)X를 1로 골라 네 칸을 묶으면 1
K0K_0(X, 1)(X, 1)X를 1로 골라 네 칸을 묶으면 1
J1J_1(0, 1)(X, X)Q0=1Q_0=1 열의 X를 1로 골라 세로 두 칸을 묶으면 Q0Q_0
K1K_1(X, X)(0, 1)Q0=1Q_0=1 열의 X를 1로 골라 세로 두 칸을 묶으면 Q0Q_0

J1J_1과 K1K_1의 Q0=0Q_0=0 열에 남은 X는 0으로 골라 식을 마무리합니다. 그래서 J0=K0=1J_0=K_0=1, J1=K1=Q0J_1=K_1=Q_0입니다. 아래 비트 Q0Q_0은 에지마다 반전하고, 위 비트 Q1Q_1은 에지 직전의 Q0Q_0이 1일 때만 반전합니다. 이진수를 1씩 셀 때 아래 자리가 1이었다가 0으로 넘어가는 순간에만 위 자리가 바뀐다는 사실을 그대로 옮긴 식입니다.

이전 Q0가 상위 비트의 반전을 고릅니다

이전 Q0=0이므로 상위 비트는 유지한다. 두 비트가 토글해 0으로 돌아간다. 각 단계의 값과 전환 이유를 비교합니다.

컴퓨터구조 · 논리 연결

이전 Q0가 상위 비트의 반전을 고릅니다

J0·K0에는 논리 1, J1·K1에는 에지 직전 Q0를 연결합니다. 두 JK 소자는 같은 상승 에지에서 갱신합니다.

이전 Q0가 상위 비트의 반전을 고릅니다고정 논리 1을 J0와 K0에, 이전 Q0를 J1과 K1에 연결하고 두 JK 소자를 공통 상승 에지 클록으로 동시에 갱신합니다.Q0 → J1,K1고정 논리 1하위 JK · Q0J0=K0=1매 에지 반전상위 JK · Q1J1=K1=Q0이전 Q0=1에 반전공통 상승 에지 CLK실선: JK 입력 값 연결 · 점선: 두 소자의 공통 클록같은 에지에서 이전 Q0로 두 다음 상태를 계산합니다
이전 Q0가 상위 비트의 반전을 고릅니다고정 논리 1을 J0와 K0에, 이전 Q0를 J1과 K1에 연결하고 두 JK 소자를 공통 상승 에지 클록으로 동시에 갱신합니다.Q0 → J1,K1고정 논리 1하위 JK · Q0J0=K0=1매 에지 반전상위 JK · Q1J1=K1=Q0이전 Q0=1에 반전공통 상승 에지 CLK실선: JK 입력 값점선: 공통 CLK같은 에지·이전 Q0 사용

정상 동작의 입력 연결 개요입니다. Q0는 상위 소자의 클록이 아니라 J1·K1에 연결됩니다. reset 동안 J=0·K=1을 선택하는 추가 논리, 전원·setup/hold·배선 지연은 본문에서 따로 구분합니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 00→01부터 11→00까지 진행합니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
00→01

이전 Q0=0이므로 상위 비트는 유지한다.

  • 두 Q 값 1: J1=K1=0
  • 두 Q 값 2: 이전 00
  • 같은 CLK 에지 후 01
01→10

이전 Q0=1이므로 두 비트가 토글한다.

  • 두 Q 값 1: J1=K1=1
  • 두 Q 값 2: 이전 01
  • 같은 CLK 에지 후 10
10→11

이전 Q0=0이므로 Q1은 유지한다.

  • 두 Q 값 1: 이전 10
  • 같은 CLK 에지 후 11
11→00

두 비트가 토글해 0으로 돌아간다.

  • 두 Q 값 1: 이전 11
  • 같은 CLK 에지 후 00

이전 Q0가 상위 비트의 반전을 고릅니다

이전 Q0=0이므로 상위 비트는 유지한다. 두 비트가 토글해 0으로 돌아간다. 각 단계의 값과 전환 이유를 비교합니다.

컴퓨터구조 · 논리 연결

이전 Q0가 상위 비트의 반전을 고릅니다

J0·K0에는 논리 1, J1·K1에는 에지 직전 Q0를 연결합니다. 두 JK 소자는 같은 상승 에지에서 갱신합니다.

이전 Q0가 상위 비트의 반전을 고릅니다고정 논리 1을 J0와 K0에, 이전 Q0를 J1과 K1에 연결하고 두 JK 소자를 공통 상승 에지 클록으로 동시에 갱신합니다.Q0 → J1,K1고정 논리 1하위 JK · Q0J0=K0=1매 에지 반전상위 JK · Q1J1=K1=Q0이전 Q0=1에 반전공통 상승 에지 CLK실선: JK 입력 값 연결 · 점선: 두 소자의 공통 클록같은 에지에서 이전 Q0로 두 다음 상태를 계산합니다
이전 Q0가 상위 비트의 반전을 고릅니다고정 논리 1을 J0와 K0에, 이전 Q0를 J1과 K1에 연결하고 두 JK 소자를 공통 상승 에지 클록으로 동시에 갱신합니다.Q0 → J1,K1고정 논리 1하위 JK · Q0J0=K0=1매 에지 반전상위 JK · Q1J1=K1=Q0이전 Q0=1에 반전공통 상승 에지 CLK실선: JK 입력 값점선: 공통 CLK같은 에지·이전 Q0 사용

정상 동작의 입력 연결 개요입니다. Q0는 상위 소자의 클록이 아니라 J1·K1에 연결됩니다. reset 동안 J=0·K=1을 선택하는 추가 논리, 전원·setup/hold·배선 지연은 본문에서 따로 구분합니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 00→01부터 11→00까지 진행합니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
00→01

이전 Q0=0이므로 상위 비트는 유지한다.

  • 두 Q 값 1: J1=K1=0
  • 두 Q 값 2: 이전 00
  • 같은 CLK 에지 후 01
01→10

이전 Q0=1이므로 두 비트가 토글한다.

  • 두 Q 값 1: J1=K1=1
  • 두 Q 값 2: 이전 01
  • 같은 CLK 에지 후 10
10→11

이전 Q0=0이므로 Q1은 유지한다.

  • 두 Q 값 1: 이전 10
  • 같은 CLK 에지 후 11
11→00

두 비트가 토글해 0으로 돌아간다.

  • 두 Q 값 1: 이전 11
  • 같은 CLK 에지 후 00

그림은 두 JK 플립플롭이 같은 클록을 함께 받고, Q0Q_0이 위 플립플롭의 클록이 아니라 J1J_1, K1K_1 입력으로 이어진 모습입니다. Q0Q_0을 위 비트의 클록으로 쓰는 리플 카운터와 구별해야 합니다. 리셋 회로, 전원, 게이트의 실제 지연은 그림에서 생략했으며, 아래에서 따로 다룹니다.

한 에지에서 모든 비트를 이전 값으로 계산한다

지금 상태가 01이면 Q0Q_0은 반전해 0이 되고, 에지 직전의 Q0Q_0이 1이므로 Q1Q_1도 반전해 1이 되어 다음 상태는 10입니다. 이때 두 비트의 다음 값은 모두 에지 직전의 값으로 계산해야 합니다. 실제 회로에서도 모든 플립플롭이 같은 에지에서 동시에 값을 받아들이기 때문입니다. 소프트웨어로 흉내 낼 때 이것을 놓치면 전혀 다른 회로가 됩니다.

def jk(q, j, k):
    return (j & (1 - q)) | ((1 - k) & q)


def counter_step(state, reset=False):
    if reset:
        return 0
    q1, q0 = divmod(state, 2)
    next_q0 = jk(q0, 1, 1)
    next_q1 = jk(q1, q0, q0)
    return 2 * next_q1 + next_q0


def counter_step_wrong(state):
    q1, q0 = divmod(state, 2)
    q0 = jk(q0, 1, 1)
    q1 = jk(q1, q0, q0)
    return 2 * q1 + q0


for step in (counter_step, counter_step_wrong):
    state, trace = 0, []
    for _ in range(4):
        state = step(state)
        trace.append(f"{state:02b}")
    print(step.__name__, trace)
print(counter_step(0b11, reset=True))
counter_step ['01', '10', '11', '00']
counter_step_wrong ['11', '10', '01', '00']
0

jk는 JK 플립플롭의 특성 방정식 Q+=JQ‾+K‾QQ^+=J\overline{Q}+\overline{K}Q이고, divmod(state, 2)는 상태를 위 비트와 아래 비트로 나눕니다. counter_step은 두 비트의 다음 값을 모두 원래의 q0로 계산한 뒤 함께 돌려주므로, 00에서 시작해 01, 10, 11, 00으로 셉니다. counter_step_wrong은 q0를 먼저 새 값으로 바꾼 뒤 그 새 값으로 q1의 입력을 정합니다. 그 결과 11, 10, 01, 00으로 거꾸로 세는 회로가 되었는데, 위 비트가 "아래 비트가 1에서 0으로 넘어갈 때"가 아니라 "아래 비트가 1이 될 때" 반전하기 때문입니다. 마지막 줄은 리셋이 켜진 에지에서 11이 00이 된다는 결과입니다.

리셋과 실제 부품

counter_step의 리셋은 리셋 신호가 켜진 에지에서 00을 저장하는 동기 리셋입니다. 앞에서 구한 입력식 J0=K0=1J_0=K_0=1, J1=K1=Q0J_1=K_1=Q_0은 카운터가 세는 동작만 정한 것이라, 리셋까지 회로로 만들려면 리셋이 켜진 동안 각 비트에 J=0J=0, K=1K=1을 넣어 다음 에지에서 0이 되게 하는 논리를 더해야 합니다. 플립플롭의 비동기 클리어 단자를 쓰면 에지와 상관없이 곧바로 0이 되므로, 같은 시간표로 읽을 수 없습니다.

실제 부품은 이 교재의 모델과 다를 수 있습니다. 예를 들어 onsemi SN74LS76A 데이터시트의 JK 플립플롭은 하강 에지에서 동작하고, 클록과 상관없이 동작하는 set과 clear 단자를 가집니다. 그래서 이 글의 상승 에지, 동기 리셋 모델을 그 부품의 배선과 타이밍으로 그대로 옮기면 안 됩니다. 실제 동기 회로에서는 에지 직전에 입력이 안정되는지, 출력 지연과 조합 회로의 지연, 설정 시간과 유지 시간을 함께 확인해야 하며, 이런 시간 조건은 MIT 6.004의 순차 논리 강의에서 더 볼 수 있습니다.

정리

  • 여기표는 지금의 값과 원하는 다음 값에서 필요한 입력을 거꾸로 찾은 표이며, JK 플립플롭은 전이마다 한 입력이 무관 조건 X가 됩니다.
  • 카운터의 전이마다 여기표를 적용하고, 무관 조건을 이용해 카르노 맵으로 줄이면 2비트 동기 카운터의 입력식은 J0=K0=1J_0=K_0=1, J1=K1=Q0J_1=K_1=Q_0입니다.
  • 동기 회로에서는 모든 비트의 다음 값을 에지 직전의 값으로 함께 계산해야 하며, 새 값을 먼저 쓰면 다른 회로가 됩니다.
  • 동기 리셋을 회로로 만들려면 입력 논리를 더해야 하고, 실제 부품의 동작 에지와 비동기 단자는 데이터시트로 확인합니다.

연습 문제

1. 잘못 이은 입력

J0=K0=1J_0=K_0=1은 그대로 두고 J1=K1=1J_1=K_1=1로 잘못 이었습니다. 00에서 시작해 네 에지 뒤까지의 상태를 쓰고, 정상 카운터와 처음 달라지는 전이를 찾으세요.

해설 보기

J = K = 1이면 그 비트는 에지마다 반전하므로, 두 비트가 함께 반전해 상태는 11, 00, 11, 00입니다. 첫 전이부터 정상 카운터의 00에서 01과 달리 00에서 11로 갑니다. 위 비트가 아래 비트와 상관없이 매번 반전하기 때문이며, J1J_1, K1K_1을 Q0Q_0에 이어야 아래 비트가 1일 때만 반전합니다. 입력식에 Q0Q_0이 들어간 이유를 이 오류로 확인할 수 있습니다.

2. 3비트로 늘리기

같은 방법으로 3비트 동기 카운터를 만들면 맨 위 비트 Q2Q_2의 입력 J2J_2, K2K_2는 무엇이 되어야 하나요?

해설 보기

1씩 셀 때 어떤 자리는 그 아래 자리가 모두 1인 다음 순간에만 바뀝니다. 그래서 Q2Q_2는 에지 직전의 Q1Q_1과 Q0Q_0이 모두 1일 때만 반전해야 하므로 J2=K2=Q1Q0J_2=K_2=Q_1Q_0입니다. 이 식으로 000에서 시작해 에지를 이어 가면 1, 2, … , 7을 지나 다시 0으로 돌아옵니다. 일반적으로 k번 비트의 입력은 그 아래 비트를 모두 AND한 값이 됩니다.

3. 리셋이 켜진 에지

정상 입력식을 쓴 카운터가 상태 11에 있을 때 리셋을 켜고 에지를 하나 주면 결과는 무엇인가요? 리셋을 켠 순간에 곧바로 00이 된다고 말해도 되나요?

해설 보기

동기 리셋은 리셋이 카운트보다 먼저이므로 그 에지에서 00이 저장됩니다. 본문 코드의 마지막 줄도 0을 냅니다. 하지만 리셋을 켠 순간에 곧바로 00이 되는 것은 아니고, 다음 에지가 올 때까지는 11이 유지됩니다. 곧바로 00이 되는 것은 비동기 클리어의 동작이므로, 두 방식을 같은 시간표로 설명하면 안 됩니다.

입력식을 설계한 뒤에는 모든 상태에서 다음 상태를 계산해 원하는 순서와 비교하고, 모든 비트를 에지 직전의 값으로 계산했는지 확인해 보세요. 다음 장의 CPU 데이터 경로에서는 레지스터와 선택 회로를 이어 명령어를 실행하는 경로를 만듭니다.