본문 바로가기
CS 공부/컴퓨터 구조, 운영체제

컴퓨터 구조(4) - CPU의 작동원리

by 프롭 2026. 1. 29.

 

ALU와 제어장치

 

ALU

ALU가 받아 들이는 정보를 알아보자.

ALU가 계산을 하기 위해서는 피연산자와 수행할 연산이 필요하다. 그래서 ALU는 레지스터를 통해 피연산자를 받아들이고, 제어장치로부터 수행할 연산을 알려주는 제어 신호를 받아들인다. 이렇게 받아들인 피연산자와 제어 신호로 산술 연산, 논리 연산 등 다양한 연상을 수행한다.

 

ALU가 내보내는 정보를 알아보자.

연산을 수행한 결과는 특정 숫자나 문자가 될 수도 있고, 메모리 주소가 될 수도 있다. CPU의 접근을 더 빠르게 하기위해서 연산 결과는 우선 메모리가 아닌 레지스터에 저장된다.

 

ALU가 내보내는 또 다른 정보로 계산 결과와 더불어 플래그를 내보낸다. 이진수만 봐서는 음수, 양수 판단이 어려워 이를 위해 플래그를 사용한다 했었다. 그리고 연산 결과가 이 결과를 담을 레지스터보다 클 경우 결과값이 너무 크다라는 추가 정보가 필요하다. 이처럼 연산 결과에 대한 추가적인 정보를 내보내야할 때 사용한다.

 

플래그들은 플래그 레지스터에 저장된다. 이 레지스터를 읽음으로써 추가적인 참고 정보를 얻을 수 있다.

 

대표적인 플래그로는 다음과 같다.

  1. 부호 플래그 : 연산 결과의 부호를 나타낸다. / 1일 경우 음수, 0일 경우 양수를 의미한다
  2. 제로 플래그 : 연산 결과가 0인지 나타낸다. / 제로 플래그가 1일 경우 0, 0일 경우 0이 아님을 의미한다.
  3. 캐리 플래그 : 연산 결과가 올림, 빌림이 발생했는지 나타낸다. / 1일 경우 발생 했음, 0일 경우 아님을 의미한다.
  4. 오버플로우 플래그 : 오버플로우가 발생했는지를 나타낸다. / 1일 경우 발생 했음, 0일 경우 아님을 의미한다.
  5. 인터럽트 플래그 : 인터럽트가 가능한지를 나타낸다. / 1일 경우 가능함을, 0일 경우 아님을 의미한다.
  6. 슈퍼바이저 플래그 : 커널 모드인지 사용자 모드인지 나타낸다. / 1일 경우 커널 모드, 0일 경우 사용자 모드로 실행 중임을 의미한다.

 

제어장치

제어장치는 제어 신호를 내보내고, 명령어를 해석하는 부품이다. 그리고 제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호이다. cpu 제조사마다 제어장치의 구현 방식이나 명령어를 해석하는 방식, 받아들이고 내보내는 정보에는 조금씩 차이가 있다.

 

제어장치가 받아들이는 정보를 알아보자.

 

첫째, 제어장치는 클럭 신호를 받아들인다.

클럭이란 컴퓨터의 모든 부품을 움직일 수 있게하는 시간 단위이다. 클럭의 주기에 맞춰 데이터가 이동되거나, 연산이 수행되거나, 메모리에 저장된 명령어를 읽어 들인다. 그러나 컴퓨터의 모든 부품이 한 클럭마다 작동한다 이해하면 안되고 하나의 명령어가 여러 클럭에 걸쳐 실행될 수 있음을 알아야 한다.

 

둘째, 제어장치는 명령어를 받아들인다.

CPU가 해석 할 명령어는 명령어 레지스터에 저장된다. 제어장치는 명령어 레지스터로 부터 해석할 명령어를 받아들이고 해석 해 제어 신호를 컴퓨터 부품들에 보낸다.

 

셋째, 제어장치는 플래그 레지스터 속 플래그 값을 받아들인다.

플래그는 ALU 연산에 대한 추가 상태 정보라 했다. 제어장치는 플래그 값을 받아들이고 이름 참고하여 제어 신호를 발생 시킨다.

 

넷째, 제어장치는 시스템 버스, 그중 제어 버스로 전달된 제어 신호를 받아들인다.

