[컴퓨터구조] 3. CPU

2026-01-18

index

이것이 취업을 위한 컴퓨터 과학이다 with CS 기술 면접 책을 읽으면서 배운 점을 정리합니다.

이번 글에서는 개발자가 알아야 할 CPU의 핵심 개념들을 학습합니다. 레지스터의 역할부터 인터럽트 처리 과정, 그리고 CPU 성능 향상을 위한 다양한 설계 기법에 대해 다룹니다.

1️⃣ 레지스터

레지스터는 CPU 안에 있는 작은 임시 저장장치다. 프로그램을 이루는 데이터와 명령어가 실행 전후로 레지스터에 저장되기 때문에 레지스터에 저장된 값만 잘 관찰해도 프로그램이 어떻게 작동하는지 파악할 수 있다.

주요 레지스터의 종류

프로그램 카운터 (Program Counter)

프로그램 카운터는 메모리에서 다음으로 읽어 들일 명령어의 주소를 저장한다.

📍 프로그램 카운터의 동작

  • 일반적으로 1씩 증가하며 다음 명령어 주소를 가리킨다
  • 순차적인 프로그램 실행은 프로그램 카운터가 1씩 증가하기 때문에 가능하다
  • 조건문이나 리턴문 실행 시에는 임의의 위치로 변경된다

명령어 레지스터 (Instruction Register)

명령어 레지스터는 메모리에서 방금 읽어 들인 명령어를 저장한다. 제어장치는 명령어 레지스터 속 명령어를 해석한 뒤 ALU로 하여금 연산하도록 시키거나 다른 부품으로 제어 신호를 보낸다.

범용 레지스터 (General Purpose Register)

범용 레지스터는 다양하고 일반적인 상황에서 자유롭게 사용할 수 있는 레지스터다.

  • 데이터, 명령어, 주소 모두 저장 가능
  • CPU 안에 여러 개 존재
  • 프로그래머가 직접 활용 가능

플래그 레지스터 (Flag Register)

플래그 레지스터연산의 결과 혹은 CPU 상태에 대한 부가 정보를 저장한다. 플래그는 CPU가 명령어를 처리하는 과정에서 반드시 참조해야 할 상태 정보를 의미하는 비트다.

🚩 주요 플래그의 종류

플래그 설명 의미
부호 플래그 연산 결과의 부호 1: 음수, 0: 양수
제로 플래그 연산 결과가 0인지 여부 1: 결과가 0, 0: 결과가 0이 아님
캐리 플래그 올림수나 빌림수 발생 여부 1: 발생, 0: 미발생
오버플로우 플래그 오버플로우 발생 여부 1: 발생, 0: 미발생
인터럽트 플래그 인터럽트 가능 여부 1: 가능, 0: 불가능
슈퍼바이저 플래그 실행 모드 구분 1: 커널 모드, 0: 사용자 모드

스택 포인터 (Stack Pointer)

스택 포인터메모리 내 스택 영역의 최상단 데이터 위치를 가리키는 레지스터다.

🔝 스택 포인터의 역할

  • 마지막으로 스택에 저장된 데이터의 위치를 가리킴
  • 스택이 채워진 정도를 나타냄
  • 데이터를 꺼내면 이전 데이터 위치를 가리키도록 갱신됨
# 스택 포인터 동작 예시
메모리 - 스택 영역
[스택 데이터 1]
[스택 데이터 2]
[스택 데이터 3] ← 스택 포인터

# pop() 후
[스택 데이터 1]
[스택 데이터 2] ← 스택 포인터

2️⃣ 인터럽트

인터럽트는 CPU의 작업을 방해하는 신호를 의미한다. 인터럽트는 크게 동기 인터럽트비동기 인터럽트로 나뉜다.

인터럽트의 분류

🔄 동기 인터럽트 (Synchronous Interrupts)

동기 인터럽트는 CPU에 의해 발생하는 인터럽트다. CPU가 예외적인 상황을 마주쳤을 때 발생하며, 예외(Exception)라고도 부른다.

