혼공학습단 컴운 2주차📚

하영·2023년 7월 16일
0

혼공학습단

목록 보기
2/13
post-thumbnail

기본 미션 📣

04-2 확인문제 2번 | ① 플래그 레지스터 ② 프로그램 카운터 ③ 범용 레지스터 ④ 명령어 레지스터

05-1 확인문제 4번 | 코어

선택 미션 📣

05-1 코어와 멀티 코어, 스레드와 멀티 스레드 개념정리 | 완료


04-1 ALU와 제어장치

ALU

ALU는 레지스터로부터 피연산자를 받아들이고 제어장치로부터 제어 신호를 받아들인다. 레지스터와 제어장치로부터 받아들인 피연산자와 제어 신호로 산술 연산, 논리 연산 등 다양한 연산을 수행한다.

ALU는 연산한 결괏값과 연산 결과에 대한 추가적인 정보인 플래그를 내보낸다.
ALU가 내보내는 대표적인 플래그는 아래와 같다.


플래그 종류의미사용예시
부호 플래그연산한 결과의
부호를 나타낸다.
부호 플래그가 1일 경우 계산 결과는 음수,
0일 경우 계산 결과는 양수를 의미한다.
제로 플래그연산한 결과가 0인지
여부를 나타낸다.
제로 플래그가 1일 경우 연산 결과는 0,
0일 경우 연산 결과는 0이 아님을 의미한다.
캐리 플래그연산 결과 올림수나 빌림수가
발생했는지를 나타낸다.
캐리 플래그가 1일 경우 올림수나 빌림수가 발생했음을 의미하고,
0일 경우 발생하지 않았음을 의미한다.
오버플로우 플래그오버플로우가 발생했는지를 나타낸다.오버플로우 플래그가 1일 경우 오버플로우가 발생했음을 의미하고, 0일 경우 발생하지 않았음을 의미한다.
인터럽트 플래그인터럽트가 가능한지를 나타낸다.인터럽트 플래그가 1일 경우 인터럽트가 가능함을 의미하고,
0일 경우 인터럽트가 불가능함을 의미한다.
슈퍼바이저 플래그커널 모드로 실행 중인지,
사용자 모드로 실행 중인지를 나타낸다.
슈퍼바이저 플래그가 1일 경우 커널 모드로 실행 중임을 의미하고,
0일 경우 사용자 모드로 실행 중임을 의미한다.

이러한 플래그들은 플래그 레지스터에 저장된다.

제어장치

제어장치는 제어 신호를 내보내고, 명령어를 해석한다.

제어장치가 받아들이는 정보는 클럭 신호, 명령어, 플래그 값, 제어 신호 등이 있다.

제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호이다. 제어 신호는 CPU뿐만 아니라 입출력장치를 비롯한 CPU 외부 장치도 발생시킬 수 있다.

04-2 레지스터

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

레지스터는 CPU마다 이름, 크기, 종류가 매우 다양한데, 그 중 많은 CPU가 공통으로 포함하고 있는 레지스터는 다음과 같다.

프로그램 카운터

프로그램 카운터는 메모리에서 읽어 들일 명령어의 주소를 저장한다. CPU마다 명령어 포인터라고도 부른다. 프로그램 카운터는 지속적으로 증가하며 계속해서 다음 명령어를 읽어 들일 준비를 한다.

명령어 레지스터

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

메모리 주소 레지스터

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

메모리 버퍼 레지스터

메모리 버퍼 레지스터는 메모리와 주고받을 값(데이터와 명령어)을 저장하는 레지스터이다. 메모리 데이터 레지스터라고도 부른다. CPU가 데이터 버스로 주고받을 값은 메모리 버퍼 레지스터를 거친다.

범용 레지스터

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

플래그 레지스터

플래스 레지스터는 ALU 연산 결과에 따른 플래그와 CPU 상태에 대한 부가적인 정보를 저장하는 레지스터이다.

스택 포인터

스택 포인터는 스택 주소 지정 방식이라는 주소 지정 방식에 사용되는데, 스택에서 스택의 꼭대기를 가리키는 레지스터를 스택 포인터라 한다. 쉽게 말해, 스택의 어디까지 데이터가 채워져 있는지에 대한 표시라고 보면 된다.

베이스 레지스터

베이스 레지스터는 변위 주소 지정 방식이라는 주소 지정 방식에 사용되는 레지스터로,
베이스 레지스터 주소 지정 방식에서 베이스 레지스터 안에 기준 주소를 저장한다.

변위 주소 지정 방식

변위 주소 지정 방식은 오퍼랜드 필드의 값과 특정 레지스터의 값을 더하여 유효 주소를 얻어내는 주소 지정 방식이다. 변위 주소 지정 방식에는 두 가지가 있는데, 상대 주소 지정 방식과 베이스 레지스터 주소 지정 방식이다.