제어 신호는 CPU뿐만 아니라 입출력 장치를 비롯한 외부 장치도 발생시킬 수 있다. 제어장치는 제어 버스를 통해 외부로부터 전달된 제어 신호를 받아들이기도 한다.

 

제어장치가 내보내는 정보를 알아보자.

여기에는 크게 CPU 외부에 전달하는 제어 신호와 내부에 전달하는 제어 신호가 있다. 이때 외부에 제어 신호를 전달한다는 말은 제어 버스로 제어 신호를 내보낸다는 말과 같다. 이러한 제어 신호는 크게 메모리에 전달하는 제어 신호입출력 장치에 전달하는 제어 신호가 있다.

내부에 전달하는 제어 신호에는 크게 ALU에 전달하는 제어 신호레지스터에 전달하는 제어 신호가 있다.

 

레지스터

프로그램 속 명령어와 데이터는 실행 전후로 반드시 레지스터에 저장된다. 그렇기에 레지스터에 저장된 값만 잘 관찰해도 프로그램의 실행 흐름을 파악할 수 있다.

 

주요 레지스터는 다음과 같다.

1. 프로그램 카운터 2. 명령어 레지스터 3. 메모리 주소 레지스터 4. 메모리 버퍼 레지스터

5. 플래그 레지스터 6. 범용 레지스터 7. 스택 포인터 8. 베이스 레지스터

네 번째 메모리 버퍼 레지스터까지 우선 알아보자.

 

1. 프로그램 카운터(명령어 포인터)

프로그램 카운터는 메모리에 가져올 명령어의 주소, 즉 메모리에 읽어 들일 명령어의 주소를 저장한다.

 

2. 명령어 레지스터

명령어 레지스터는 해석할 명령어, 즉 메모리에서 읽어 들인 명령어를 저장한다. 제어장치는 명령어 레지스터 속 명령어를 받아들이고 이를 해석해 제어 신호를 내보낸다.

 

3. 메모리 주소 레지스터

메모리 주소 레지스터는 메모리의 주소를 저장하는 레지스터이다. CPU가 읽어 들이고자 하는 주소 값을 주소 버스로 보낼 때 메모리 주소 레지스터를 거친다.

 

4. 메모리 버퍼 레지스터

메모리 버퍼 레지스터는 메모리와 주고받을 값을 저장하는 레지스터이다. CPU가 주소 버스로 내보낼 값이 메모리 레지스터를 거친다면, 데이터 버스로 주고 받을 값은 메모리 버퍼 레지스터를 거친다.

 

프로그램 카운터가 꾸준히 증가하여 순차적으로 메모리속 프로그램을 읽어 드려 실행해가는 구조이다. 하지만 종종 프로그램 카운터 실행 중 다음 번지 주소가 아닌 전혀 다른 값으로 업데이트 되는 경우도 있는데 이는 특정 메모리 주소 실행 흐름을 이동하는 명령어가 실행되었을 때 나타난다. 또한 인터럽트가 발생해도 순차적인 실행 흐름이 끊긴다.

 

5. 범용 레지스터

범용 레지스터는 이름과 같이 다양한 상황에서 자유롭게 사용 가능한 레지스터이다. 범용 레지스터는 데이터와 주소를 모두 저장할 수 있다. 일반적으로 CPU 안에는 여러개의 범용 레지스터들이 있다.

 

6. 플래그 레지스터

플래그 레지스터는 앞서 설명 한 것과 같이 연산 결과 또는 CPU 상태에 대한 부가적인 정보를 저장하는 레지스터이다.

 

여기서 앞에서 설명하지 못한 추가적인 주소 지정 방식을 알아보려한다. 프로그램 카운터, 스택 포인터, 베이스 레지스터는 주소 지정에 사용될 수 있는 특별한 레지스터다. 스택 포인터는 스택 주소 지정 방식에 사용되고, 프로그램 카운터와 베이스 레지스터는 변위 주소 지정 방식에 사용된다.

 

스택 주소 지정 방식

