ComputerScience/컴퓨터 구조

[컴퓨터 구조] CPU의 작동 원리

ruu++ 2024. 8. 28. 23:44

이 글은 혼자 공부하는 컴퓨터 구조 + 운영체제 (저자 : 강민철)의 책과 유튜브 영상을 참고하여 개인적으로 정리하는 글이라는 것을 알립니다!!.

1. ALU(산술 논리 연산 장치)

ALU

1.1 ALU 로 들어오는 정보

  • 레지스터에서 연산에 사용할 피연산자를 가져옵니다.
  • 제어장치에서 수행할 연산을 알려주는 제어 신호를 받습니다

1.2 ALU에서 내보내는 정보

  • 특정 숫자나 문자메모리 주소가 바로 메모리 주소에 저장되는 것이 아닌 레지스터에 일시적으로 저장됩니다.
    why? 레지스터에 저장하는 이유는 CPU가 메모리가 접근하는 속도가 레지스터가 더 빠릅니다. 만약 CPU 메모리에 저장한다면, 메모리에 자주 접근하게 되고 프로그램 속도를 늦출 수 있습니다.
  • ALU는 계산된 결과와 플래그를 내보냅니다.

1.3.1 플래그(flag)

플래그? 연산 결과에 대한 추가적인 상태정보를 말합니다.

플래그는 CPU가 프로그램 실행하는 도중 반드시 기억해야 하는 참고 정보입니다

1.3.2 플래그 레지스터

플래그들이 저장되는 공간을 플래그 레지스터라고 합니다.
ALU가 연산 이후 부호 플래그가 1이 된다면 이 연산의 결과값은 음수라고 알 수 있습니다.

1.4 제어장치

  • 제어장치는 제어 신호를 내보내고 명령어를 해석하는 부품입니다.
  • 제어신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 전기 신호입니다.

제어장치

1.4.1 제어 장치가 받는 정보

  1. 제어장치는 클럭 신호를 받습니다.
  2. 클럭은 모든 작업의 타이밍과 속도를 조절하는 핵심 컴퓨터 요소입니다. 일정 시간, 간격 기준으로 컴퓨터 장치 사이에서 주기적으로 전기 신호를 오갑니다.
    하지만, 모든 부품이 한 클럭에 모두 동작하는 것이 아니라, 하나의 명령어가 여러 클럭에 걸쳐 실행될 수 있습니다.
  3. 제어장치는 해석해야 할 명령어를 받습니다.

제어장치는 명령어 레지스터로부터 해석할 명령어를 받아 해석한 후 제어신호를 발생시켜 컴퓨터 부품들에게 수행할 내용을 전달합니다.

  1. 제어장치는 플래그 레지스터 속 플래그 값을 받습니다.

중요한 참고사항 중 하나인 플래그 값을 받아 참고하여 제어신호를 발생시킵니다.

  1. 제어장치는 시스템 버스, 그중에서 제어 버스로 전달된 제어 신호를 받습니다

제어 신호는 CPU 뿐만 아니라 여러 입출력 장치, 외부 장치도 발생할 수 있습니다. 그런 신호들을 제어장치는 제어 버스를 통해서 받을 수 있습니다.

1.4.2 제어 장치가 내보내는 정보

  1. CPU 내부로 전달하는 제어 신호
  • ALU에게 수행할 연산을 지시하기 위한 제어 신호
  • 레지스터 간 데이터 이동 또는 레지스터에 저장된 명령어를 해석하기 위한 제어 신호
  1. CPU 외부(제어 버스)로 전달하는 제어 신호
  • 입출력장치에 전달하는 제어 신호
  • 메모리에 전달하는 제어 신호

2. 레지스터

CPU 속 레지스터는 제조사마다 크기, 이름, 종류가 매우 다양합니다. 여러 전공 서적에서 중요하게 다루는 공통적인 레지스터 8가지를 알아보겠습니다.

프로그램 카운터

  • 프로그램 카운터는 메모리에서 읽을 명령어의 주소를 저장합니다.
  • 프로그램 카운터를 명령어 포인터라고 부르는 CPU도 있습니다.