상대 주소 지정 방식은 오퍼랜드와 프로그램 카운터의 값을 더하여 유효 주소를 얻는다.
만약 오퍼랜드에 -3이 있다면 CPU가 읽어 들이기로 한 명령어로부터 '세 번째 이전' 번지에 명령어를 실행한다.

베이스 레지스터 주소 지정 방식은 오퍼랜드와 베이스 레지스터의 값을 더하여 유효 주소를 얻는 방식이다. 여기서 베이스 레지스터는 '기준 주소', 오퍼랜드는 '기준 주소로부터 떨어진 거리'로서의 역할을 한다. 만약 베이스 레지스터에 200이라는 값이 있고 오퍼랜드가 40이라면 240번지에 있는 값을 찾으라는 의미이다.

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

명령어 사이클

프로그램 속 각각의 명령어들은 일정한 주기가 반복되며 실행되는데, 이 주기를 명령어 사이클이라고 한다. 명령어 사이클은 인출, 실행, 간접, 인터럽트 사이클로 구성되어 있다. 프로그램은 대부분 인출 사이클과 실행 사이클을 반복하며 실행된다.

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

CPU가 가져온 명령어를 실행하는 단계인 실행 사이클은 제어장치가 명령어 레지스터에 담긴 값을 해석하고, 제어 신호를 발생시킨다.

간접 사이클은 간접 주소 지정 방식과 같이 명령어를 바로 실행할 수 없고 메모리 접급을 한 번 더 해야하는 단계를 말한다.

인터럽트

CPU가 수행 중인 작업은 방해를 받아 잠시 중단될 수 있는데, 여기서 CPU의 작업을 방해하는 신호를 인터럽트라고 한다. 인터럽트의 종류에는 크게 동기 인터럽트와 비동기 인터럽트가 있다.

동기 인터럽트는 CPU에 의해 발생하는 인터럽트로, CPU가 명령어들을 수행하다가 예상치 못한 상황이나 오류와 같은 예외적인 상황에 마주쳤을 때 발생하며 예외라고도 부른다.

비동기 인터럽트하드웨어 인터럽트라고도 하는데, 주로 입출력장치에 의해 발생하는 인터럽트로 알림 역할을 한다. CPU는 비동기 인터럽트로 인해 입출력 작업 중에도 효율적으로 명령어를 처리 할 수 있는데, 프린터로부터 프린트 완료 인터럽트를 받을 때까지 다른 작업을 처리할 수 있게 하는 것이 예와 같다.

비동기 인터럽트(하드웨어 인터럽트) 처리 순서는 다음과 같다.

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

인터럽트 서비스 루틴은 인터럽트를 처리하기 위한 프로그램이다. 인터럽트 핸들러라고도 불리는데, 어떤 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하고 작동해야 할지에 대한 정보로 이루어져 있다.

인터럽트 서비스 루틴은 입출력장치마다 각기 다른 인터럽트 서비스 루틴을 가지고 있는데 이를 구분하기 위한 것이 인터럽트 벡터이다.


05-1 빠른 CPU를 위한 설계 기법

CPU의 성능을 좋게 하기 위해서는 여러 가지 방법이 있다.

클럭

클럭이란 컴퓨터의 모든 부품을 일사불란하게 움직일 수 있게 하는 시간 단위이다. 컴퓨터 부품들은 클럭이라는 박자에 맞춰 데이터를 이동시키거나 명령어를 읽어들인다.

그렇기 때문에 클럭 속도(Hz)가 높아지면 CPU는 명령어 사이클을 더 빠르게 반복한다. 실제로도 클럭 속도가 높은 CPU가 성능이 좋다.

하지만 무조건 클럭 속도만 높인다고 CPU의 성능이 좋은 것은 아니다. 클럭 속도를 무작정 높이면 컴퓨터가 뜨거워지는 발열 문제가 발생한다. 그렇기 때문에 클럭 속도 만으로는 CPU의 성능을 올리는 것은 한계가 있다.

코어와 멀티코어

우리가 지금까지 CPU의 정의로 알고 있었던 '명령어를 실행하는 부품'은 오늘날 코어라는 용어로 사용된다. 다시 말해, 오늘날의 CPU는 단순히 '명령어를 실행하는 부품'에서 '명령어를 실행하는 부품을 여러 개 포함하는 부품'으로 명칭의 범위가 확장되었다.

따라서 오늘날에는 CPU안에 '명령어를 실행하는 부품'인 코어가 여러 개 들어있는데 이것을 멀티코어라 한다.

당연히 멀티코어의 처리 속도는 단일코어보다 빠르다. 만약 클럭 속도가 2.4GHz인 단일 코어 CPU와 클럭 속도가 1.9GHz인 멀티코어 CPU가 있다면 일반적으로 후자의 성능이 더 좋다고 보면 된다.

