커리큘럼 🫠


📃 기본 미션1

p.125, 확인 문제 2번 ) 설명에 맞는 레지스터를 보기에서 찾아 빈칸을 채워 보세요.

보기 : 프로그램 카운터, 명령어 레지스터, 플래그 레지스터, 범용 레지스터

(①) : 연산 결과 혹은 CPU 상태에 대한 부가 정보를 저장하는 레지스터

(②) : 메모리에서 가져올 명령어의 주소를 저장하는 레지스터

(③) : 데이터와 주소를 모두 저장할 수 있는 레지스터

(④) : 해석할 명령어를 저장하는 레지스터

 

🖍 ) 

① = 플래그 레지스터

② = 프로그램 카운터

③ = 범용 레지스터

④ = 명령어 레지스터

 

📃 기본 미션2

p.155, 확인 문제 4번 ) 다음 그림은 멀티코어 CPU를 간략하게 도식화한 그림입니다. 빈칸에 알맞은 용어를 써 넣으세요.

🖍 ) 코어

현대적인 관점에서 ALU, 제어 장치, 레지스터세트를 가지는 '명령어를 실행하는 부품'은 코어로 지칭하며, 코어를 여러개 가지는 멀티코어 CPU로 CPU의 작업처리 속도를 증대시켰다.

 

📃 선택 미션

코어와 스레드, 멀티 코어와 멀티 스레드의 개념 정리하기

코어(core)?
현대적인 관점에서 CPU내에 '명령어를 실행하는 부품'이라는 용어로 사용되고 있는 부품 단위

전통적인 관점의 CPU와 현대적인 관점의 CPU

멀티코어(multi core)?
여러 개의 코어를 포함하고 있는 CPU
코어를 증가함에 따라 비례적으로 CPU의 연산 속도가 증가하는가? ➡️ 그건 아니다.
코어마다 처리할 명령어를 적절하게 분배하는 것에 따라 멀티코어의 연산 속도가 크게 달라진다.
스레드(thread)?
사전적 의미로 '실행 흐름의 단위'이다.
하드웨어적으로는 '하나의 코어가 동시에 처리하는 명령어 단위'를 뜻한다.
소프트웨어적으로는 '하나의 프로그램에서 독립적으로 실행되는 단위'를 뜻한다.

분야별로 사용되는 용례가 다르기 때문에 스레드를 두가지의 종류로 구분지어 기억해야한다.

멀티스레드(multi thread)?
하드웨어적으로는 CPU의 코어에 여러개의 스레드를 포함하여 여러 명령어를 동시에 처리할 수 있는 스레드
소프트웨어적으로는 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것
멀티 스레드(ex. n스레드)의 작업 수행시 메모리 입장에선 작업 흐름이 동시에 n개 존재할 수 있다.
메모리의 입장에선 하나의 명령어를 처리하는 CPU가 n개 있는 것처럼 보인다.
그러므로 멀티스레드는 논리 프로세서(logical processor)를 여러개 가지는 것과 동일하다.

Chapter 4️⃣

04-1 ALU와 제어장치

ALU는 계산하는 장치, 제어장치는 제어 신호를 발생시키고 명령어를 해석하는 장치

CPU의 구조

 

 

ALU

  • ALU는 피연산자와 수행할 연산을 받아 계산을 수행한다.
  • 레지스터로부터 피연산자를 받아들인다.
  • 제어장치로부터 제어신호(산술 연산, 논리 연산)을 받아들인다.
  • 결괏값을 레지스터에 저장하는 이유는 메모리에 접근하는 속도보다 훨씬 빠르기 때문

ALU가 받는 신호와 내보내는 신호

 

플래그

  • ALU는 연산 결과에 대한 부가 정보로 플래그를 플래그 레지스터로 내보낸다.
  • 계산 결과에 대한 정보 (음수) 를 알리는 추가 정보를 담기도 한다.
  • 연산 결과가 연산 결과를 담을 레지스터보다 큰 상황인 오버플로우(overflow)를 알리기도 한다.