⚡ 비동기 인터럽트 (Asynchronous Interrupts)

비동기 인터럽트는 주로 입출력장치에 의해 발생하는 인터럽트다. 하드웨어 인터럽트라고도 부른다.

  • 입출력 작업 완료 알림
  • 키보드, 마우스 입력 알림
  • 하드웨어 이벤트 알림

하드웨어 인터럽트

하드웨어 인터럽트는 CPU가 효율적으로 명령어를 처리하기 위해 사용한다. 인터럽트를 사용하지 않는다면 CPU는 입출력장치의 작업 완료 여부를 주기적으로 확인해야 한다(폴링).

💡 폴링(Polling)이란?

폴링은 입출력장치의 상태가 어떤지, 처리할 데이터가 있는지 주기적으로 확인하는 방식이다.

  • CPU 사이클을 낭비함
  • 입출력 완료를 기다리는 동안 다른 작업 불가
  • 인터럽트 방식에 비해 비효율적

하드웨어 인터럽트를 사용하면 CPU는 입출력 작업이 진행되는 동안 다른 작업을 처리할 수 있다.

하드웨어 인터럽트 처리 과정

1️⃣ 인터럽트 요청 신호

입출력장치는 CPU에게 인터럽트 요청(Interrupt Request) 신호를 보낸다.

2️⃣ 인터럽트 여부 확인

CPU는 실행 사이클이 끝나고 명령어를 인출하기 전에 항상 인터럽트 여부를 확인한다.

3️⃣ 인터럽트 플래그 확인

CPU는 플래그 레지스터의 인터럽트 플래그를 통해 현재 인터럽트를 받아들일 수 있는지 확인한다.

  • 인터럽트 플래그가 활성화되어 있어야 인터럽트 수용 가능
  • 일부 인터럽트는 플래그와 무관하게 처리됨 (Non-Maskable Interrupt)

4️⃣ 작업 백업

CPU는 현재까지의 작업을 메모리 내 스택에 백업한다.

백업 내용
- 프로그램 카운터 값
- 레지스터 값들
- 프로그램 재개에 필요한 모든 정보

5️⃣ 인터럽트 서비스 루틴 실행

CPU는 인터럽트 벡터(Interrupt Vector)를 참조하여 해당하는 인터럽트 서비스 루틴(ISR)을 실행한다.

💡 인터럽트 서비스 루틴(ISR)이란?

인터럽트를 처리하기 위한 프로그램으로, 인터럽트 핸들러라고도 부른다.

  • 입출력장치마다 각기 다른 ISR을 가짐
  • 메모리에 여러 개의 ISR이 저장되어 있음
  • 인터럽트 벡터를 통해 적절한 ISR을 찾아 실행함

6️⃣ 작업 복구

ISR 실행이 끝나면 백업해 둔 작업을 복구하여 실행을 재개한다.

인터럽트 처리 흐름

정상 작업 진행
    ↓
인터럽트 발생
    ↓
현재 상태 백업
    ↓
ISR으로 점프
    ↓
ISR 실행
    ↓
백업 상태 복구
    ↓
이전 작업 재개

인터럽트 벡터

인터럽트 벡터는 인터럽트 서비스 루틴을 식별하기 위한 정보다.

  • ISR의 시작 주소를 포함
  • CPU는 인터럽트 벡터를 통해 특정 ISR을 실행
  • 버스를 통해 전달됨
# 인터럽트 벡터 예시
메모리
┌─────────────────────────┐
│ ISR A (키보드)          │ ← 인터럽트 벡터 A
├─────────────────────────┤
│ ISR B (프린터)          │ ← 인터럽트 벡터 B
├─────────────────────────┤
│ ISR C (마우스)          │ ← 인터럽트 벡터 C
└─────────────────────────┘

프린터 인터럽트 발생
→ 인터럽트 벡터 B 전달
→ ISR B의 시작 주소로 점프
→ 프린터 ISR 실행

명령어 사이클과 인터럽트