하지만 CPU의 연산 속도가 꼭 코어 수에 비례하여 증가하진 않는다. 중요한 것은 코어마다 처리할 명령어들을 얼마나 적절하게 분배하느냐 이고 연산 속도도 그에 따라 크게 달라진다.

스레드와 멀티스레드

스레드의 사전적 의미는 '실행 흐름의 단위'이지만, 스레드에는 CPU에서 사용되는 하드웨어적 스레드와 프로그래밍에서 사용되는 소프트웨어적 스레드가 있다.

하드웨어적 스레드

스레드를 하드웨어적으로 정의하면 '하나의 코어가 동시에 처리하는 명령어 단위'를 의미한다. 따라서 여러 스레드를 지원하는 CPU는 하나의 코어로도 여러 개의 명령어를 동시에 실행할 수 있다.
이처럼 하나의 코어로 여러 명령어를 동시에 처리하는 CPU를 멀티스레드 프로세서라고 한다.

소프트웨어적 스레드

소프트웨어적으로 정의된 스레드는 '하나의 프로그램에서 독립적으로 실행되는 단위'를 의미한다. 하나의 프로그램은 실행되는 관정에서 한 부분만 실행될 수도 있지만, 프로그램의 여러 부분이 동시에 실행될 수도 있다.


따라서 ' 한 번에 하나씩 명령어를 처리하는 1코어 1스레드 CPU도 소프트웨어적 스레드를 수십 개 실행할 수 있다. ' 라는 것은 하드웨어적 스레드와 소프트웨어적 스레드의 의미를 모두 함유하고 있는 것이다.

05-2 명령어 병렬 처리 기법

좋은 성능을 가진 CPU를 만들려면 높은 클럭 속도에 멀티코어, 멀티스레드도 중요하지만
CPU가 놀지 않고 시간을 알뜰하게 쓰며 작동하게 만드는 것도 중요하다.
그렇게 만드는 것이 바로 명령어 병렬 처리 기법인데, 대표적으로는 명령어 파이프라이닝, 슈퍼스칼라, 비순차적 명령어 처리가 있다.

명령어 파이프라인

명령어 파이프라인은 명령어가 처리되는 과정을 인출, 해석, 실행, 저장 단계로 나누어 보는데, 여기서 중요한 점은 같은 단계가 겹치지만 않는다면 CPU는 '각 단계를 동시에 실행할 수 있다'는 것이다.

이처럼 마치 공장 생산 라인과 같이 명령어들을 명령어 파이프라인에 넣고 동시에 처리하는
기법을 명령어 파이프라이닝이라고 한다.

명령어 파이프라이닝은 높은 성능을 가져오긴 하지만 특정 상황에서는 성능 향상에 실패하는 경우도 있다. 이러한 상황을 파이프라인 위험이라고 한다. 파이프라인 위험에는 크게 데이터 위험, 제어 위험, 구조적 위험이 있다.

데이터 위험

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

예를 들어 명령어1: A = B + C, 명령어 2: D = A + F가 있다면 명령어 2는 명령어 1의 수행이 끝나야만 수행될 수 있다. 만약 명령어 1의 수행이 끝나기 전에 명령어 2가 수행된다면 결괏값은 예측값과 달라질 수 있다. 따라서 명령어 2는 명령어 1의 데이터에 의존적이다.

이처럼 데이터 의존적인 두 명령어를 무작정 동시에 수행하려고 할 때 파이프라인이 제대로 작동하지 않는 것을 '데이터 위험'이라고 한다.

제어 위험

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

프로그램 실행 흐름이 바뀌면서 프로그램 카운터 값에 갑작스러운 변화가 생긴다면 명령어 파이프라인에 미리 가지고 와서 처리 중이었던 명령어들은 아무 쓸모가 없어지는 것이다.

구조적 위험

구조적 위험은 명령어들을 겹쳐 실행하는 과정에서 서로 다른 명령어가 동시에 같은 CPU부품을 사용하려고 할 때 발생한다. 구조적 위험은 자원 위험이라고도 부른다.

슈퍼스칼라

오늘날 대부분의 CPU는 여러 개의 파이프라인을 이용하는데, CPU 내부에 여러 개의 명령어 파이프라인을 포함한 구조를 슈퍼스칼라라고 한다.

슈퍼스칼라 구조로 명령어 처리가 가능한 CPU를 슈퍼스칼라 프로세서라고 한다. 슈퍼스칼라 프로세서는 매 클럭 주기마다 동시에 여러 명령어를 인출할 수도, 실행할 수도 있어야 한다. 예로 멀티스레드 프로세서가 있다.