플래그 종류 의미 사용 예시
부호 플래그 연산한 결과의 부호를 나타낸다. 부호 플래그가 1일 경우 계산 결과는 음수, 0일경우 계산 결과는 양수를 의미한다.
제로 플래그 연산 결과가 0인지 여부를 나타낸다. 제로 플래그가 1일 경우 연산 결과는 0, 0일 경우 연산 결과는 0이 아님을 나타낸다.
캐리 플래그 연산 결과 올림수나 빌림수가 발생했는지를 나타낸다. 캐리 플래그가 1일 경우 올림수나 빌림수가 발생했음을 의미하고 0일 경우 발생하지 않았음을 의미한다.
오버플로우 플래그 오버플로우가 발생했는지를 나타낸다. 오버플로우 플래그가 1일 경우 오버플로우가 발생했음을 의미하고, 0일 경우 발생하지 않았음을 의미한다.
인터럽트 플래그 인터럽트가 가능한지를 나타낸다. 인터럽트 플래그가 1일 경우 인터럽트가 가능함을 의미하고, 0일 경우 인터럽트가 불가능함을 의미한다.
슈퍼바이저 플래그 커널 모드로 실행 중인지, 사용자 모드로 실행 중인지를 나타낸다. 슈퍼바이저 플래그가 1일 경우 커널 모드로 실행 중임을 의미하고, 0일 경우 사용자 모드로 실행 중임을 의미한다.

 

플래그 레지스터

  • 플래그 종류에 따른 정보를 저장하는 플래그 레지스터

플래그 정보들을 저장하는 플래그 레지스터

 

제어장치

  • 제어 신호를 내보내고, 명령어를 해석하는 부품
  • 제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호
  • 제어 장치가 받아들이는 정보
    1. 제어장치는 클럭 신호를 받아들인다.
    2. 제어장치는 ‘해석해야 할 명령어’를 받아들인다.
    3. 제어장치는 플래그 레지스터 속 플래그 값을 받아들인다.
    4. 제어장치는 시스템 버스, 그 중에서 제어 버스로 전달된 제어 신호를 받아들인다. (입출력 장치를 비롯한 주변 장치의 제어 신호)
  • 제어 장치가 내보내는 정보
    1. CPU 외부에 전달하는 제어 신호 (레지스터나 ALU로 보내는 정보)
    2. CPU 내부에 전달하는 제어 신호 (메모리 혹은 입출력장치)

제어장치가 받아들이는 정보와 내보내는 정보

 

 

클럭 (clock)

  • 컴퓨터의 모든 부품을 일사불란하게 움직일 수 있게 하는 시간 단위

단위 시간당 클럭이 많이 발생하면 클럭 주기가 높다 😉

 

04-2 레지스터

레지스터

  • CPU 내부의 작은 임시저장장치
  • 프로그램 속 명령어 & 데이터는 실행 전후로 레지스터에 저장
  • CPU 내부에는 다양한 레지스터들이 있고 각기 역할이 다르다.

CPU내부에 존재하는 다양한 레지스터들

 

프로그램 카운터

  • 메모리에서 가져올 명령어의 주소를 저장한다.
  • 메모리에서 읽어 들일 명령어의 주소를 저장한다.
  • Instruction Pointer(명령어 포인터) 라고 부르는 CPU도 있음

명령어 레지스터

  • 해석할 명령어 (방금 메모리에서 읽어들인 명령어)를 저장한다.

메모리 주소 레지스터

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

메모리 버퍼 레지스터

  • 메모리와 주고받을 값 (데이터와 명령어)를 저장한다.
  • CPU가 정보를 데이터 버스로 주고받을 때 거치는 레지스터
  • 메모리 데이터 레지스터 (MDR : Memory Data Register)라고도 부른다.

플래그 레지스터

  • 연산 결과 또는 CPU 상태에 대한 부가적인 정보를 저장한다.

