
이 장의 가장 큰 흐름은 다음과 같다.
수와 코드 → 논리 게이트 → Flip-Flop → Register → Bus → Register 간 데이터 전송
처음에는 각각 별개의 내용처럼 보이지만, 결국 컴퓨터가 0과 1을 어떻게 표현하고, 계산하고, 기억하고, 이동시키는가를 배우는 과정이다.
컴퓨터 내부의 전기회로에서는 두 가지 상태를 구분하기 쉽다.
예를 들어 전압의 높고 낮음을 추상화해서 다음과 같이 표현할 수 있다.
낮은 전압 → 0
높은 전압 → 1
즉, 실제 컴퓨터 내부에서는 전기 신호가 흐르고 있지만 이를 논리적으로는 0과 1이라는 두 값으로 생각한다.
이것이 컴퓨터에서 2진수(Binary)가 자연스럽게 사용되는 이유다.
우리가 평소 사용하는 숫자는 10진수다.
예를 들어 다음 숫자를 보자.
3025.37
우리는 그냥 삼천이십오 점 삼칠이라고 읽지만, 실제로 각 자리에는 서로 다른 가중치(Weight)가 존재한다.
숫자 3 0 2 5 . 3 7
Weight 10³ 10² 10¹ 10⁰ 10⁻¹ 10⁻²
따라서 3025.37은 실제로 다음과 같다.
3025.37
= 3 × 10³
+ 0 × 10²
+ 2 × 10¹
+ 5 × 10⁰
+ 3 × 10⁻¹
+ 7 × 10⁻²
계산하면
= 3000 + 0 + 20 + 5 + 0.3 + 0.07
= 3025.37
즉,
숫자의 실제 값 = 각 자리의 숫자 × 그 자리의 Weight를 모두 더한 것
이라고 생각하면 된다.
10진수에서는 Weight가 다음과 같다.
..., 10³, 10², 10¹, 10⁰, 10⁻¹, 10⁻², ...
2진수에서는 다음과 같다.
..., 2³, 2², 2¹, 2⁰, 2⁻¹, 2⁻², ...
5진수에서는 다음과 같다.
..., 5³, 5², 5¹, 5⁰, 5⁻¹, 5⁻², ...
따라서 이를 일반적인 R진법으로 표현하면
..., R³, R², R¹, R⁰, R⁻¹, R⁻², ...
이 된다.
수학적으로는 다음과 같이 표현한다.
V(N) \= \sum A_kR\^k
여기서
R : 몇 진법인지 나타내는 밑(Base, Radix)A_k : 각 자리에 들어있는 숫자R^k : 해당 자리의 Weight이다.
그리고 R진수에서 사용할 수 있는 숫자는
0 ~ R-1
이다.
2진수에서는
0, 1
만 사용할 수 있다.
5진수에서는
0, 1, 2, 3, 4
만 사용할 수 있다.
16진수에서는 총 16개의 기호가 필요하므로
0 1 2 3 4 5 6 7 8 9 A B C D E F
를 사용한다.
(1234.2)₅(1234.2)₅는 5진수다.
5진수이므로 각 자리의 Weight는 5의 거듭제곱이다.
숫자 1 2 3 4 . 2
Weight 5³ 5² 5¹ 5⁰ 5⁻¹
따라서
(1234.2)₅
= 1 × 5³
+ 2 × 5²
+ 3 × 5¹
+ 4 × 5⁰
+ 2 × 5⁻¹
계산하면
= 125 + 50 + 15 + 4 + 0.4
= 194.4
따라서
(1234.2)₅ = (194.4)₁₀
이다.
5진수에서는 한 자리에 5 이상이 올 수 없다.
(1234)₅ → 가능
(1254)₅ → 불가능
왜냐하면 사용할 수 있는 숫자가
0, 1, 2, 3, 4
뿐이기 때문이다.
(1011.1)₂이번에는 2진수다.
각 자리의 Weight를 적어보면
숫자 1 0 1 1 . 1
Weight 2³ 2² 2¹ 2⁰ 2⁻¹
따라서
(1011.1)₂
= 1 × 2³
+ 0 × 2²
+ 1 × 2¹
+ 1 × 2⁰
+ 1 × 2⁻¹
계산하면
= 8 + 0 + 2 + 1 + 0.5
= 11.5
따라서
(1011.1)₂ = (11.5)₁₀
이다.
2진수이기 때문에 각 자리에는 반드시
0 또는 1
만 올 수 있다.
시험 중요
특히 10진수 ↔ 2진수 ↔ 8진수 ↔ 16진수 변환은 직접 할 수 있어야 한다.
10진수를 R진수로 변환할 때는 정수와 소수의 방법이 다르다.
정수 부분 → R로 계속 나눈다.
소수 부분 → R을 계속 곱한다.
27.625₁₀ → 2진수먼저 정수와 소수 부분을 분리한다.
27.625
정수 부분 : 27
소수 부분 : 0.625
27을 2진수로 바꾸려면 계속 2로 나눈다.
27 ÷ 2 = 13 ... 1
13 ÷ 2 = 6 ... 1
6 ÷ 2 = 3 ... 0
3 ÷ 2 = 1 ... 1
1 ÷ 2 = 0 ... 1
나머지를 아래에서 위로 읽는다.
11011
따라서
27₁₀ = 11011₂
이다.
우리가 실제로 찾고 싶은 것은 다음 네모 안의 숫자다.
27 =
□ × 2⁴
+ □ × 2³
+ □ × 2²
+ □ × 2¹
+ □ × 2⁰
이를 변수로 표현하면
27 =
a₄ × 2⁴
+ a₃ × 2³
+ a₂ × 2²
+ a₁ × 2¹
+ a₀ × 2⁰
이다.
2진수이므로 각 a에는
0 또는 1
만 들어간다.
27을 직접 2의 거듭제곱으로 표현하면
27 = 16 + 8 + 2 + 1
= 1 × 2⁴
+ 1 × 2³
+ 0 × 2²
+ 1 × 2¹
+ 1 × 2⁰
따라서
11011₂
이다.
즉, Weight를 직접 보고 구해도 된다.
하지만 숫자가 커지면 불편하기 때문에 2로 계속 나누는 방법을 사용한다.
27을 2로 나누면
27 = 2 × 13 + 1
이다.
마지막 1은 바로 2⁰ 자리에 들어갈 값이다.
다시 13을 2로 나누면
13 = 2 × 6 + 1
이때 나온 나머지는 2¹ 자리의 값이 된다.
즉 나머지가
2⁰ → 2¹ → 2² → ...
순서로 나오기 때문에 마지막에는 거꾸로 읽는 것이다.
이번에는
0.625
를 2진수로 바꿔보자.
소수는 반대로 2를 계속 곱한다.
0.625 × 2 = 1.25
↑
1
정수 부분 1을 가져온다.
소수 부분 0.25만 남겨 다시 2를 곱한다.
0.25 × 2 = 0.5
↑
0
다시
0.5 × 2 = 1.0
↑
1
이번에는 정수 부분을 위에서 아래로 읽는다.
101
따라서
0.625₁₀ = 0.101₂
이다.
정수와 합치면
27.625₁₀ = 11011.101₂
가 된다.
우리가 찾고 싶은 것은
0.625 =
□ × 2⁻¹
+ □ × 2⁻²
+ □ × 2⁻³
+ ...
이다.
이를
0.625 =
a₋₁ × 2⁻¹
+ a₋₂ × 2⁻²
+ a₋₃ × 2⁻³
+ ...
라고 하자.
양쪽에 2를 곱하면
1.25 =
a₋₁ × 2⁰
+ a₋₂ × 2⁻¹
+ a₋₃ × 2⁻²
+ ...
가 된다.
여기서 a₋₁ × 2⁰가 정수 부분으로 튀어나온다.
실제로
0.625 × 2 = 1.25
에서 정수 부분이 1이다.
따라서 첫 번째 소수 자리인 2⁻¹ 자리에는 1이 들어간다는 것을 알 수 있다.
다시 소수 부분 0.25에 2를 곱하면 다음 자리인 2⁻²를 알아낼 수 있다.
그래서
정수 → 나누기
소수 → 곱하기
를 사용하는 것이다.
12.25₁₀ → 2진수12 ÷ 2 = 6 ... 0
6 ÷ 2 = 3 ... 0
3 ÷ 2 = 1 ... 1
1 ÷ 2 = 0 ... 1
아래에서 위로 읽으면
1100
이다.
0.25 × 2 = 0.5 → 0
0.5 × 2 = 1.0 → 1
따라서
0.01
이다.
최종적으로
12.25₁₀ = 1100.01₂
이다.
검산하면
1100.01₂
= 1×2³ + 1×2² + 1×2⁻²
= 8 + 4 + 0.25
= 12.25
이다.
3/163/16 = 0.1875
그런데 16 = 2⁴이므로 더 쉽게 생각할 수 있다.
3/16
= 2/16 + 1/16
= 1/8 + 1/16
= 2⁻³ + 2⁻⁴
따라서
0.0011₂
이다.
1/3소수 부분 변환법을 사용한다.
1/3 × 2 = 2/3
정수 부분 → 0
다시
2/3 × 2 = 4/3 = 1 + 1/3
정수 부분 → 1
다시 1/3이 등장한다.
따라서 같은 과정이 무한 반복된다.
0.010101010101...
즉
1/3 = 0.010101...₂
이다.
01이 계속 반복된다.
이런 경우 반복되는 부분 위에 선이나 점을 표시하여 순환한다는 것을 나타낼 수 있다.
숫자의 자릿수를 알아낼 때 로그를 사용할 수 있다.
예를 들어
3205
는 몇 자리인가?
다음 관계가 성립한다.
1000 ≤ 3205 < 10000
이를 10의 거듭제곱으로 쓰면
10³ ≤ 3205 < 10⁴
이다.
양쪽에 log₁₀을 취하면
3 ≤ log₁₀(3205) < 4
이다.
따라서 log₁₀(3205)의 정수 부분은 3이다.
여기에 1을 더하면
3 + 1 = 4자리
가 된다.
따라서 일반적으로
10진수 N의 자릿수
= floor(log₁₀N) + 1
이다.
2진수에서는 밑을 2로 바꾸면 된다.
2진수 N의 자릿수
= floor(log₂N) + 1
1000₁₀은 2진수에서 몇 자리인가?
2의 거듭제곱을 비교한다.
2⁹ = 512
2¹⁰ = 1024
따라서
512 ≤ 1000 < 1024
즉
2⁹ ≤ 1000 < 2¹⁰
이므로 필요한 자릿수는
10자리
이다.
다음 관계를 반드시 기억한다.
8 = 2³
16 = 2⁴
따라서
2진수 3자리 ↔ 8진수 1자리
2진수 4자리 ↔ 16진수 1자리
로 정확하게 대응한다.
각 8진수 숫자를 2진수 3자리로 바꾸면 된다.
0 → 000
1 → 001
2 → 010
3 → 011
4 → 100
5 → 101
6 → 110
7 → 111
(523.25)₈각 숫자를 3bit로 바꾼다.
5 → 101
2 → 010
3 → 011
.
2 → 010
5 → 101
따라서
(523.25)₈
=
(101_010_011.010_101)₂
이다.
여기서 _는 숫자를 읽기 쉽게 구분하기 위한 것이다.
101010011
과
101_010_011
은 같은 값이다.
16진수는 총 16개의 숫자가 필요하다.
하지만 숫자 기호는 0~9까지밖에 없기 때문에 이후에는 알파벳을 사용한다.
10진수 16진수
0 0
1 1
...
9 9
10 A
11 B
12 C
13 D
14 E
15 F
그 다음 숫자는
10₁₆
이다.
주의해야 한다.
10₁₆ = 16₁₀
이다.
16은
16 = 2⁴
이므로 16진수 한 자리는 정확히 4bit와 대응한다.
0 → 0000
1 → 0001
...
A → 1010
B → 1011
C → 1100
D → 1101
E → 1110
F → 1111
(D1AF)₁₆ → 8진수바로 16진수에서 8진수로 바꾸려고 하지 말고
16진수 → 2진수 → 8진수
순서로 바꾸면 쉽다.
먼저
D → 1101
1 → 0001
A → 1010
F → 1111
따라서
D1AF₁₆
=
1101 0001 1010 1111₂
이제 8진수는 3bit씩 묶으면 된다.
오른쪽부터 3개씩 묶는다.
1 | 101 | 000 | 110 | 101 | 111
맨 앞은 3bit가 되도록 0을 붙여도 된다.
001 | 101 | 000 | 110 | 101 | 111
각각 8진수로 변환하면
001 → 1
101 → 5
000 → 0
110 → 6
101 → 5
111 → 7
따라서
(D1AF)₁₆ = (150657)₈
이다.
1111을 어떻게 보는가?여기서 매우 중요한 개념이 있다.
1111
이라는 bit가 있다고 하자.
우리는 이것을 보고
2진수 1111 = 15
라고 생각할 수 있다.
하지만 컴퓨터 내부의 bit 자체에는 '15'라는 의미가 들어있는 것이 아니다.
1111이라는 bit pattern을 어떤 규칙으로 해석하느냐에 따라 의미가 달라질 수 있다.
예를 들어
1111
은 상황에 따라
등으로 사용될 수 있다.
즉,
컴퓨터 내부에는 결국 0과 1만 존재하고, 그 0과 1을 어떤 의미로 해석할지는 규칙에 의해 결정된다.
이 개념은 앞으로 컴퓨터구조를 이해할 때 매우 중요하다.
컴퓨터 내부에서는 실제로 2진수로 데이터를 처리한다.
그런데 2진수는 사람이 읽기에 너무 길다.
예를 들어
11111110110111001011101010011000
보다
FEDCBA98
처럼 16진수로 표현하는 것이 훨씬 읽기 쉽다.
왜 16진수를 사용하냐면
16진수 1자리 = 2진수 4자리
로 정확히 대응하기 때문이다.
그래서 메모리 주소나 기계어 등을 사람이 볼 때 16진수를 많이 사용한다.
BCD는
Binary Coded Decimal
의 약자다.
말 그대로 10진수의 각 자릿수를 이진 코드로 표현하는 방법이다.
예를 들어
59
가 있다고 하자.
59라는 값 전체를 2진수로 바꾼다.
59₁₀ = 111011₂
59를
5
9
라는 두 개의 10진수 숫자로 따로 본다.
그리고 각각을 4bit로 바꾼다.
5 → 0101
9 → 1001
따라서
59 → 0101 1001
이 된다.
즉 BCD에서는
10진수 숫자 하나하나를 숫자의 값 전체가 아니라 하나의 기호처럼 따로 코드화한다.
라고 이해하면 된다.
기본 단위는 반드시 기억한다.
1 bit = 0 또는 1 하나
그리고
1 Byte = 8 bit
이다.
일반적으로
b = bit
B = Byte
라고 쓴다.
따라서
1B = 8b
이다.
컴퓨터는 문자도 결국 0과 1로 저장해야 한다.
예를 들어 사람이
A
라고 입력했다고 하자.
컴퓨터가 문자 A 자체를 저장하는 것이 아니라, A에 해당하는 숫자 코드를 저장한다.
ASCII에서는
A = 65
로 약속되어 있다.
65를 2진수로 표현하면
1000001
이다.
따라서
A → 1000001
로 표현할 수 있다.
b6 b5 b4 b3 b2 b1 b0는 무엇인가?각 bit의 자리 이름이다.
b6 b5 b4 b3 b2 b1 b0
각 자리의 Weight는
2⁶ 2⁵ 2⁴ 2³ 2² 2¹ 2⁰
이다.
A의 코드인 1000001을 넣으면
b6 b5 b4 b3 b2 b1 b0
1 0 0 0 0 0 1
이다.
따라서
1 × 2⁶ + 1 × 2⁰
= 64 + 1
= 65
가 된다.
그래서 ASCII 코드 65가 A다.
예를 들어
good morning
이라는 문자열도 컴퓨터 내부에서는
g → 문자 코드
o → 문자 코드
o → 문자 코드
d → 문자 코드
공백 → 문자 코드
m → 문자 코드
...
처럼 문자 하나하나가 숫자로 저장된다.
즉 컴퓨터 입장에서는 문자열도 결국 bit들의 집합이다.
ASCII만으로는 영어 중심의 제한된 문자만 표현할 수 있다.
한글, 일본어, 중국어 등 세계의 다양한 문자를 표현하기 위해 훨씬 큰 문자 체계가 필요하다.
그래서 Unicode가 사용된다.
현재 단계에서는
Unicode = 세계 여러 문자를 하나의 문자 코드 체계로 표현하기 위한 표준
정도로 이해하면 충분하다.
디지털 회로는 크게 두 종류로 생각할 수 있다.
현재 입력만 보고 현재 출력이 결정된다.
현재 입력
↓
조합 논리회로
↓
현재 출력
과거에 어떤 값이 들어왔는지는 중요하지 않다.
프로그래밍으로 비유하면 상태가 없는 함수와 비슷하다.
현재 입력뿐만 아니라 이전에 저장되어 있던 상태도 출력에 영향을 준다.
현재 입력 ─┐
↓
순차 논리회로 → 출력
↑
이전 상태
즉 기억 능력이 있다.
논리 게이트는 0과 1을 입력받아 특정 규칙에 따라 0 또는 1을 출력하는 가장 기본적인 회로다.
두 입력이 모두 1일 때만 1이다.
A B | Y
---------
0 0 | 0
0 1 | 0
1 0 | 0
1 1 | 1
프로그래밍으로 생각하면
A && B
와 비슷하다.
하나라도 1이면 1이다.
A B | Y
---------
0 0 | 0
0 1 | 1
1 0 | 1
1 1 | 1
두 값이 서로 다르면 1이다.
A B | Y
---------
0 0 | 0
0 1 | 1
1 0 | 1
1 1 | 0
즉
같으면 0
다르면 1
이다.
입력을 반대로 만든다.
A | Y
------
0 | 1
1 | 0
AND의 결과를 NOT한다.
NAND = NOT(AND)
따라서
A B | Y
---------
0 0 | 1
0 1 | 1
1 0 | 1
1 1 | 0
이다.
OR의 결과를 NOT한다.
NOR = NOT(OR)
XOR의 결과를 NOT한다.
따라서 두 값이 같으면 1이다.
A B | Y
---------
0 0 | 1
0 1 | 0
1 0 | 0
1 1 | 1
입력을 그대로 출력한다.
0 → 0
1 → 1
논리적으로 아무것도 하지 않는 것처럼 보이지만, 실제 회로에서는 신호 전달이나 회로 분리 등에 사용한다.
뒤에서 배우는 3-State Buffer가 Bus를 구성할 때 매우 중요하다.
일반적으로
높은 전압 → 논리 1
낮은 전압 → 논리 0
으로 해석한다.
반대로
높은 전압 → 논리 0
낮은 전압 → 논리 1
로 해석한다.
중요한 것은 실제 전기 신호가 바뀌는 것이 아니라 그 신호에 어떤 논리적 의미를 부여하느냐가 달라지는 것이다.
순차 논리회로는 값을 기억할 수 있다.
그중 동기식 순차 논리회로는 Clock이라는 공통 신호에 맞춰 상태가 변한다.
Clock은 여러 회로에게
지금 값을 받아!
지금 상태를 바꿔!
라고 알려주는 공통 박자라고 생각하면 된다.
Flip-Flop은 1bit의 데이터를 저장하는 기억 소자다.
이 문장은 반드시 기억한다.
Flip-Flop 1개 → 1bit 저장
예를 들어 Flip-Flop의 출력 Q가
Q = 1
이라면 현재 1이라는 1bit 정보를 기억하고 있는 것이다.
Flip-Flop 그림에는 일반적으로 두 개의 출력이 있다.
Q
Q̅
Q는 정상 출력이다.
Q̅는 Q의 반대 값이다.
Q = 0 → Q̅ = 1
Q = 1 → Q̅ = 0
이다.
Clock은 다음과 같이 0과 1을 반복하는 신호다.
┌─────┐ ┌─────┐
───────┘ └───────┘ └──────
↑ ↓ ↑ ↓
Clock이
0 → 1
로 변하는 순간을 상승 에지(Rising Edge, Positive Edge)라고 한다.
↑
______|‾‾‾‾‾
반대로
1 → 0
로 변하는 순간은 하강 에지(Falling Edge, Negative Edge)다.
‾‾‾‾‾|______
↓
Flip-Flop은 Clock의 특정 순간(edge)에 반응한다.
예를 들어 Positive Edge Triggered Flip-Flop이라면
Clock 0 → 1
이 되는 바로 그 순간에 입력을 확인한다.
따라서 앞으로 타이밍 다이어그램을 볼 때 가장 먼저 해야 하는 것은
1. Clock을 찾는다.
2. 상승 에지 ↑를 모두 표시한다.
3. 각 ↑ 순간의 입력을 확인한다.
4. Flip-Flop의 규칙에 따라 Q를 결정한다.
이다.
이것이 순차 논리회로의 그림을 읽는 가장 중요한 방법이다.
둘 다 데이터를 기억할 수 있지만 언제 입력에 반응하는가가 다르다.
특정 레벨(Level)이 유지되는 동안 입력에 반응한다.
예를 들어 Enable이 1인 동안 입력이 바뀌면 출력도 영향을 받을 수 있다.
따라서
Latch → Level Sensitive
이다.
Clock의 특정 Edge 순간에만 입력을 받아들인다.
따라서
Flip-Flop → Edge Sensitive
이다.
Latch = Level Sensitive
Flip-Flop = Edge Sensitive
Flip-Flop이 Clock의 상승 에지에서 D 값을 읽는다고 하자.
그런데 Clock이 올라가는 정확한 순간에 D가 계속 변하고 있다면 안정적으로 값을 읽기 어렵다.
그래서 입력이 일정 시간 동안 안정되어 있어야 한다.
Clock edge가 발생하기 이전에 입력값이 미리 안정되어 있어야 하는 최소 시간이다.
Clock ↑
│
D ───────────────1────────────
<-------->
Setup Time
즉
"Clock이 올라오기 직전에는 D를 바꾸지 마라."
라고 생각하면 된다.
Clock edge가 발생한 이후에도 입력을 일정 시간 유지해야 한다.
Clock ↑
│
D ───────────────1────────────
<------->
Hold Time
즉
"Clock이 올라간 직후에도 바로 D를 바꾸지 마라."
라는 의미다.
Clock edge가 발생했다고 해서 출력 Q가 물리적으로 0초 만에 변하는 것은 아니다.
실제 회로이기 때문에 약간의 시간이 필요하다.
Clock ↑
│
│ Delay
└────────→ Q 변화
이를 Propagation Delay라고 한다.
일반적으로 Delay가 작으면 더 빠르게 동작할 수 있다.
실제 부품을 선택할 때 Datasheet를 보고
등을 확인할 수 있다.
가장 이해하기 쉬운 Flip-Flop이다.
규칙은 하나다.
Clock의 유효 Edge 순간의 D 값을 Q에 저장한다.
즉
Clock ↑일 때
Q ← D
이다.
현재
Q = 0
이라고 하자.
Clock 상승 에지 순간에
D = 1
이라면
Q ← 1
이 된다.
그 이후 D가 다시 0으로 바뀌더라도 다음 Clock 상승 에지가 오기 전까지 Q는 계속 1을 유지한다.
D 0 ---- 1 ---- 0 --------
↑
Clock ----------|---------------
↑
이 순간 D=1
Q 0 -------1---------------
즉 D의 값이 Q로 전달되지만 Clock에 맞춰 저장된다.
S는 Set, R은 Reset이다.
S = Set → Q를 1로
R = Reset → Q를 0으로
따라서 기본적으로
S=1 → Q=1
R=1 → Q=0
라고 이해하면 된다.
JK Flip-Flop은 다음 표를 기억해야 한다.
J K | 다음 Q
----------------
0 0 | 현재 값 유지
0 1 | 0
1 0 | 1
1 1 | 현재 Q 반전
즉
J=0, K=0
→ 아무것도 하지 않는다.
J=0, K=1
→ Q를 0으로 만든다.
J=1, K=0
→ Q를 1로 만든다.
J=1, K=1
→ Q를 반대로 바꾼다.
마지막 11이 특히 중요하다.
현재
Q=0
이면
Q=1
로 바뀌고,
현재
Q=1
이면
Q=0
으로 바뀐다.
이를 Toggle이라고 한다.
T Flip-Flop은 더 간단하다.
T | 다음 Q
-------------
0 | 현재 Q 유지
1 | 현재 Q 반전
즉
T=0 → Q
T=1 → Q̅
이다.
그래서 Counter 같은 회로를 만들 때 유용하다.
이 부분은 Q 출력 파형을 직접 그리는 문제가 나올 수 있다.
그림을 볼 때 절대 모든 선을 한 번에 보려고 하지 않는다.
다음 순서대로 본다.
↑ ↑ ↑ ↑
Clock __|‾|_____|‾|_____|‾|_____|‾
Positive Edge Triggered JK FF라면 이 순간만 보면 된다.
예를 들어 첫 번째 상승 에지에서
J=1
K=0
이라면 JK 표에서
10 → Q=1
이다.
Clock 중간에 J와 K가 변해도 Q가 바로 변하는 것이 아니다.
다음 상승 에지가 올 때까지 현재 값을 유지한다.
초기 상태가
Q=0
이라고 하자.
각 상승 에지에서 J,K가 다음과 같다고 하자.
첫 번째 ↑ : J=1, K=0
두 번째 ↑ : J=0, K=0
세 번째 ↑ : J=1, K=1
네 번째 ↑ : J=0, K=1
하나씩 계산한다.
J=1, K=0
→ Set
→ Q=1
J=0, K=0
→ 유지
→ Q=1
J=1, K=1
→ 반전
→ Q=0
J=0, K=1
→ Reset
→ Q=0
따라서 Q는
초기 0
→ 1
→ 1
→ 0
→ 0
으로 변한다.
앞으로 Flip-Flop 파형 문제를 보면 무조건 다음 순서로 푼다.
① Clock을 찾는다.
② 유효 Edge를 표시한다.
Positive → ↑
Negative → ↓
③ 해당 순간의 입력을 읽는다.
④ Flip-Flop의 동작표를 적용한다.
⑤ 다음 Edge까지 Q를 유지한다.
이것만 기억하면 된다.
Flip-Flop 하나는
1bit
를 저장한다.
그렇다면 4bit 데이터를 저장하려면 Flip-Flop이 몇 개 필요할까?
4개
이다.
예를 들어
[D FF] → 1bit
[D FF] → 1bit
[D FF] → 1bit
[D FF] → 1bit
이렇게 4개를 묶으면 4bit Register가 된다.
따라서
Register = 여러 개의 Flip-Flop을 묶어 여러 bit의 데이터를 저장하는 장치
라고 이해하면 된다.
4bit Register를 예로 들면
Input
D3 D2 D1 D0
│ │ │ │
▼ ▼ ▼ ▼
[FF][FF][FF][FF]
│ │ │ │
▼ ▼ ▼ ▼
Q3 Q2 Q1 Q0
Output
이다.
D는 입력,
Q는 현재 Register에 저장되어 있는 출력이다.
예를 들어
D = 1011
이고 저장 조건이 만족되면
Q ← 1011
이 된다.
Register 그림에는 데이터 이외에도
Clear
Enable
Clock
같은 신호가 존재한다.
이들은 저장하려는 데이터 자체가 아니다.
Register에게
초기화해라.
저장을 허용해라.
지금 저장해라.
와 같은 명령을 내린다.
그래서 Control Signal(제어 신호)이라고 한다.
/Clear : Low Active그림에서
/Clear
처럼 /가 붙어 있다면 일반적으로 Low Active라는 뜻이다.
즉 0일 때 기능이 작동한다.
/Clear = 0 → Clear 작동
/Clear = 1 → Clear 작동하지 않음
Clear가 작동하면
Q = 0000
으로 초기화한다.
Enable은 일반적으로
Enable = 1 → 동작 허용
Enable = 0 → 현재 상태 유지
이다.
즉 1일 때 기능이 활성화되므로 High Active다.
교수님 설명에서 Clear가 가장 강한 신호라고 이해하면 된다.
예를 들어 다음 표를 생각해보자.
/Clear | Enable | Clock | 결과
--------------------------------
0 | X | X | Q=0
1 | 0 | X | Q 유지
1 | 1 | ↑ | Q ← D
여기서 X는
Don't Care
라는 뜻이다.
즉 0이든 1이든 상관없다.
/Clear = 0
이면 다른 신호는 볼 필요가 없다.
Q = 0000
이 된다.
따라서 Clear가 가장 우선순위가 높다.
/Clear = 1
Enable = 0
이면 Clear는 작동하지 않지만 Enable이 꺼져 있다.
따라서
Q 유지
이다.
/Clear = 1
Enable = 1
Clock ↑
이면 입력 D를 저장한다.
Q ← D
이다.
Clear가 비동기(Asynchronous)라면 Clock을 기다리지 않는다.
/Clear : 1 → 0
이 되는 순간
Q=0000
이 된다.
반면 일반적인 데이터 적재는
Clock ↑
를 기다린다.
따라서 동기식(Synchronous)이다.
이 그래프는 시험에서 매우 중요할 가능성이 있다.
그래프에
Clear
Enable
Clock
D
Q
가 있다고 하자.
한 번에 다 보지 않는다.
다음 순서대로 본다.
/Clear = 0
이면 즉시
Q=0000
이다.
다른 신호는 무시한다.
Enable=0
이면
Q 유지
이다.
Clock ↑
인 순간의 D를 읽는다.
예를 들어
D=0011
이라면
Q ← 0011
이다.
D가 중간에
0011
→ 1010
→ 1111
→ 0101
처럼 계속 변해도 Clock 상승 에지가 없다면 Q는 바뀌지 않는다.
이것이 동기 적재(Synchronous Load)다.
Shift Register는 Register에 저장된 bit들을 Clock에 맞춰 한 칸씩 이동시키는 Register다.
예를 들어
SI → [FF0] → [FF1] → [FF2] → [FF3]
│ │ │ │
Q0 Q1 Q2 Q3
와 같은 구조가 있다고 하자.
SI는
Serial Input
즉 직렬 입력이다.
예를 들어 1100이라는 4bit 데이터를 보내고 싶다고 하자.
병렬 전송이라면
1 1 0 0
↓ ↓ ↓ ↓
4bit를 동시에 보낸다.
직렬 전송은
1 → 1 → 0 → 0
처럼 한 번에 1bit씩 보낸다.
초기값을
0000
이라고 하자.
SI로 데이터를 하나씩 입력한다.
예를 들어 회로의 이동 방향이 다음과 같다고 하자.
SI → Q0 → Q1 → Q2 → Q3
Clock이 한 번 상승할 때마다 한 칸씩 이동한다.
예를 들어 SI에 차례대로
1, 1, 0, 0
을 넣으면 각 Clock마다 저장된 값이 이동한다.
중요한 것은 정확한 숫자의 좌우 방향을 무작정 외우는 것이 아니다.
자료의 화살표를 보고 SI가 어느 Flip-Flop에 들어가고, 각 Q가 다음 어느 D로 연결되는지를 확인해야 한다.
핵심 원리는
Clock ↑
→ 모든 bit가 동시에 한 칸 이동
이다.
SI에서는 한 번에 1bit만 들어온다.
SI
1
↓
다음 Clock
1
↓
다음 Clock
0
↓
다음 Clock
0
그런데 충분한 Clock이 지난 후 Register의
Q3 Q2 Q1 Q0
를 동시에 읽으면 4bit를 한 번에 얻을 수 있다.
즉
Serial Input
↓
Shift Register
↓
Parallel Output
이 가능하다.
그래서 Shift Register를 직렬 데이터를 병렬 데이터로 변환하는 데 사용할 수 있다.
일반 Shift Register가 한 방향으로만 이동한다면 양방향 Shift Register는
왼쪽 Shift ←
오른쪽 Shift →
둘 다 가능하다.
어느 방향으로 이동할지는 Control Signal이 결정한다.
자료에서는 S1, S0 같은 선택 신호의 조합에 따라 동작을 선택한다.
예를 들어 구조적으로는
S1 S0 | 동작
---------------------
0 0 | 현재 값 유지
0 1 | 오른쪽 Shift
1 0 | 왼쪽 Shift
1 1 | 병렬 Load
와 같이 여러 기능 중 하나를 선택하는 형태로 이해하면 된다.
정확한
S1,S0조합은 수업 자료의 표를 기준으로 외우고, 핵심은 제어 신호 조합으로 Register가 수행할 동작을 선택한다는 것이다.
Counter는
정해진 순서대로 상태를 반복적으로 변화시키는 Register의 일종
이다.
예를 들어 4bit 이진 Counter는 다음처럼 상태가 변할 수 있다.
0000 → 0
0001 → 1
0010 → 2
0011 → 3
0100 → 4
...
1110 → 14
1111 → 15
0000 → 0
...
즉
0 → 1 → 2 → ... → 15 → 0 → ...
을 계속 반복한다.
자료의 원형 그림에서
0000 → 0001 → 0010 → ... → 1111
↑ ↓
└────────────────────────────┘
처럼 연결되어 있는 이유가 이것이다.
마지막 상태가 끝나면 다시 처음 상태로 돌아간다.
4bit Counter를
Q3 Q2 Q1 Q0
라고 하자.
숫자를 하나씩 증가시키면
0 = 0000
1 = 0001
2 = 0010
3 = 0011
4 = 0100
5 = 0101
6 = 0110
7 = 0111
8 = 1000
...
이 된다.
따라서 가장 낮은 자리 Q0는 매번 바뀐다.
Q0 : 0 1 0 1 0 1 0 1 ...
Q1은 두 번마다 바뀐다.
Q1 : 0 0 1 1 0 0 1 1 ...
Q2는 네 번마다 바뀐다.
Q2 : 0 0 0 0 1 1 1 1 ...
Q3는 여덟 번마다 바뀐다.
Q3 : 0 0 0 0 0 0 0 0 1 1 1 1 ...
따라서 각 출력의 주파수도 계속 절반으로 줄어든다.
일반 Counter는
Q ← Q + 1
을 반복한다.
하지만 병렬 적재 기능이 있다면 원하는 초기값을 한 번에 넣을 수도 있다.
예를 들어
D = 1010
이고 Load가 활성화되어 있다면
Q ← 1010
으로 값을 넣을 수 있다.
그 후 Counter를 동작시키면
1010
1011
1100
1101
...
처럼 카운트할 수 있다.
즉 각 제어 신호의 역할을 다음처럼 생각하면 된다.
Clear → 0으로 초기화
Load → D값을 Q에 적재
Enable → Counting 허용
Clock → 실제 상태가 변하는 시점
이제 지금까지 배운 Register들을 서로 연결한다.
CPU 내부에는 수많은 Register가 존재한다.
그리고 Register 사이에서 데이터를 이동시키고 연산해야 한다.
마이크로오퍼레이션(Microoperation)은
컴퓨터 내부에서 Register에 저장된 데이터에 대해 수행되는 기본적인 작은 동작
이라고 이해하면 된다.
예를 들어
R2 ← R1
은 R1의 값을 R2로 전달하는 동작이다.
또
R3 ← R1 + R2
는 R1과 R2를 더해서 R3에 저장하는 동작이다.
다음 표현을 보자.
R2 ← R1
프로그래밍으로 비유하면
R2 = R1;
과 비슷하다.
화살표는 오른쪽에서 왼쪽으로 데이터가 이동한다고 읽는다.
R1 ───────→ R2
주의할 점은 R1의 데이터가 사라지는 것이 아니다.
복사된다.
예를 들어
R1 = 1010
R2 = 0000
에서
R2 ← R1
을 수행하면
R1 = 1010
R2 = 1010
이 된다.
4/ 표시는 무엇인가?회로 그림의 선 옆에
4/
처럼 적혀 있다면 그 선이 하나의 bit가 아니라 4bit를 동시에 전달하는 선 묶음이라는 의미다.
즉
────── 4/ ──────
는 실제로는
bit 0 ─────────
bit 1 ─────────
bit 2 ─────────
bit 3 ─────────
네 개의 선을 간단하게 표현한 것이다.
두 Register가 같은 Clock을 사용하면 같은 시간 기준으로 동작할 수 있다.
즉
Clock ↑
라는 공통 시점을 기준으로 데이터를 전달하고 저장한다.
이를 통해 여러 Register의 동작을 동기화할 수 있다.
T1 : R2 ← R1이 표현을 해석해보자.
T1 : R2 ← R1
은
T1이라는 제어 시점에 R1의 데이터를 R2에 저장한다.
라는 뜻이다.
예를 들어 현재
R1의 Q = 1100
이라고 하자.
R1의 출력이 R2의 입력 D에 연결되어 있다.
R1 Q ─────────→ R2 D
T1이 활성화되면 R2의 Enable이 활성화된다.
하지만 바로 Q2가 바뀌는 것은 아니다.
R2가 상승 에지 Flip-Flop으로 구성되어 있다면
Clock ↑
를 기다린다.
Clock이 올라가는 순간
R2 ← R1
이 이루어진다.
따라서
R2 = 1100
이 된다.
이 부분에서 가장 중요한 개념은
Enable은 저장할 준비를 시키고, 실제 저장은 Clock Edge에서 일어난다.
는 것이다.
순서를 보면
① R1에 데이터가 존재한다.
② T1이 활성화된다.
③ T1에 의해 R2 Enable이 활성화된다.
④ R1의 Q가 R2의 D에 들어와 있다.
⑤ Clock ↑
⑥ R2가 D를 저장한다.
⑦ 약간의 Delay 후 Q2에서 새로운 값이 나타난다.
이다.
그래서 타이밍 그래프에서 계속 Clock이 올라가는 순간을 보는 것이다.
이번에는 단순히 데이터를 복사하는 것이 아니라 계산한다.
예를 들어
R2 ← R1 + R0
을 수행한다고 하자.
이때 중간에 ALU가 사용된다.
ALU는
Arithmetic Logic Unit
의 약자다.
우리말로 산술 논리 연산 장치다.
다음과 같은 계산을 수행한다.
덧셈
뺄셈
AND
OR
XOR
...
중요한 점은
ALU는 기본적으로 조합 논리회로다.
즉 ALU 자체가 결과를 기억하는 것이 아니다.
입력이 들어오면 입력에 따라 결과가 만들어진다.
구조를 단순하게 보면
R1 ─────┐
↓
ALU ─────→ R2
↑
R0 ─────┘
이다.
예를 들어
R1 = 0101
R0 = 0011
이면 ALU에서
0101
+0011
-----
1000
을 계산한다.
ALU는 조합 논리회로이기 때문에 입력이 들어오면 약간의 전파 지연 후 결과가 출력된다.
그 결과가 R2의 D 입력에 도착한다.
그 후
R2 Enable = 1
Clock ↑
이면
R2 ← 1000
이 된다.
즉 CPU 내부에서 매우 자주 등장하는 구조가
Register
↓
ALU
↓
Register
이다.
Register가 두 개뿐이라면 서로 직접 연결할 수 있다.
하지만 CPU 안에 Register가
R0
R1
R2
R3
R4
...
처럼 많이 존재한다고 하자.
모든 Register를 서로 직접 연결하면 선이 너무 많아진다.
그래서 여러 Register가 하나의 공통 데이터 통로를 공유한다.
이 공통 데이터 선을 Bus라고 한다.
Bus = 여러 Register 또는 장치가 공유하는 데이터 전송 통로
예를 들어
R0 → R1
R0 → R2
R0 → R3
R1 → R0
R1 → R2
R1 → R3
...
를 전부 별도 선으로 연결하면 회로가 매우 복잡해진다.
대신
R0 ─┐
R1 ─┤
R2 ─┼──── BUS ────→ Register들
R3 ─┘
처럼 공용 도로 하나를 만든다.
한 순간에 하나의 Register만 Bus에 데이터를 출력해야 한다.
왜냐하면 R0가 Bus에
1010
을 출력하고 있는데 동시에 R1이
0101
을 출력하려고 하면 같은 선에서 충돌하기 때문이다.
따라서
한 순간 → 하나의 Source만 Bus 사용
이 원칙이 중요하다.
여기서 3-State Buffer가 사용된다.
일반적인 논리 신호는
0
1
두 가지라고 배웠다.
그런데 3-State Buffer에는 세 번째 상태가 있다.
0
1
Z
여기서 Z가
High Impedance
상태다.
쉽게 말하면
"나는 지금 이 선에서 빠져 있을게."
라는 상태다.
예를 들어 R0, R1, R2가 같은 Bus에 연결되어 있다고 하자.
현재 R1의 값을 Bus에 출력하고 싶다.
그러면
R0 → Z
R1 → 1010
R2 → Z
로 만든다.
그러면 Bus에는
1010
만 나타난다.
R0와 R2도 물리적으로 Bus에 연결되어 있지만 High-Z 상태이므로 Bus를 구동하지 않는다.
따라서 여러 장치가 하나의 Bus를 공유할 수 있다.
예를 들어
R2 ← R0
을 Bus를 통해 수행한다고 하자.
순서는 다음과 같다.
① R0의 3-State Buffer 활성화
② R0의 Q가 Bus에 나타남
③ 다른 Register의 출력은 High-Z
④ Bus의 값이 R2의 D에 도착
⑤ R2 Enable 활성화
⑥ Clock ↑
⑦ R2가 Bus의 값을 저장
⑧ R2의 Q에서 새로운 값 출력
그림으로 보면
R0
│
▼
3-State Buffer
│
▼
BUS ─────────→ D of R2
│
Clock ↑
│
▼
Q2
이다.
이제 Bus와 ALU를 결합한다.
자료에는
ABus
BBus
가 등장한다.
처음 보면 Bus가 왜 두 개나 있는지 헷갈린다.
이유는 간단하다.
ALU는 보통 두 개의 입력을 받아 연산해야 하기 때문이다.
예를 들어
R3 ← R1 + R2
를 계산하고 싶다.
R1과 R2 두 값이 동시에 ALU에 들어가야 한다.
따라서
R1 → ABus
R2 → BBus
로 보낸다.
그림으로 표현하면
R1 ─────→ ABus ─────┐
│
▼
┌─────┐
│ ALU │ ─────→ Result Bus
└─────┘
▲
│
R2 ─────→ BBus ─────┘
이다.
현재
R1 = 0011
R2 = 0101
이라고 하자.
다음 연산을 수행한다.
R3 ← R1 + R2
먼저
ABus = 0011
BBus = 0101
이 된다.
ALU가 덧셈을 수행한다.
0011
0101
----
1000
따라서 Result Bus에는
1000
이 나타난다.
R3 Enable이 활성화되어 있고 Clock이 상승하면
R3 ← 1000
이 된다.
복잡해 보여도 다음 순서만 보면 된다.
어떤 Register가 ABus를 사용하고 있는가?
예를 들어
R1 → ABus
라면
ABus = Q1
이다.
예를 들어
R2 → BBus
라면
BBus = Q2
이다.
예를 들어 Add라면
Result = ABus + BBus
이다.
예를 들어
R3 Enable = 1
인지 확인한다.
Clock ↑
순간 Result Bus의 값을 R3가 저장한다.
따라서
R3 ← Result
가 된다.
Source Register A
↓
ABus ─────┐
│
▼
ALU
▲
│
BBus ─────┘
↑
Source Register B
↓
Result Bus
↓
Destination Register
↓
Clock ↑
↓
저장
이 구조를 머릿속에 넣으면 된다.
복잡한 회로의 동작을 매번 그림으로 그리기 어렵다.
그래서 Register 사이의 데이터 이동과 연산을 간단한 기호로 표현한다.
예를 들어
R1
R2
PC
MAR
AC
등은 Register를 의미한다.
←R2 ← R1
은
R1의 내용을 R2로 전송한다.
라는 뜻이다.
프로그래밍의 대입과 비슷하다.
R3 ← R1 + R2
은
R1과 R2를 더한 결과를 R3에 저장한다.
라는 뜻이다.
:다음 표현을 보자.
T1 : R2 ← R1
이는
T1이라는 제어 조건/시점에 R1의 값을 R2에 전달한다.
라는 뜻이다.
즉
조건 : 수행할 Microoperation
형태다.
T3 : AC ← AC + MAR
은
T3 시점에 AC와 MAR의 값을 더해서 그 결과를 AC에 저장한다.
라는 뜻이다.
이 장의 내용은 사실 전부 하나로 연결되어 있다.
컴퓨터
│
▼
모든 정보는 0과 1
│
├──────────────────┐
▼ ▼
계산해야 함 기억해야 함
│ │
▼ ▼
논리 게이트 Flip-Flop
│ │
▼ ▼
조합 논리회로 Register
│ │
│ ├── Shift Register
│ └── Counter
│
└─────────┬────────┘
▼
Bus
│
┌────┴────┐
▼ ▼
ABus BBus
│ │
└────┬────┘
▼
ALU
│
▼
Result Bus
│
▼
Register
예를 들어 CPU가 다음 동작을 수행한다고 하자.
R3 ← R1 + R2
이 짧은 표현 안에 지금까지 배운 내용이 거의 전부 들어있다.
R1은 여러 개의 Flip-Flop으로 이루어진 Register다.
R1 = 0011
이라는 값을 기억하고 있다.
R2 역시 Register다.
R2 = 0101
을 기억하고 있다.
제어 회로가 R1을 ABus에 출력하도록 한다.
ABus = 0011
R2를 BBus에 출력한다.
BBus = 0101
ALU가 두 값을 더한다.
0011 + 0101 = 1000
ALU 결과가 Result Bus를 통해 R3의 D 입력으로 전달된다.
D3 = 1000
R3의 Enable을 활성화한다.
Clock 상승 에지가 발생한다.
Clock ↑
R3가 D 값을 저장한다.
R3 ← 1000
이제 R3의 Q 출력은
1000
이다.
조합 논리회로와 순차 논리회로의 차이를 생각하면 된다.
ALU 같은 조합 논리회로는 입력이 바뀌면 출력도 바뀐다.
입력 변화
↓
ALU 계산
↓
출력 변화
반면 Register는 아무 때나 값을 저장하면 안 된다.
D가 바뀜
→ 아직 저장 안 함
D가 또 바뀜
→ 아직 저장 안 함
Clock ↑
→ 바로 이 순간의 D를 저장
즉 Clock을 이용해서
"지금 계산 결과를 확정해서 저장해."
라는 시점을 정해주는 것이다.
그래서 타이밍 다이어그램 문제에서 Clock의 상승 에지가 가장 중요한 기준점이 된다.
반드시 할 수 있어야 한다.
10진수 → 2진수
정수 : 2로 나누고 나머지를 아래에서 위로
소수 : 2를 곱하고 정수 부분을 위에서 아래로
그리고
2진수 3bit ↔ 8진수 1자리
2진수 4bit ↔ 16진수 1자리
를 기억한다.
Flip-Flop = 1bit 저장
Clock ↑ → Q ← D
J K | 다음 Q
---------------
0 0 | 유지
0 1 | 0
1 0 | 1
1 1 | 반전
T=0 → 유지
T=1 → 반전
Latch → Level Sensitive
Flip-Flop → Edge Sensitive
무조건
① Clock 찾기
② 유효 Edge 찾기
③ 그 순간 입력 확인
④ 동작표 적용
⑤ Q 결정
⑥ 다음 Edge까지 Q 유지
순서로 푼다.
Flip-Flop 여러 개
↓
Register
4bit Register라면 기본적으로 4개의 1bit 저장 요소가 필요하다.
/Clear=0
→ 즉시 초기화
/Clear=1, Enable=0
→ 유지
/Clear=1, Enable=1, Clock ↑
→ Q ← D
Clock ↑
→ bit가 한 칸 이동
직렬 입력을 받아 여러 Q를 통해 병렬 데이터로 사용할 수 있다.
0000
0001
0010
0011
...
1111
0000
처럼 정해진 상태를 반복한다.
R2 ← R1
은
R1의 데이터를 R2에 복사
한다는 뜻이다.
Bus = 여러 Register가 공유하는 데이터 통로
가장 중요한 규칙:
한 순간에는 하나의 Source만 Bus를 구동해야 한다.
Z = High Impedance
는
Bus에 연결되어 있지만 현재는 Bus를 구동하지 않는 상태
라고 이해한다.
ALU가 두 개의 입력을 필요로 하기 때문에 존재한다.
Register A → ABus ─┐
▼
ALU → Result
▲
Register B → BBus ─┘
자료의 파형 그림이 나오면 전체를 한 번에 해석하려고 하지 않는다.
예를 들어 다음 신호들이 있다고 하자.
Clear
Enable
Clock
D
Q
반드시 다음 순서로 본다.
1. Clear가 작동하고 있는가?
YES → Q 초기화
NO → 다음으로
2. Enable이 활성화되어 있는가?
NO → Q 유지
YES → 다음으로
3. Clock의 유효 Edge인가?
NO → Q 유지
YES → D 확인
4. 그 순간 D가 무엇인가?
Q ← D
5. 다음 유효 Edge까지 Q 유지
JK Flip-Flop도 똑같다.
1. Clock ↑를 찾는다.
2. 그 순간 J와 K를 읽는다.
3. JK 표를 적용한다.
4. Q를 결정한다.
5. 다음 ↑까지 유지한다.
Register 전송도 똑같다.
1. Source Register는 누구인가?
2. Bus에 어떤 값이 올라왔는가?
3. Destination Register는 누구인가?
4. Destination Enable이 켜져 있는가?
5. Clock ↑인가?
6. 그렇다면 Destination에 저장
Bus 연산도 똑같다.
1. ABus에는 누가 올라왔는가?
2. BBus에는 누가 올라왔는가?
3. ALU가 무슨 연산을 하는가?
4. 결과는 무엇인가?
5. 어느 Register가 결과를 받을 것인가?
6. Clock ↑에서 저장
결국 Chapter 2 후반부의 그림은 전부
"어떤 데이터가 어디에 있고 → 어떤 제어 신호가 활성화되고 → Clock의 어느 순간에 → 어디로 저장되는가?"
를 읽는 문제라고 생각하면 된다.