명령어 레지스터

  • 메모리에서 읽은 명령어를 저장합니다.
  • 제어장치는 명령어 레지스터에서 명령어를 받아들이고 해석합니다. 그 뒤에 제어 신호를 내보냅니다.

메모리 주소 레지스터

  • 메모리 주소를 저장합니다.
  • CPU가 읽는 주소 값을 주소 버스로 보낼 때 메모리 주소 레지스터를 거칩니다.

메모리 버퍼 레지스터

  • 메모리와 주고 받을 값을 저장하는 레지스터입니다.
  • 데이터 버스로 주고 받는 값은 메모리 버퍼 레지스터를 거칩니다.

범용 레지스터

  • 범용레지스터는 일반적인 상황에서 자유롭게 사용할 수 있는 레지스터입니다.
  • 데이터와 주소를 모두 저장할 수 있습니다.

플래그 레지스터

  • ALU 연산결과에 따른 여러개의 플래그를 저장하는 레지스터입니다.

2.1 프로그램 실행 예시로 4가지 레지스터를 자세하게 알아봅시다.

  1. 프로그램이 2000번지부터 2500번지까지 저장되었다고 가정합니다. 만약 2000번지에는 1101 이라는 값을 가지고 있다는 가정 해봅시다.

실행할 프로그램 예시

  1. 프로그램을 실행하기 위해서 프로그램 카운터는 2000을 가집니다. 메모리에서 가져올 명령어가 2000번지에 있기 때문입니다.

프로그램 카운터

  1. 2000 번지의 데이터를 가져오려면 주소 버스로 1000번지를 보내야합니다. 주소 버스를 보내기 위해선 메모리 주소 레지스터에 2000번지를 저장합니다.

  1. 메모리 읽기 제어 신호와 그에 해당하는 메모리 주소 레지스터 값이 각각 제어 버스와 주소 버스를 통해 메모리로 보냅니다.

  1. 메모리 2000번에 저장된 값은 데이터 버스를 통해 메모리 버퍼 레지스터에 전달되고 프로그램 카운터가 증가하여 다음 명령어를 읽을 준비를 합니다.

  1. 메모리 버퍼 레지스터에 저장된 값은 명령어 레지스터로 이동합니다.

  1. 제어장치는 명령어 레지스터의 명령어를 해석하고 제어신호를 발생합니다.

해당 과정에서 프로그램 카운터가 계속 증가하면서 다음 명령어를 읽습니다. 이 과정의 반복으로 CPU는 프로그램 순차적으로 읽어 프로그램을 실행합니다.

2.2.1 스택 포인터

스택 포인터라는 특별한 레지스터가 존재합니다. 스택 포인터라는 것은 무엇일까요?
스택 포인터는 스택에서 자주 구현하는 Top을 가르키는 주소를 가진 레지스터를 말합니다.
스택에 대해서 잘 모른다면 해당 위키를 읽어보세요!.
https://en.wikipedia.org/wiki/Stack_(abstract_data_type)

2.2.2 스택 주소 지정 방식

스택 포인터를 사용하는 스택 주소 지정 방식이라는 것이 존재합니다. 스택은 FILO(First In Last Out)의 데이터 처리를 하는 자료 구조라고 말할 수 있는데요. 이 것은 가장 먼저 들어간 데이터가 가장 마지막에 나온다는 것을 말합니다.

스택 메모리

위의 그림을 보면 스택 포인터는 4번지를 가리키는 것을 볼 수 있습니다. 만약에 pop이 된다면 4번지의 데이터가 비우게 되고 스택 포인터는 5번지를 가리키게 됩니다.

메모리에는 스택 영역이라고 별도의 공간을 사용하기로 암묵적으로 약속되어 있는데요. 언어, 프로그램마다 사용되는 스택영역의 크기는 정말 다양합니다.

2.3.1 변위 주소 지정 방식

변위주소지정방식

변위 주소 지정 방식은 명령어의 오퍼랜드의 값과 CPU의 레지스터의 값더하여 유효 주소를 얻는 주소 지정 방식입니다.