범용 레지스터

  • 다양하고 일반적인 상황에서 자유롭게 사용한다.
  • 보통 여러개 존재한다.
  • 주소나 명령어 범용적으로 사용한다.

스택 포인터

  • 주소 지정에 사용한다.
  • 스택의 꼭대기 (TOS)를 가리키는 레지스터 : 스택이 어디까지 차 있는지에 대한 표시
  • 스택 영역
    • 메모리 안에 스택처럼 사용할 영역이 정해져 있다.
    • 다른 주소 공간과는 다르게 스택처럼 사용하기로 암묵적으로 약속된 영역이다.

스택 포인터에 TOS 주소가 저장되어있다.

베이스 레지스터

  • 주소 지정에 사용한다.
  • 변위 주소 지정 방식에서 사용된다.

레지스터에 저장된 값을 오퍼랜드 값과 합쳐서 메모리의 유효 주소로 활용한다!

변위 주소 지정 방식

  • 오퍼랜드 필드의 값(변위)과 특정 레지스터의 값을 더하여 유효 주소를 얻는 방식
  • 일반적으로 프로그램 카운터나 베이스 레지스터에 저장된 값을 오퍼랜드의 주소값과 더한 주소를 유효주소로 사용한다.
  • 프로그램 카운터를 활용하면 상대 주소 지정 방식
  • 베이스 레지스터를 활용하면 베이스 레지스터 주소 지정 방식

변위 주소 지정방식의 명령어 구조

상대 주소 지정 방식

  • 오퍼랜드 필드의 값(변위)과 프로그램 카운터의 값을 더하여 유효 주소를 얻는 방식

실행할 명령어의 주소가 담긴 프로그램 카운터로부터 오퍼랜드 값 만큼 이동한 곳에 있는 명령어를 수행한다.

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

  • 오퍼랜드 필드의 값(변위)과 베이스 레지스터의 값을 더하여 유효 주소를 얻는 방식

베이스 레지스터에 담긴 값을 기준으로 삼아 오퍼랜드의 값과 합쳐서 유효주소로 사용한다.

 

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

명령어 사이클

  • CPU가 하나의 명령어를 처리하는 과정의 정형화된 흐름
  • 프로그램 속 각각의 명령어들은 명령어 사이클이 반복되며 일반적으로 인출 사이클과 실행 사이클을 반복하며 실행된다.
  • 인출 사이클
    • 메모리에 있는 명령어를 CPU로 가지고 오는 단계
  • 실행 사이클
    • CPU로 가져온 명령어를 실행하는 단계

✅ CPU로 명령어를 가지고 와도 바로 실행이 불가능한 경우도 있다. (간접 주소 지정방식) ➡️ 메모리 접근이 더 필요한 경우 간접 사이클이 추가되기도 한다.

명령어 사이클의 개요 (인터럽트를 추가하면 이것과는 달라진다.)

 

인터럽트

  • CPU의 정상적인 작업을 방해하는 신호
  • CPU가 꼭 주목해야할때, 얼른 처리해야할 다른 작업이 생겼을 때 발생
  • 명령어 사이클에 개입해서 작업을 중단시킨다.
  • 크게 동기 인터럽트(예외)와 비동기 인터럽트(하드웨어 인터럽트)가 존재한다.

동기 인터럽트

  • CPU가 예기치 못한 상황을 접했을 때 발생
  • 실행하는 프로그래밍상의 오류와 같은 예외적인 상황에서 발생하는 인터럽트로 예외(Exception)라고 부름

동기 인터럽트에 존재하는 4개지 종류

비동기 인터럽트

  • 주료 입출력장치에 의해 발생
  • 알림과 같은 역할
  • 입출력 작업 도중에도 효율적으로 명령어를 처리하기 위해 사용한다.
    • 입출력장치는 CPU에 비해 느리다.
    • 인터럽트가 없다면 CPU는 프린트 완료 여부를 확인하기 위해서 주기적으로 확인해야 함
    • 인터럽트가 있다면 입출력 작업 동안 CPU는 다른 일을 할 수 있다.

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

