Skip to content

CPU 작동 원리 (연산장치 · 제어장치 · 레지스터) ​

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의 동작 과정 ​

프로그램 하나가 실행될 때 장치들은 다음 순서로 움직입니다.

  1. 주기억장치는 입력장치에서 입력받은 데이터, 또는 보조기억장치에 저장된 프로그램을 읽어 옵니다.
  2. CPU는 프로그램을 실행하기 위해 주기억장치에 저장된 명령어와 데이터를 읽어 와 처리하고, 결과를 다시 주기억장치에 저장합니다.
  3. 주기억장치는 처리 결과를 보조기억장치에 저장하거나 출력장치로 보냅니다.
  4. 제어장치는 1~3 과정에서 명령어가 순서대로 실행되도록 각 장치를 제어합니다.
text
보조기억장치 / 입력장치
        │ ①
        ▼
   주기억장치(RAM) ◀──── ② ────▶ CPU (명령어 꺼내 처리, 결과 저장)
        │ ③
        ▼
보조기억장치 / 출력장치

④ 제어장치가 ①~③ 전체의 순서를 지휘

장치 사이의 연결 통로(버스)는 컴퓨터의 구성을 참고하세요.

명령어 세트 ​

명령어 세트(Instruction Set) 는 CPU가 실행할 수 있는 명령어의 집합입니다. 명령어 하나는 두 부분으로 이루어집니다.

text
┌──────────────────────┬──────────────────────────┐
│ 연산 코드 (Opcode)   │ 피연산자 (Operand)        │
│ 무엇을 할지          │ 무엇을 가지고 / 어디에     │
│ 예: ADD              │ 예: 100번지               │
└──────────────────────┴──────────────────────────┘
  • 연산 코드: 실행할 연산입니다. 연산, 제어(분기), 데이터 전달, 입출력 기능을 가집니다.
  • 피연산자: 연산에 필요한 데이터 또는 데이터가 저장된 위치입니다. 주소, 숫자·문자, 논리 데이터 등을 담습니다.

CPU 종류(x86, ARM 등)마다 명령어 세트가 다르기 때문에, 한 CPU용으로 만든 실행 파일은 다른 종류의 CPU에서 바로 돌아가지 않습니다. 이 이야기는 ARM 프로세서에서 이어집니다.

명령어 사이클 ​

CPU는 프로그램을 실행하기 위해 주기억장치에서 명령어를 순서대로 인출하고, 해독하고, 실행하는 과정을 반복합니다.

CPU가 주기억장치에서 명령어 하나를 인출해서 실행하기까지 필요한 일련의 활동을 명령어 사이클(Instruction Cycle) 이라고 합니다. 명령어 사이클은 네 가지로 나뉩니다.

사이클하는 일
인출 사이클 (Fetch)주기억장치의 지정된 주소에서 명령어 하나를 가져옴
간접 사이클 (Indirect)피연산자에 데이터의 주소가 아니라 "주소가 적힌 곳의 주소"가 들어 있으면, 실제 주소를 한 번 더 읽어 옴
실행 사이클 (Execute)명령어를 실행함
인터럽트 사이클 (Interrupt)실행 도중 인터럽트 요청이 있었으면 그것을 처리하러 감 (인터럽트 참고)

명령어 하나의 실행이 끝나면 다음 명령어의 인출 사이클이 다시 시작됩니다. 각 단계에서 레지스터가 어떻게 움직이는지는 명령어 사이클에서 따로 정리합니다.

인출 사이클: 명령어를 꺼내 오는 과정 ​

인출 사이클에서 가장 중요한 부분은 PC 값을 증가시키는 것입니다. 그래야 다음 명령어를 가리킬 수 있습니다.

  1. PC에 저장된 주소를 MAR로 전달합니다.
  2. MAR에 담긴 주소를 이용해 주기억장치의 해당 위치에서 명령어를 인출합니다.
  3. 인출한 명령어를 MBR에 저장합니다.
  4. 다음 명령어를 인출할 수 있도록 PC 값을 증가시킵니다.
  5. MBR에 저장된 명령어를 IR(명령어 레지스터)로 전달합니다.

이것을 시간 단계(T0, T1, T2)별 기호로 쓰면 다음과 같습니다. ←는 "오른쪽 값을 왼쪽에 넣는다"는 뜻이고, M[MAR]은 "메모리에서 MAR이 가리키는 주소의 값"입니다.

text
T0 : MAR ← PC
T1 : MBR ← M[MAR],  PC ← PC + 1
T2 : IR  ← MBR

T1에서 메모리 읽기와 PC 증가가 같이 적혀 있는 것은, 둘이 서로 다른 부품을 쓰기 때문에 같은 박자에 동시에 할 수 있어서입니다. 여기까지가 명령어를 인출하는 과정입니다.

PC ← PC + 1의 +1은 "다음 명령어"라는 뜻입니다. 실제 CPU에서는 명령어 하나의 크기(예: 4바이트)만큼 주소가 증가합니다.

실행 사이클: 명령어별로 실행하는 과정 ​

인출이 끝나면 IR에 명령어가 들어 있는 상태입니다. 이미 인출이 끝났으므로 실행 사이클에서는 PC를 증가시킬 필요가 없습니다. 아래에서 IR(Addr)은 "IR에 든 명령어의 피연산자(주소) 부분"입니다.

ADD addr: 더하기 ​

메모리 addr 번지의 값을 AC에 더합니다.

text
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC  ← AC + MBR

데이터를 MBR까지 가져왔으면, AC에 MBR 값을 더하기만 하면 됩니다.

LOAD addr: 불러오기 ​

기억장치에 있는 데이터를 AC로 옮기는 명령어입니다.

text
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC  ← MBR

STA addr: 저장하기 ​

AC에 있는 데이터를 기억장치에 저장하는 명령어입니다. (STA = STore Accumulator)

text
T0 : MAR    ← IR(Addr)
T1 : MBR    ← AC
T2 : M[MAR] ← MBR

JUMP addr: 건너뛰기 ​

PC 값을 IR의 주소값으로 바꾸는 분기 명령어입니다. 다음 인출 사이클이 addr 번지에서 시작되므로, 프로그램의 실행 흐름이 그곳으로 건너뜁니다. 반복문이나 if 문이 이런 분기 명령어로 만들어집니다.

text
T0 : PC ← IR(Addr)

코드로 따라가 보기 ​

위 과정을 Python으로 흉내 내 보겠습니다. 7과 5를 더해서 12번지에 저장하는 프로그램입니다.

python
# 아주 단순한 누산기(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])

실행 결과:

text
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계산 결과를 담아 두는 그릇
명령어연산 코드(무엇을) + 피연산자(무엇을 가지고/어디에)
명령어 사이클인출 → (간접) → 실행 → (인터럽트) 를 계속 반복