CPU 작동 원리 (연산장치 · 제어장치 · 레지스터)
CPU(중앙처리장치)는 컴퓨터에서 가장 핵심적인 역할을 하는 부분으로, 사람으로 치면 두뇌에 해당합니다. 메모리에서 명령어를 하나씩 꺼내 해석하고 실행하는 일을 아주 빠르게 반복합니다.
한눈에 보기
- CPU는 크게 연산장치, 제어장치, 레지스터 세 가지로 구성됩니다.
- 비유: CPU를 요리사 한 명이 일하는 주방이라고 생각해 보세요.
- 제어장치는 레시피(프로그램)를 한 줄씩 읽고 "다음엔 이걸 해"라고 지휘하는 머리입니다.
- 연산장치는 실제로 썰고 볶는 손입니다.
- 레지스터는 손 바로 옆에 둔 작은 접시들입니다. 냉장고(메모리)까지 가지 않고 바로 집을 수 있어서 가장 빠릅니다.
- CPU가 하는 일은 결국 꺼내 오기(인출) → 해석하기(해독) → 실행하기의 반복입니다.

그림 출처: Wikimedia Commons (CC BY-SA 3.0)
그림처럼 오늘날 대부분의 컴퓨터는 프로그램과 데이터를 같은 메모리에 두고, CPU가 그 메모리에서 명령어를 하나씩 꺼내 실행하는 폰 노이만 구조를 따릅니다. 그림의 Control Unit이 제어장치, Arithmetic/Logic Unit이 연산장치이고, 레지스터는 이 두 장치 안팎에서 값을 잠깐 들고 있습니다.
CPU의 세 가지 구성 요소
연산장치 (ALU)
- 덧셈·뺄셈 같은 산술 연산과 AND·OR·크기 비교 같은 논리 연산을 수행합니다. 그래서 산술논리연산장치(ALU, Arithmetic Logic Unit) 라고도 부릅니다.
- 연산에 필요한 데이터를 레지스터에서 가져오고, 연산 결과를 다시 레지스터로 보냅니다.
제어장치 (Control Unit)
- 명령어를 순서대로 실행할 수 있도록 제어하는 장치입니다.
- 주기억장치에서 프로그램 명령어를 꺼내 해독하고, 그 결과에 따라 명령어 실행에 필요한 제어 신호를 기억장치, 연산장치, 입출력장치로 보냅니다.
- 반대로 이 장치들이 보낸 신호도 받아서, 다음에 무엇을 할지 결정합니다.
레지스터 (Register)
- CPU 안에 있는 아주 빠른 기억장치입니다. 메모리 계층 중 가장 빠르지만 크기는 가장 작습니다.
- 명령어 주소, 명령어 코드, 연산에 필요한 데이터, 연산 결과 등을 임시로 저장합니다.
- 용도에 따라 두 종류로 나뉩니다.
- 범용 레지스터: 연산에 필요한 데이터나 연산 결과를 임시로 저장합니다.
- 특수목적 레지스터: 정해진 특별한 용도로만 쓰는 레지스터입니다.
- CPU 종류에 따라 사용할 수 있는 레지스터의 개수와 크기가 다릅니다. (예: 64비트 CPU의 범용 레지스터는 하나에 64비트)
특수목적 레지스터 중 중요한 것들
| 레지스터 | 이름 | 저장하는 것 | 비유 |
|---|---|---|---|
| PC | 프로그램 카운터 (Program Counter) | 다음에 실행할 명령어의 주소 | 레시피에서 "다음 줄" 위치에 꽂아 둔 책갈피 |
| IR | 명령어 레지스터 (Instruction Register) | 지금 실행 중인 명령어 | 지금 읽고 있는 레시피 한 줄 |
| MAR | 메모리 주소 레지스터 (Memory Address Register) | 읽기·쓰기를 할 주기억장치의 주소 | 냉장고 몇 번 칸인지 적은 메모 |
| MBR | 메모리 버퍼 레지스터 (Memory Buffer Register) | 주기억장치에서 읽어 온 데이터, 또는 저장할 데이터 | 냉장고와 조리대 사이를 오가는 쟁반 |
| AC | 누산기 (Accumulator) | 연산 결과를 임시로 저장 | 계산 중간 결과를 담아 두는 그릇 |
MBR은 MDR(Memory Data Register)이라고도 부릅니다.
CPU의 동작 과정
프로그램 하나가 실행될 때 장치들은 다음 순서로 움직입니다.
- 주기억장치는 입력장치에서 입력받은 데이터, 또는 보조기억장치에 저장된 프로그램을 읽어 옵니다.
- CPU는 프로그램을 실행하기 위해 주기억장치에 저장된 명령어와 데이터를 읽어 와 처리하고, 결과를 다시 주기억장치에 저장합니다.
- 주기억장치는 처리 결과를 보조기억장치에 저장하거나 출력장치로 보냅니다.
- 제어장치는 1~3 과정에서 명령어가 순서대로 실행되도록 각 장치를 제어합니다.
보조기억장치 / 입력장치
│ ①
▼
주기억장치(RAM) ◀──── ② ────▶ CPU (명령어 꺼내 처리, 결과 저장)
│ ③
▼
보조기억장치 / 출력장치
④ 제어장치가 ①~③ 전체의 순서를 지휘장치 사이의 연결 통로(버스)는 컴퓨터의 구성을 참고하세요.
명령어 세트
명령어 세트(Instruction Set) 는 CPU가 실행할 수 있는 명령어의 집합입니다. 명령어 하나는 두 부분으로 이루어집니다.
┌──────────────────────┬──────────────────────────┐
│ 연산 코드 (Opcode) │ 피연산자 (Operand) │
│ 무엇을 할지 │ 무엇을 가지고 / 어디에 │
│ 예: ADD │ 예: 100번지 │
└──────────────────────┴──────────────────────────┘- 연산 코드: 실행할 연산입니다. 연산, 제어(분기), 데이터 전달, 입출력 기능을 가집니다.
- 피연산자: 연산에 필요한 데이터 또는 데이터가 저장된 위치입니다. 주소, 숫자·문자, 논리 데이터 등을 담습니다.
CPU 종류(x86, ARM 등)마다 명령어 세트가 다르기 때문에, 한 CPU용으로 만든 실행 파일은 다른 종류의 CPU에서 바로 돌아가지 않습니다. 이 이야기는 ARM 프로세서에서 이어집니다.
명령어 사이클
CPU는 프로그램을 실행하기 위해 주기억장치에서 명령어를 순서대로 인출하고, 해독하고, 실행하는 과정을 반복합니다.
CPU가 주기억장치에서 명령어 하나를 인출해서 실행하기까지 필요한 일련의 활동을 명령어 사이클(Instruction Cycle) 이라고 합니다. 명령어 사이클은 네 가지로 나뉩니다.
| 사이클 | 하는 일 |
|---|---|
| 인출 사이클 (Fetch) | 주기억장치의 지정된 주소에서 명령어 하나를 가져옴 |
| 간접 사이클 (Indirect) | 피연산자에 데이터의 주소가 아니라 "주소가 적힌 곳의 주소"가 들어 있으면, 실제 주소를 한 번 더 읽어 옴 |
| 실행 사이클 (Execute) | 명령어를 실행함 |
| 인터럽트 사이클 (Interrupt) | 실행 도중 인터럽트 요청이 있었으면 그것을 처리하러 감 (인터럽트 참고) |
명령어 하나의 실행이 끝나면 다음 명령어의 인출 사이클이 다시 시작됩니다. 각 단계에서 레지스터가 어떻게 움직이는지는 명령어 사이클에서 따로 정리합니다.
인출 사이클: 명령어를 꺼내 오는 과정
인출 사이클에서 가장 중요한 부분은 PC 값을 증가시키는 것입니다. 그래야 다음 명령어를 가리킬 수 있습니다.
- PC에 저장된 주소를 MAR로 전달합니다.
- MAR에 담긴 주소를 이용해 주기억장치의 해당 위치에서 명령어를 인출합니다.
- 인출한 명령어를 MBR에 저장합니다.
- 다음 명령어를 인출할 수 있도록 PC 값을 증가시킵니다.
- MBR에 저장된 명령어를 IR(명령어 레지스터)로 전달합니다.
이것을 시간 단계(T0, T1, T2)별 기호로 쓰면 다음과 같습니다. ←는 "오른쪽 값을 왼쪽에 넣는다"는 뜻이고, M[MAR]은 "메모리에서 MAR이 가리키는 주소의 값"입니다.
T0 : MAR ← PC
T1 : MBR ← M[MAR], PC ← PC + 1
T2 : IR ← MBRT1에서 메모리 읽기와 PC 증가가 같이 적혀 있는 것은, 둘이 서로 다른 부품을 쓰기 때문에 같은 박자에 동시에 할 수 있어서입니다. 여기까지가 명령어를 인출하는 과정입니다.
PC ← PC + 1의 +1은 "다음 명령어"라는 뜻입니다. 실제 CPU에서는 명령어 하나의 크기(예: 4바이트)만큼 주소가 증가합니다.
실행 사이클: 명령어별로 실행하는 과정
인출이 끝나면 IR에 명령어가 들어 있는 상태입니다. 이미 인출이 끝났으므로 실행 사이클에서는 PC를 증가시킬 필요가 없습니다. 아래에서 IR(Addr)은 "IR에 든 명령어의 피연산자(주소) 부분"입니다.
ADD addr: 더하기
메모리 addr 번지의 값을 AC에 더합니다.
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC ← AC + MBR데이터를 MBR까지 가져왔으면, AC에 MBR 값을 더하기만 하면 됩니다.
LOAD addr: 불러오기
기억장치에 있는 데이터를 AC로 옮기는 명령어입니다.
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC ← MBRSTA addr: 저장하기
AC에 있는 데이터를 기억장치에 저장하는 명령어입니다. (STA = STore Accumulator)
T0 : MAR ← IR(Addr)
T1 : MBR ← AC
T2 : M[MAR] ← MBRJUMP addr: 건너뛰기
PC 값을 IR의 주소값으로 바꾸는 분기 명령어입니다. 다음 인출 사이클이 addr 번지에서 시작되므로, 프로그램의 실행 흐름이 그곳으로 건너뜁니다. 반복문이나 if 문이 이런 분기 명령어로 만들어집니다.
T0 : PC ← IR(Addr)코드로 따라가 보기
위 과정을 Python으로 흉내 내 보겠습니다. 7과 5를 더해서 12번지에 저장하는 프로그램입니다.
# 아주 단순한 누산기(AC) 방식 CPU 흉내 내기
# 메모리 0~3번지: 명령어, 10~12번지: 데이터
memory = {
0: ('LOAD', 10), # AC ← M[10]
1: ('ADD', 11), # AC ← AC + M[11]
2: ('STA', 12), # M[12] ← AC
3: ('HALT', None),
10: 7,
11: 5,
12: 0,
}
PC, AC = 0, 0
while True:
# 인출 사이클
MAR = PC # T0: MAR ← PC
MBR = memory[MAR] # T1: MBR ← M[MAR]
PC = PC + 1 # PC ← PC + 1
IR = MBR # T2: IR ← MBR
op, addr = IR
if op == 'HALT':
break
# 실행 사이클
if op == 'LOAD':
MAR = addr; MBR = memory[MAR]; AC = MBR
elif op == 'ADD':
MAR = addr; MBR = memory[MAR]; AC = AC + MBR
elif op == 'STA':
MAR = addr; MBR = AC; memory[MAR] = MBR
elif op == 'JUMP':
PC = addr
print(f'{op:4} {addr} -> AC={AC}, PC={PC}')
print('12번지 값:', memory[12])실행 결과:
LOAD 10 -> AC=7, PC=1
ADD 11 -> AC=12, PC=2
STA 12 -> AC=12, PC=3
12번지 값: 12명령어 하나가 끝날 때마다 PC가 1씩 늘어나며 다음 명령어를 가리키는 것을 볼 수 있습니다. 실제 CPU는 이 과정을 1초에 수십억 번 반복합니다. 운영체제가 여러 프로그램에 이 CPU 시간을 어떻게 나눠 주는지는 CPU 분석에서 다룹니다.
정리
| 개념 | 비전공자 버전 요약 |
|---|---|
| CPU | 명령어를 꺼내 해석하고 실행하는 컴퓨터의 두뇌 |
| 연산장치 (ALU) | 계산과 비교를 실제로 하는 손 |
| 제어장치 | 레시피를 읽고 순서를 지휘하는 머리 |
| 레지스터 | CPU 안의 가장 빠르고 작은 임시 접시 |
| PC | 다음에 실행할 명령어 위치를 가리키는 책갈피 |
| IR | 지금 실행 중인 명령어 |
| MAR / MBR | 메모리의 "몇 번지"와 "오가는 데이터"를 잠깐 담는 칸 |
| AC | 계산 결과를 담아 두는 그릇 |
| 명령어 | 연산 코드(무엇을) + 피연산자(무엇을 가지고/어디에) |
| 명령어 사이클 | 인출 → (간접) → 실행 → (인터럽트) 를 계속 반복 |