✅ 인터럽트의 종류를 막론하고 인터럽트 처리 순서는 대동소이하다.

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

인터럽트 요청 신호

  • 인터럽트 요청 주체 (ex. 입출력장치)가 CPU에게 보내는 요청 신호
  • CPU가 인터럽트 요청을 받아들이려면 플래그 레지스터의 인터럽트 플래그가 활성화 되어있어야 한다.

플래그 레지스터에 있는 인터럽트 플래그가 1일때 인터럽트 요청을 받아들인다.

  • 모든 인터럽트를 인터럽트 플래그로 막을 수 있는 건 아니다. ➡️ 막을 수 없는 인터럽트(non maskable interrupt) 존재

인터럽트 플래그 비활성에도 발생하는 인터럽트가 있다! 😱

인터럽트 서비스 루틴

  • CPU가 인터럽트를 받아들이기로 했다면 인터럽트 서비스 루틴을 실행한다.
  • 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하는지 작성된 프로그램
  • 인터럽트 서비스 루틴도 프로그램이기 때문에 메모리에 저장된다.

인터럽트 벡터

  • 인터럽트를 보낼 수 있는 주체가 여러 개 ➡️ 각각의 인터럽트를 구분하기 위한 정보
  • 인터럽트 벡터는 인터럽트 서비스 루틴을 식별하기 위한 정보
  • 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴의 시작주소를 알아내고 실행한다.
CPU가 인터럽트를 처리한다 == 인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다 (+ 그리고 인터럽트의 시작 주소는 인터럽트 벡터를 통해 알 수 있다.)
인터럽트 서비스 루틴 실행 전의 CPU 수행 작업의 내역을 메모리 스택에 저장하고 인터럽트 서비스 루틴 종료 후 스택에 저장해 둔 값으로 작업을 재개한다.

인터럽트 사이클을 추가한 명령어 사이클


Chapter 5️⃣

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

앞선 내용 상기

  1. 컴퓨터 부품들은 ‘클럭 신호’에 맞춰 일사불란하게 움직인다.
  2. CPU는 ‘명령어 사이클’이라는 정해진 흐름에 맞춰 명령어들을 실행한다.

🤔 : 그럼 클럭 신호가 빠르게 반복되면 빠르고 많이 움직이는거 아니야?

✅ 일반적으로 옳다. 그렇기 때문에 CPU의 속도 단위로 간주되기도 한다.

 

클럭 속도

  • 헤르츠(Hz) 단위로 측정
  • 1 헤르츠는 1초에 클럭이 반복되는 횟수
  • 클럭이 1초에 한번 반복되면 1Hz, 1초에 100번 반복되면 100Hz
  • CPU 속도를 높이기 위해 클럭 속도를 높이게 되면 높은 발열과 전력소모량, 하드웨어적인 이슈로 인해 한계점이 존재

코어와 멀티코어

  • 코어
    • 전통적인 관점에서의 ‘명령어를 실행하는 부품’은 하나만 존재하지만 오늘날엔 여러 개가 존재한다.
    • ‘명령어를 실행하는 부품’을 코어라는 용어로 사용하고 있다.

많이 발전했네! 🥳

 

  • 멀티코어
    • 여러 개의 코어를 포함하고 있는 CPU
  • 코어를 증가함에 따라 비례적으로 CPU의 연산 속도가 증가하는가? ➡️ 그건 아님 (조별과제 😤)
  • 코어마다 처리할 명령어를 적절하게 분배하는 것에 따라 멀티코어의 연산 속도가 크게 달라진다.

스레드와 멀티스레드

  • 두가지의 종류로 구분지어 기억

 

하드웨어적 스레드 : 하나의 코어가 동시에 처리하는 명령어 단위

  • 하나의 코어에서 2개의 명령어를 동시에 처리할 수 있다면 1코어당 2스레드를 가진다. : 멀티스레드 CPU

딱 봐도 빨라 보인다.

 