인터럽트 사이클까지 포함한 명령어 사이클의 전체 흐름은 다음과 같다.

인출 사이클 → (간접 사이클) → 실행 사이클 → 인터럽트 사이클 → 인출 사이클 → ...

예외 (Exception)

예외는 동기 인터럽트로, CPU에 의해 발생한다. 예외의 종류는 다음과 같다.

폴트 (Fault)

폴트는 예외를 처리한 직후에 예외가 발생한 명령어부터 실행을 재개하는 예외다.

📄 페이지 폴트 예시

1. CPU가 명령어 실행 시도
2. 필요한 데이터가 메모리에 없음
3. 폴트 발생
4. 보조기억장치에서 데이터를 메모리로 로드
5. 폴트가 발생한 명령어부터 다시 실행

트랩 (Trap)

트랩은 예외를 처리한 직후에 예외가 발생한 명령어의 다음 명령어부터 실행을 재개하는 예외다.

🐛 브레이크포인트 예시

def calculate():
    x = 10
    y = 20
    # 브레이크포인트 설정 → 트랩 발생
    result = x + y  # 디버깅 후 이 줄부터 실행 재개
    return result

중단 (Abort)

중단은 실행 중인 프로그램을 강제로 중단시킬 수밖에 없는 심각한 오류를 발견했을 때 발생하는 예외다.

소프트웨어 인터럽트

소프트웨어 인터럽트는 시스템 콜이 발생했을 때 발생하는 예외다.

3️⃣ CPU 성능 향상 기법

CPU 클럭 속도

클럭(Clock)은 컴퓨터의 부품을 일사불란하게 움직일 수 있게 하는 시간의 단위다.

⏱️ 클럭의 특징

  • 클럭 주기에 맞춰 데이터 이동 및 연산 수행
  • 클럭 속도는 헤르츠(Hz) 단위로 측정
  • 1초에 몇 번 반복되는지를 나타냄
클럭 속도 = 1초당 클럭 횟수

예시:
- 100Hz = 1초에 100번 클럭
- 1GHz = 1초에 1,000,000,000번 클럭

⚠️ 클럭 속도 향상의 한계

클럭 속도를 높이면 CPU 성능이 향상되지만, 과도하게 높이면 발열 문제가 발생한다. 따라서 클럭 속도만으로는 CPU 성능을 높이는 데 한계가 있다.

멀티코어

코어(Core)는 CPU 내에서 명령어를 읽어 들이고, 해석하고, 실행하는 부품을 의미한다. 여러 개의 코어를 포함하고 있는 CPU를 멀티코어 CPU 또는 멀티코어 프로세서라고 부른다.

멀티스레드

하드웨어 스레드

하드웨어 스레드는 하나의 코어가 동시에 처리하는 명령어의 단위를 의미한다.

1코어 1스레드 CPU
- 한 번에 1개의 명령어 처리

2코어 4스레드 CPU
- 한 번에 4개의 명령어 동시 처리

하드웨어 스레드는 논리 프로세서(Logical Processor)라고도 부른다.

소프트웨어 스레드

소프트웨어 스레드는 하나의 프로그램에서 독립적으로 실행되는 단위를 의미한다.

import threading
import time

def task1():
    for _ in range(5):
        print("Task 1 is running")
        time.sleep(1)

def task2():
    for _ in range(5):
        print("Task 2 is running")
        time.sleep(1)

# 2개의 소프트웨어 스레드 생성
thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)

# 동시 실행
thread1.start()
thread2.start()

thread1.join()
thread2.join()

💡 하드웨어 스레드 vs 소프트웨어 스레드

  • 하드웨어 스레드: 병렬성(Parallelism)을 구현하기 위한 물리적 실행 단위
  • 소프트웨어 스레드: 동시성(Concurrency)을 구현하기 위한 논리적 실행 단위

1코어 1스레드 CPU에서도 여러 소프트웨어 스레드를 실행할 수 있다.

병렬성과 동시성

⚡ 병렬성 (Parallelism)