슈퍼스칼라 프로세서는 이론적으로는 파이프라인 개수에 비례하여 프로그램 처리 속도가 빨라지지만, 실제로는 반드시 파이프라인 개수에 비례하여 빨라지지는 않는다.

또한, 슈퍼스칼라 프로세서는 하나의 파이프라인을 이용할 때 보다 데이터 위험, 제어 위험, 자원 위험을 피하기가 까다롭기 때문에 고도로 설계되어야 한다.

비순차적 명령어 처리(OoOE)

비순차적 명령어 처리는 파이프라인 위험과 같은 예상치 못한 문제들로 인해 명령어가 멈추는 것을 방지해 순서를 바꿔 실행해도 무방한 명령어를 먼저 실행하는 기법이다.

위 표처럼 1번, 2번과 데이터 의존적인 3번을 마지막으로 옮겨 데이터 위험이 일어나지 않게 하는 것이 비순차적 명령어 처리이다.

이처럼 비순차적 명령어 처리가 가능한 CPU는 명령어들이 어떤 명령어와 데이터 의존성을 가지고 있는지, 순서를 바꿔 실행할 수 있는 명령어에는 어떤 것들이 있는지를 판단할 수 있어야 한다.

05-3 CISC와 RISC

명령어 집합 ( ISA )

CPU가 이해할 수 있는 명령어들의 모음을 명령어 집합 또는 명령어 집합 구조(ISA) 라고 한다.
하지만 명령어는 CPU마다 생김새, 할 수 있는 연산, 주소 지정 방식 등에 차이가 있다.
즉, CPU마다 ISA가 다를 수 있다는 것이다.

ISA가 다르다는 건 같은 프로그램이라 할지라도 CPU가 이해할 수 있는 명령어가 다르다는 뜻이고, 명령어가 달라지면 어셈블리어도 달라진다. 또, 그의 따른 나비효과로 제어장치가 명령어를 해석하는 방식, 사용되는 레지스터의 종류와 개수, 메모리 관리 방법 등 많은 것이 달라진다. 그리고 CPU 하드웨어 설계에도 큰 영향을 미친다.

그렇기 때문에 ISA는 CPU의 언어임과 동시에 CPU를 비롯한 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속이라고 볼 수 있다.

CISC

CISC는 현대 ISA의 양대 산맥 중 하나로 Complex Instruction Set Computer의 약자이다. 이를 그대로 해석하면 '복잡한 명령어 집합을 활용하는 컴퓨터'를 의미하는데 이름 그래도 복잡하고 다양한 명령어들을 활용하는 CPU 설계 방식이다.

CISC는 다양하고 강력한 기능의 명령어 집합을 활용하기 때문에 명령어의 형태와 크기가 다양한 가변 길이 명령어를 활용하는데, 여기서 다양하고 강력한 명령어를 활용한다는 말은 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다는 것을 의미한다. 그렇기 때문에 메모리 공간을 절약할 수 있다는 장점이 있다.

하지만 치명적인 단점이 있는데, 명령어의 크기와 실행되기까지의 시간이 일정하지 않다는 것이다. CISC가 활용하는 명령어는 명령어 수행 시간이 길고 가지각색이기 때문에 파이프라인이 효율적으로 명령어를 처리할 수 없다. 현대 CPU에서 명령어 파이프라인은 높은 성능을 내기 위해 절대 놓쳐서는 안 되는 핵심기술이기 때문에 아주 치명적인 단점이 된다.

게다가 CISC가 사용하는 복잡하고 다양한 명령어들은 사실 그 사용 빈도가 낮다.
이러한 이유로 CISC 기반 CPU는 성장에 한계가 있다.

RISC

RISC는 CISC를 견주는 ISA로 CISC의 한계를 극복하고자 나왔다. 그렇기 때문에 CISC에 비해 명령어의 종류가 적고, 명령어가 짧고 규격화되어있다.

즉, 고정 길이 명령어를 활용하는데 명령어가 규격화되어 있고, 하나의 명령어가 1클럭 내외로 실행되기 때문에 RISC 명령어 집합은 명령어 파이프라이닝에 최적화되어 있다.

그리고 RISC는 메모리에 직접 접근하는 명령어를 load, store 두 개로 제한할 만큼 메모리 접근을 단순화하고 최소화를 추구한다. 그렇기 때문에 CISC보다 주소 지정 방식의 종류가 적은 경우가 많다.
대신 레지스터를 적극적으로 활용하는데, 그렇기에 CISC보다 레지스터를 이용하는 연산이 많고 범용 레지스터 개수도 더 많다.

다만 사용 가능한 명령어 개수가 CISC보다 적기 때문에 RISC는 CISC보다 많은 명령으로 프로그램을 작동시킨다.

0개의 댓글