✅ 하이퍼 스레딩 : 인텔 사의 멀티스레드 기술을 지칭

 

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

  • 하나의 프로그램에서 동시에 여러개의 영역이 동시에 실행된다.

1클럭에서 여러군데의 메모리 접근이 발생하면 멀티스레드 🤔

 

  • 1코어 1스레드의 CPU도 소프트웨어적으로 여러 스레드를 만들 수 있다.

 

멀티스레드 프로세서

  • 멀티스레드 프로세서를 설계하는 것은 매우 복잡 ➡️ 핵심은 레지스터
  • 하나의 명령어를 실행하기 위해 꼭 필요한 레지스터들을 편의상 ‘레지스터 세트’라고 표기 ➡️ 레지스터 세트가 여러개 있다면 하나의 코어가 여러개의 명령어를 실행할 수 있다.

레지스터 세트가 여러개!! 부자 된 기분!! 🤑

 

  • 멀티 스레드(ex. n스레드)의 작업 수행시 메모리 입장에선 작업 흐름이 동시에 n개 존재할 수 있다.
  • 메모리의 입장에선 하나의 명령어를 처리하는 CPU가 n개 있는 것처럼 보인다. ➡️ 그래서 하드웨어 스레드를 논리 프로세서(logical processor)라고 부르기도 한다.

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

명령어 파이프라인

  • 명령어가 처리 되는 과정을 비슷한 시간 간격으로 나누면?
    1. 명령어 인출(Instruction Petch)
    2. 명령어 해석(Instruction Decode)
    3. 명령어 실행(Execute Instruction)
    4. 결과 저장 (Write Back)
    ✅ 명령어 인출 ➡️ 명령어 실행으로 나누기도 하고, 명령어 인출 ➡️ 명령어 해석 ➡️ 메모리 접근 ➡️ 결과 저장으로 나누기도 한다.
  • 같은 단계가 겹치지만 않으면 CPU는 ‘각 단계를 동시에 실행할 수 있다’

단위 시간(tn)마다 실행되는 명령어들, 1클럭당 실행되는 명령어인가?! 👻👻

 

  • t2의 경우 명령어 1의 실행과 명령어 2의 해석과 명령어 3의 인출을 동시에 실행 중이다.
  • 명령어들을 명령어 파이프라인에 넣고 동시에 처리하는 기법을 명령어 파이프라이닝이라고 한다.
  • 파이프라인 위험 : 파이프라이닝으로 특정 상황에서 성능 향상에 실패하는 경우

파이프라인 위험의 3 종류

 

이터 위험

  • 명령어 간 의존성에 의해 발생
  • 모든 명령어를 동시에 처리할 수는 없다 ➡️ 이전 명령어를 끝까지 실행해야만 비로소 실행할 수 있는 경우

제어 위험

  • 프로그램 카운터의 갑작스러운 변화 : JUMP 명령어 같은 것
  • 명령어 파이프라인에 미리 가지고 와서 처리 중이었던 명령어들이 아무 쓸모 없어짐
  • 분기 예측(branch prediction) : 프로그램이 어디로 분기할지 미리 예측한 후 그 주소를 인출하는 기술로 예방한다.

으악! 기껏 파이프라이닝으로 열심히 작업했는데!! 🙀

 

구조적 위험

  • 서로 다른 명령어가 같은 CPU 부품(ALU, 레지스터)를 쓰려고 할 때 발생
  • 자원 위험(resource hazard)이라고도 부른다.

슈퍼스칼라

  • CPU 내부에 여러 개의 명령어 파이프라인을 포함한 구조 (오늘날의 멀티스레드 프로세서)

명령어 파이프라인 그림과 다른점은 단위시간에 같은 명령어를 2개씩 처리하고 있다는 점! 🤭

  • 이론적으로는 파이프라인 개수에 비례해서 처리 속도가 증가
  • 하지만 파이프라인 위험도의 증가로 인해 파이프라인 개수에 비례해서 처리 속도가 증가하진 않음

비순차적 명령어 처리

  • OoOE : Out of order execution
  • 명령어들간의 합법적인 새치기