스택 주소 지정 방식은 스택 포인터를 이용한 주소 지정 방식이다. 스택은 후에 자료구조 파트에서 자세히 설명하겠다. 스택은 가장 최근에 저장한 값부터 꺼낼 수 있는데 여기서 스택 포인터는 스택의 꼭대기를 가리키는 레지스터다. 쉽게 말해 스택 포인터는 스택의 어디까지 데이터가 채워져 있는지에 대한 표시다. 스택은 메모리 안에 있다. 정확히는 메모리 안에 스택처럼 사용할 영역이 정해져 있다.

 

변위 주소 지정 방식

앞에서 연산 코드와 오퍼랜드를 설명했었다. 오퍼랜드 필드에는 메모리의 주소가 담길 때도 있다했는데 변위 주소 지정 방식이 오퍼랜드 필드의 값과 특정 레지스터의 값을 더하여 유효 주소를 얻어내는 주소 지정 방식이다. 그래서 변위 주소 지정 방식을 사용하는 명령어는 연산 코드 필드, 레지스터 필드, 오퍼랜드 필드가 있다.이때 오퍼랜드 필드의 주소와 어떤 레지스터를 더하는지에 따라 상대 주소 지정 방식, 베이스터 레지스터 주소 지정 방식 등으로 나뉜다.

 

  • 상대 주소 지정 방식

상대 주소 지정 방식은 오퍼랜드와 프로그램 카운터의 값을 더하여 유효 주소를 얻는 방식이다. 분기하여 특정 주소 실행할 때 사용된다.

 

  • 베이스 레지스터 주소 지정 방식

베이스 레지스터 주소 지정 방식은 오퍼랜드와 베이스 레지스터의 값을 더하여 유효 주소를 얻는 방식이다.

여기서 베이스 레지스터는 '기준 주소', 오퍼랜드는 '기준 주소로부터 떨어진 거리'이다. 즉, 베이스 레지스터 속 기준 주소로부터 얼마나 떨어진 주소에 접근할 것인지 연산하여 주소를 얻는 방식이다.

 

명령어 사이클과 인터럽트

 

명령어 사이클

실행하는 프로그램은 수많은 명령어로 이루어져 있고, CPU는 이 명령어들을 하나씩 실행한다. 이때 프로그램 속 각각의 명령어들은 일정한 주기가 반복되며 실행되는데, 이 주기를 명령어 사이클이라한다.

 

메모리에 저장된 명령어 하나를 실행한다 해보자 명령어를 메모리에서 CPU로 가져와야 한다. 이게 명령

어 사이클의 첫 번째 과정이다. 메모리에 있는 명령어를 CPU로 가져오는 단계를 인출 사이클이라 한다.

 

이제 가져온 명령어를 실행하자 이것이 명령어 사이클의 두 번째 단계이다. 가져온 명령어를 실행하는 단계를 실행 사이클이라고 한다. 프로긂을 이루는 수많은 명령어는 일반적으로 인출과 실행 사이클이 반복되며 실행된다.

 

모든 명령어가 이렇게 간단히 실행되는 것은 아니다. 명령어를 가져와도 바로 실행할 수 없는 경우도 있기 때문이다. 앞에서 설명한 간접 주소 지정 방식을 생각해보자. 간접 주소 지정 방식은 오퍼랜드 필드에 유효 주소의 주소를 명시한다 했다. 이를 실행하기 위해서는 메모리 접근을 한 번 더 해야 하기 때문에 바로 실행 할 수 없다. 이 단꼐를 간접 사이클이라 한다. 추가로 고려해야 할 것이 남았는데 바로 인터럽트다

 

인터럽트

인터럽트는 영어로 interrupt이며 '방해하다, 중단시키다'를 의미한다. CPU의 작업을 방해하는 신호를 말한다. CPU가 작업을 중단해야 할 정도라면 CPU가 꼭 필요하거나 얼른 처리해야 할 다른 작업이 생겼을 때 발생할 것이다. 인터럽트의 종류에는 크게 동기 인터럽트와 비동기 인터럽트가 있다.

 

동기 인터럽트는 CPU에 의해 발생하는 인터럽트다. CPU가 명령어들을 수행하다 프로그래밍상의 오류와 같은 예외적인 상황에 마주쳤을 때 발생하는 인터럽트가 동기 인터럽트다. 이런 점에서 예외라고 부르기도한다.

 