병렬성은 작업을 물리적으로 동시에 처리하는 성질이다.

병렬성 예시 (4개의 하드웨어 스레드)

시간 →
Task1: ████████████████████████
Task2: ████████████████████████
Task3: ████████████████████████
Task4: ████████████████████████

4개의 작업이 실제로 동시에 실행됨

🔄 동시성 (Concurrency)

동시성은 동시에 작업을 처리하는 것처럼 보이는 성질이다.

동시성 예시 (1개의 하드웨어 스레드)

시간 →
Task1: ███     ███     ███
Task2:    ███     ███     ███
Task3:       ███     ███     ███

빠르게 번갈아가며 실행되어 동시에 실행되는 것처럼 보임

명령어 파이프라이닝

명령어 병렬 처리 기법(Instruction-level Parallelism)은 여러 명령어를 동시에 처리하여 CPU를 한시도 쉬지 않고 작동시키는 기법이다.

파이프라이닝의 원리

하나의 명령어 처리 과정을 여러 단계로 나눌 수 있다.

📊 명령어 처리 단계

  1. 명령어 인출 (Instruction Fetch)
  2. 명령어 해석 (Instruction Decode)
  3. 명령어 실행 (Execute Instruction)
  4. 결과 저장 (Write Back)

같은 단계가 겹치지 않는다면 CPU는 각 단계를 동시에 실행할 수 있다.

CISC vs RISC

CISC (Complex Instruction Set Computer)

CISC는 복잡한 명령어들로 구성된 명령어 집합이다.

🔧 CISC의 특징

  • 다양한 기능을 지원하는 복잡한 명령어
  • 적은 수의 명령어로 프로그램 실행 가능
  • 명령어 크기와 실행 시간이 일정하지 않음
  • 파이프라이닝에 비효율적
CISC 명령어 예시 (x86)
MOVS    ; 메모리 간 데이터 복사
LOOP    ; 반복문 실행
CALL    ; 함수 호출

RISC (Reduced Instruction Set Computer)

RISC는 짧고 규격화된 명령어로 구성된 명령어 집합이다.

⚡ RISC의 특징

  • 단순하고 규격화된 명령어
  • 1클럭 내외로 실행되는 명령어 지향
  • 같은 프로그램이라도 더 많은 명령어 필요
  • 파이프라이닝에 최적화
RISC 명령어 예시 (ARM)
ADD  R1, R2, R3  ; R2 + R3 → R1
LOAD R1, [R2]    ; 메모리 → R1
STORE R1, [R2]   ; R1 → 메모리

💡 CISC vs RISC 비교

특징 CISC RISC
명령어 복잡도 복잡 단순
명령어 개수 적음 많음
실행 시간 불규칙 규칙적
파이프라이닝 비효율적 효율적
대표 CPU Intel x86 ARM, Apple M1

파이프라인 위험 (Pipeline Hazard)

파이프라이닝이 실패하여 성능 향상이 이루어지지 않는 상황을 파이프라인 위험이라고 한다.

데이터 위험 (Data Hazard)

데이터 위험은 명령어 간 데이터 의존성에 의해 발생한다.

명령어 1: R1R2 + R3
명령어 2: R4R1 + R5  // R1에 의존

명령어 2는 명령어 1의 결과를 기다려야 함
→ 파이프라이닝 불가

제어 위험 (Control Hazard)

제어 위험은 프로그램 카운터의 갑작스러운 변화에 의해 발생한다.

# 분기문으로 인한 제어 위험
if condition:
    jump to address  # 프로그램 카운터가 갑자기 변경
                     # 미리 인출한 명령어들이 무용지물이 됨

구조적 위험 (Structural Hazard)

구조적 위험은 서로 다른 명령어가 동시에 같은 CPU 부품을 사용하려고 할 때 발생한다.

명령어 1과 명령어 2가 동시에 ALU를 사용하려고 시도
→ 구조적 위험 발생
→ 한 명령어는 대기해야 함
© 2026, Design & Developed by 정인영