합법이라도 열 받을거 같은데? 😡

 

  • 의존성이 없는 명령어의 순서를 바꿔서 파이프라인 위험을 벗어나 실행된다.
  • 명령어를 순차적으로만 실행하지 않고 순서를 바꿔 실행해도 무방한 명령어를 먼저 실행하여 명령어 파이프라인이 멈추는 것을 방지하는 기법 ➡️ 비순차적 명령어 처리 기법
  • 비순차적 명령어 처리가 가능한 CPU는 명령어들이 어떤 명령어와 데이터 의존성을 가지고 있는지, 순서를 바꿔 실행할 수 있는 명령어에는 어떤 것들이 있는지를 판단할 수 있어야 한다.

✅ 요약 : 비순차적 명령어 처리 기법은 파이프라인의 중단을 방지하기 위해 명령어를 순차적으로 처리하지 않는 명령어 병렬 처리 기법

 

05-3 CISC와 RISC

명령어 집합 (구조)

  • 명령어 집합 또는 명령어 집합 구조 (이하 ISA) : CPU가 이해할 수 있는 명령어들의 모음
  • ISA가 다르면 서로의 명령어를 이해할 수 없기 때문에 ISA는 일종의 CPU의 언어인 셈
  • ISA가 다르면 생김새 뿐만 아니라 제어장치가 명령어를 해석하는 방식, 사용하는 레지스터의 종류와 갯수 등 CPU 하드웨어 설계에도 영향을 미친다.

소프트웨어'만' 다른게 아니라 파급력이 크다!

 

CISC (Complex Instruction Set Computer)

  • 복잡한 명령어 집합을 활용하는 컴퓨터 (CPU)
  • x86, x86-64는 CISC 기반 명령어 집합 구조를 이용하고 있다.
  • 복잡하고 다양한 명령어 활용
  • 명령어의 형태와 크기가 다양한 가변 길이의 명령어를 활용

CISC의 매력어필 🤗

 

  • 다양하고 강력한 명령어를 활용
  • 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다.
  • 메모리를 최대한 아끼며 개발해야 했던 시절에 인기가 높았음
  • 명령어 파이프라이닝이 불리하다는 치명적인 단점이 존재
    • 명령어가 워낙 복잡하고 다양한 기능을 제공하는 탓에 명령어의 크기와 실행되기까지의 시간이 일정하지 않음
    • 복잡한 명령어 때문에 명령어 하나를 실행하는 데에 여러 클럭 주기가 필요
    • 대다수의 복잡한 명령어는 사용 빈도가 낮다.

매력어필에 넘어갈뻔 했는데 이런 치명적인 단점이?

 

RISC (Reduced Instruction Set Computer)

  • 명령어의 종류가 적고, 짧고 규격화된 명령어 사용

레고 블럭 조립하듯이 차곡차곡

  • 명령어 파이프라이닝에 유리함
  • 메모리 접근 최소화 (load, store만 사용하도록 제한), 레지스터를 십분 활용한다.
    • CISC 보다 범용 레지스터가 더 많다.
  • 사용 가능한 명령어 개수가 CISC보다 적기 때문에 CISC보다 더 많은 명령어로 프로그램을 동작

 

ISA 차이점 요약 도표

CISC RISC
복잡하고 다양한 명령어 단순하고 적은 명령어
가변 길이 명령어 고정 길이 명령어
다양한 주소 지정 방식 적은 주소 지정 방식
프로그램을 이루는 명령어의 수가 적음 프로그램을 이루는 명령어의 수가 많음
여러 클럭에 걸쳐 명령어를 수행 1클럭 내외로 명령어 수행
파이프라이닝하기 어려움 파이프라이닝하기 쉬움

✅ 요즘 CPU에선 CISC라도 단점을 보완하고자 CISC의 실제 실행시에 명령어를 마이크로 명령어로 쪼개어 수행하여 내부적으론 RISC 처럼 동작한다.

+ Recent posts