비동기 인터럽트는 주로 입출력장치에 의해 발생하는 인터럽트다. 그렇기에 하드웨어 인터럽트라 불리기도 한다. 입출력장치에 의한 비동기 인터럽트는 'CPU가 프린트와 같은 입출력 장치에 입출력 작업을 부탁하면 작업을 끝낸 입출력 장치가 CPU에 완료 알림(인터럽트)를 보냅니다.'그리고 '키보드, 마우스와 같은 입출력장치가 어떤 입력을 받았을 때 이를 처리하기 위해 알림(인터럽트)을 보냅니다.' 이처럼 알림 역할을 한다.

 

  • 하드웨어 인터럽트

하드웨어 인터럽트는 알림과 같은 인터럽트다. CPU는 입출력 작업 도중 효율적으로 명령어를 처리하기 위해 하드웨어 인터럽트를 사용한다.

하드웨어 인터럽트를 이용하면 프린터와 같은 입출력 장치를 사용할 때 작업이 끝날때까지 CPU가 기다리는 것이 아닌 프린터로부터 완료 인터럽트를 받을 때 까지 다른 작업을 처리할 수 있게된다. 그렇기에 입출력 작업 중에도 CPU로 효율적으로 명령어를 처리할 수 있다.

 

  • 하드웨어 인터럽트 처리 순서
  1. 입출력장치는 CPU에 인터럽트 요청 신호를 보낸다.
  2. CPU는 실행 사이클이 끝나고 명령어를 인출 하기 전 항상 인터럽트 여부를 확인한다.
  3. CPU는 인터럽트 요청을 확인하고 인터럽트 플래그를 통해 현재 인터럽트를 받아들일 수 있는지 확인한다.
  4. 인터럽트를 받아들일 수 있다면 CPU는 지금까지의 작업을 백업한다.
  5. CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행한다.
  6. 인터럽트 서비스 루틴 실행이 끝나면 백업해 둔 작업을 복구하여 실행을 재개한다.

 

인터럽트는 CPU의 정상적인 실행 흐름을 끊는 것이기에 이를 확인하는 인터럽트 요청 신호를 보낸다.

이를 수용하기 위해서는 플래그 레지스터의 인터럽트 플래그가 활성화(1로 설정) 되어있어야 한다. 0일 경우 이를 무시한다. 하지만 모든 인터럽트를 무시할 수 있는 것이 아니다. 바로 우선순위기 가장 높은 정전이나 하드웨어 고장으로 인한 인터럽트가 있다.

CPU가 인터럽트를 수행하기로 했다면 인터럽트 서비스 루틴(인터럽트를 처리하기 위한 프로그램)을 실행한다. 인터럽트 핸들러라 불리기도한다. 인터럽트 서비스 루틴은 특정 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하고 작동해야 할지에 대한 프로그램이다.

CPU는 수많은 인터럽트 서비스 루틴을 구분하기 위해 인터럽트 벡터를 이용한다. 인터럽트 벡터는 인터럽트 서비스 루틴을 식별하기 위한 정보이다. 이를 통해 서비스 루틴의 시작 주소를 알 수 있다.

이제 인터럽트가 완료되면 본래 작업으로 돌아와야하는데 여기서 인터럽트 서비스 루틴도 여느 프로그램 처럼 명령어와 데이터로 이루어져 있기에 레지스터들을 사용하며 실행된다. 그렇다면 본래 작업에 사용되는 레지스터 값들은 지워지는 것일까? 그렇지 않다 바로 이때 작업 하던 내역들을 백업을 해야하는데 프로그램 카운터 값 등 모든 내용을 스택에 백업을 한다. 그렇게 인터럽트를 처리하고나면 스택에 저장해 둔 값을 다시 불러온 뒤 이전 작업을 재개한다.

 

+ 예외의 종류

예외가 발생하면 CPU는 하던 일을 중단하고 해당 예외를 처리한다. 그리고 예외 처리 후 기존 작업으로 되돌아왔을 때 예외가 발생한 명령어부터 실행하느냐, 예외 발생한 명령어의 다음 명령어부터 실행하느냐에 따라 폴트와 트랩으로 나뉜다.

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

트랩은 예외를 처리한 직후 예외가 발생한 명령어의 다음 명령어부터 실행을 재개하는 예외이다. 주로 디버깅에 사용된다.

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

소프트웨어 인터럽트는 시스템 호출이 발생했을 때 나타난다.