변위 주소 지정 방식의 명령어는 일반 명령어와 다르게 레지스터 필드 값도 가지고 있습니다.

2.3.2 상대 주소 지정 방식

"어떤 레지스터를 사용하느냐"에 따라 또 여러 주소 지정 방식으로 나뉩니다.
상대 주소 지정 방식은 오퍼랜드와 프로그램 카운터 값을 더하여 유효 주소를 얻습니다.

상대주소지정방식

프로그램 카운터에는 보통 실행할 명령어에 대한 주소를 가지고 있다는 것을 이전에 공부했는데요. 실행할 명령어가 2005번지를 가리키고 있으며, 오퍼랜드가 -3이라면, 2002번지에 접근하게 됩니다. 즉, 세칸 이전 번지 명령어를 실행합니다.
반대로 오퍼랜드가 +3이라면 어떨까요? 그렇다면 2008번지에 접근하게 될 것 입니다.
상대 주소 지정 방식은 모든 명령어를 실행하는 것이 아니라 프로그래밍 언어의 IF문과 유사합니다. 분기하여 특정 주소의 명령어를 실행되는데 사용됩니다.

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

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

베이스레지스터 지정방식

베이스 레지스터는 영어명이 가르키는 '기존 주소'를 뜻하며, 연산코드를 더하여 특정 주소 번지에 접근하는 것을 말합니다. 만약에 베이스 레지스터가 5000일 때, 오퍼랜드 값이 100이라면, 5100번지에 접근하라는 것을 뜻합니다.


3. 명령어 사이클과 인터럽트

3.1 명령어 사이클

  • 명령어 사이클은 프로그램 속 명령어들은 일정 주기를 반복하면서 실행하는 과정을 말합니다.
  • 메모리에 저장된 명령어 하나를 실행한다면, CPU는 실행할 명령어를 메모리에서 가지고 와야 합니다. 이 단계를 인출 사이클라고 말합니다.
  • 다음으로 인출한 명령어를 실행하는 단계를 실행 사이클이라고 합니다. 제어장치가 명령어 레지스터의 값을 해석하고 제어 신호를 발생시키는 단계입니다.
  • 명령어는 인출, 실행 사이클로 간단하게 실행되는 것이 아닙니다. 간접 주소 지정 방식을 예시로 들면 해당 방식은 오퍼랜드 필드가 유효 주소의 주소를 가지고 있습니다. 그렇다면 인출하더라도 바로 실행으로 이어질 수 없습니다. 1번의 메모리 접근이 더 필요하기 때문입니다. 이러한 과정을 간접 사이클이라고 말합니다.

3.2 인터럽트

CPU에서 수행 중인 작업이 방해를 받아 잠시 중단될 수 있습니다. CPU를 방해하는 신호를 인터럽트라고 합니다.
회사에서 일 하는 도중 더 급한 일이 생겨 이전 일이 중단 되는 상황과 비슷합니다.

인터럽트 종류

3.2.1 동기 인터럽트

동기 인터럽트는 CPU에 의해 발생합니다. CPU가 명령어를 실행하는 도중 예상치 못한 상황에 마주쳤을 때, 발생하는 인터럽트를 동기 인터럽트라고 합니다. 동기 인터럽트를 예외라고 부르기도 합니다.

3.2.2 동기 인터럽트의 종류

  1. 예외
  • 예외가 발생하면 CPU는 하던 일을 종료하고 예외를 처리합니다. 처리 이후 CPU는 원래 작업을 재개합니다.
  1. 폴트
  • 예외를 처리한 이후 예외가 발생한 명령어부터 실행을 재개하는 예외입니다. 만약 필요로 하는 데이터가 보조기억장치에 있다면, 메모리에 적재한 뒤에 다시 CPU가 재개해야 합니다. 이 과정에서 CPU는 폴트를 발생시키고 메모리에 데이터를 적재시킨 뒤 재개 하는 것입니다.
  1. 트랩
  • 트랩은 예외를 처리한 이후 다음 명령어부터 실행을 재개하는 예외입니다. 대표적인 예시로 디버깅이 있습니다.
  1. 중단
  • CPU가 실행중인 프로그램을 강제 중지해야 하는 치명적인 오류를 발견했을 경우 발생하는 예외입니다.
  1. 소프트웨어 인터럽트
  • 시스템 호출이 발생했을 때, 동작하는 인터럽트입니다.

3.2.3 비동기 인터럽트

비동기 인터럽트는 주로 입출력장치에 의해 발생합니다. 보통 비동기 인터럽트를 인터럽트를 칭하는 말이기도 합니다.
정확히 하드웨어 인터럽트를 알아보려고 합니다.

3.2.4 하드웨어 인터럽트

하드웨어 인터럽트는 알림 기능과 비슷합니다. CPU가 프린트의 출력을 명령하면, CPU보다 출력 작업이 느린 프린트 출력 작업 결과를 바로 알 수 없습니다. 이때, 하드웨어 인터럽트가 입출력 작업이 끝나게 되면 CPU에게 알려주는 역할을 합니다.

3.2.5 하드웨어 인터럽트 처리 순서

CPU가 인터럽트를 처리하는 방식은 대부분 비슷하다고 합니다. CPU가 하드웨어 인터럽트를 처리하는 순서는 이렇습니다.

  1. 입출력장치가 CPU에 인터럽트 요청 신호를 보냅니다.
  2. CPU는 실행 사이클이 끝난 후 명령어를 인출하기 전 항상 인터럽트 여부를 확인합니다.
  3. CPU는 인터럽트 요청을 확인하고 인터럽트 플래그의 정보로 받아들일 수 있는지 확인합니다.
  4. 인터럽트를 받을 수 있다면 CPU는 지금까지 작업을 백업합니다.
  5. CPU는 인터럽트 백터를 참조하여 인터럽트 서비스 루틴을 실행합니다.
  6. 인터럽트 서비스 루틴이 끝나면 4에서 백업한 작업을 복구하고 다시 실행합니다.

입력장치는 인터럽트 요청 신호를 통해서 CPU에게 물어봅니다. 이 때, 인터럽트 플래그가 활성화된 상태여야 해당 인터럽트 요청 신호를 받아 그 인터럽트를 처리합니다. 인터럽트 플래그가 활성화되지 않더라도 무시할 수 없는 인터럽트가 있습니다. 그 것을 막을 수 없는 인터럽트라고 합니다.

  • 막을 수 없는 인터럽트

정전 및 하드웨어 고장으로 무시할 수 없는 치명적인 장애 발생이 여기에 속합니다.

  • 인터럽트 서비스 루틴(인터럽트 핸들러)
    1. 인터럽트가 발생되면 각 입출력장치마다 각각 다른 인터럽트 서비스 루틴을 가지고 있습니다.
    2. 각각 인터럽트 서비스 루틴은 인터럽트 발생시 어떻게 행동할지 알려주는 프로그램입니다.
  • 인터럽트 벡터
    1. 각각 입출력 장치의 서비스 루틴을 식별하기 위한 정보를 뜻합니다.
    2. 백터를 알면 인터럽트 서비스 루틴의 시작점을 알 수 있습니다.
  • 만약 인터럽트가 동작하기 이전 프로그램 카운터가 1500번지라고 가정했을 때, 인터럽트가 발생했고 그 서비스 루틴이 10번이라고 생각해봅니다.
    1. CPU가 1500번지의 명령어를 실행하기 전에 인터럽트를 확인합니다.
    2. 인터럽트가 발생했습니다.
    3. 이전 1500번지 명령어의 프로그램 카운터, 메모리 주소 레지스터, 버퍼 레지스터 등등 레지스터의 정보를 스택 메모리 영역에 백업합니다.
    4. 10번지의 서비스 루틴을 실행하고 처리합니다.
    5. 스택에 저장해둔 값을 다시 불러오고 이전에 수행했던 작업을 진행합니다.

긴 글 읽어주셔서 감사합니다!.