공부/혼자 공부하는 컴퓨터 구조+운영체제

컴퓨터 구조(1장~8장) 개념 정리

hsb_02 2024. 6. 6. 15:57

1장 컴퓨터 구조 시작하기

1-1. 컴퓨터 구조를 알아야 하는 이유

 

프로그래밍 강의나 책에 나오는 코드를 똑같이 따라 작성했는데도 코드가 제대로 작동하지 않는 경우가 많다.

 

 

 

만약 컴퓨터 구조를 이해하고 있다면 문제 상황을 빠르게 진단할 수 있고, 문제 해결의 실마리를 다양하게 찾을 수 있다.

 

 

컴퓨터 구조를 아는 이들에게는 컴퓨터란 '미지의 대상'이 아닌 '분석의 대상'이 되는 것이다.

 

 

 

 

 

1-2. 컴퓨터 구조의 큰 그림

 

우리가 알아야 할 컴퓨터 구조 지식은 크게 '컴퓨터가 이해하는 정보'와 '컴퓨터의 네 가지 핵심 부품'으로 나뉜다.

 

 

 

 

컴퓨터는 0과 1로 표현된 정보만을 이해한다. 0과 1로 표현되는 정보에는 크게 두 종류가 있는데, 바로 데이터명령어이다.

'1'과 '2'는 데이터이고, '더하라 1과 2를'은 명령어이다.

 

 

 

 

 

컴퓨터의 4가지 핵심 부품은 CPU, 메인 메모리, 보조기억장치, 입출력 장치로 나뉜다.

 

 

 

 

 

  • 메모리는 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품
  • CPU는 컴퓨터의 두뇌, 메모리에 저장된 명령어를 읽어 들이고, 읽어 들인 명령어를 해석하고 실행하는 부품
    • ALU는 컴퓨터 내부에서 수행되는 계산을 도맡는 부품
    • 레지스터는 CPU 내부의 작은 임시 저장 장치
    • 제어장치는 제어 신호라는 전기 신호를 내보내고 메모리로부터 명령어를 읽어와 해석하는 장치
  • 입출력장치는 마이크, 스피커, 프린터, 마우스, 키보드처럼 외부에 연결되어 컴퓨터 내부와 정보를 교환하는 장치를 의미
  • 컴퓨터의 핵심 부품들은 모두 메인보드라는 판에 연결
  • 컴퓨터 내부에는 다양한 종류의 통로, 즉 버스가 존재함. 하지만 여러 버스 가운데 컴퓨터의 네 가지 핵심 부품을 연결하는 가장 중요한 버스는 시스템 버스

 

 

 

 

 

2장 데이터

 

 

2-1. 0과 1로 숫자를 표현하는 방법

 

컴퓨터는 0 또는 1밖에 이해하지 못한다.

 

0과 1을 나타내는 가장 작은 정보 단위를 비트(bit)라고 한다.

 

프로그램의 크기를 말할 때는 표현의 편의를 위해 비트보다 큰 단위를 이용한다.

 

 

0과 1만으로 모든 숫자를 표현하는 방법을 이진법(binary)이라고 한다. 이진법으로 표현한 수를 이진수라고 하며 이진수 앞에 0b를 붙여 표기한다.

 

우리는 일상적으로 십진법(decimal)을 사용한다. 십진법으로 표현한 수를 십진수라 하며 우리가 평소 사용하는 숫자가 이에 해당한다.

 

이진수의 음수를 표현하는 방법 중 가장 널리 사용되는 방법은 2의 보수이다.

 

모든 0과 1을 뒤집고, 거기에 1을 더한 값이 이진수의 음수이다.

 

하지만 이례적인 경우도 존재한다. -1101(2)를 표현하기 위한 음수로서의 0101(2)과 십진수 5를 표현하기 위한 양수로서의 0101(2)는 어떻게 구분할 것인가? 

 

컴퓨터 내부에서는 어떤 수를 다룰 때는 이 수가 양수인지 음수인지를 구분하기 위해 플래그(flag)를 사용한다.

 

 

 

 

2의 보수 표현의 한계로 인해 데이터를 표현할 때 십육진법(hexadecimal) 또한 자주 사용한다. 십육진법은 수가 15를 넘어가는 시점에 자리 올림을 하는 숫자 표현 방식이다.

 

 

 

2-2. 0과 1로 문자를 표현하는 방법

 

컴퓨터가 인식하고 표현할 수 있는 문자의 모음을 문자 집합이라고 한다.

 

문자는 0과 1로 변환되어야만 비로소 컴퓨터가 이해할 수 있다. 이 변환 과정을 문자 인코딩이라 한다.

 

 

 

아스키는 영어 알파벳과 아라비아 숫자, 일부 특수 문자를 포함하는 문자 집합이다.

 

아스키 문자 집합에 속한 문자들은 각각 7비트로 표현되며 총 128(2^7)개의 문자를 표현할 수 있다.

(A = 65, a = 97)

 

 

 

EUC-KR은 한글 인코딩 방식인 완성형 인코딩 방식과 조합형 인코딩 방식 중 완성형 인코딩 방식이다.

 

한글 한 글자에 2바이트 코드가 부여되므로 한글 한 글자를 표현하려면 16비트가 필요하다. 그리고 16비트는 네 자리 십육진수로 표현이 가능하다.

 

즉, EUC-KR로 인코딩된 한글은 네 자리 십육진수로 나타낼 수 있다.(가 = b0a1, 거 = b0c5)

 

 

유니코드는 다양한 한글을 포함하며, 대부분 나라의 문자, 특수문자, 화살표나 이모티콘까지도 코드로 표현할 수 있는 통일된 문자 집합이다.

 

EUC-KR은 글자에 부여된 값을 그대로 인코딩 값으로 삼으나, 유니코드는 이 값을 다양한 방법(UTF-8, UTF-16, UTF-32)으로 인코딩한다.


 

 

 

 

3장 명령어

 

 

 

3-1. 소스코드와 명령어

 

컴퓨터는 명령어를 처리하는 기계다. 그렇다면 명령어는 컴퓨터를 실질적으로 작동시키는 매우 중요한 정보이다.

 

프로그래밍 언어로 만든 소스 코드는 컴퓨터 내부에서 명령어로 변환된다.

 

 

사람을 위한 언어를 고급 언어라고 하며, 컴퓨터가 직접 이해하고 실행할 수 잇는 언어를 저급 언어라고 한다.

 

 

저급 언어에는 두 가지 종류가 존재한다. 기계어어셈블리어이다.

 

기계어란 0과 1의 명령어 비트로 이루어진 명령어 모음이다.

 

0과 1로 표현된 명령어(기계어)를 읽기 편한 형태로 번역한 언어가 어셈블리어이다.

 

 

 

 

 

개발자들이 고급 언어로 작성한 소스 코드는 결국 저급 언어(기계어, 어셈블리어)로 변환되어 실행된다.

 

고급 언어가 저급 언어로 변환되는 방식에는 컴파일 방식인터프리트 방식이 존재한다.

 

 

컴파일 언어는 컴파일러에 의해 소스코드 전체가 저급 언어로 변환되어 실행되는 고급 언어이다.(대표적으로 C)

 

컴파일이 수행되면 소스 코드는 컴퓨터가 이해할 수 있는 저급 언어로 변환되는데, 컴파일러를 통해 저급 언어로 변환된 코드를 목적 코드(object code)라고 한다. 

 

목적 파일은 우리가 컴파일러(gcc)를 통해 컴파일한 후 나오는 .o 파일들을 말한다.

 

생성된 목적 파일들(.o)은 링킹이라는 작업을 통해 하나의 실행 파일을 결과로 내뱉는다.

 

 

 

 

인터프리터 언어는 인터프리터에 의해 소스 코드가 한 줄씩 실행되는 고급 언어이다.(대표적으로 Python)

 

 

 

 

 

한번에 소스코드 전체를 저급 언어로 변환하는 컴파일 방식이 소스코드를 한 줄씩 실행시키는 인터프리터 언어보다 속도가 빠르다.

 

 

3-2. 소스코드와 명령어

 

명령어는 연산 코드오퍼랜드로 나뉜다.

명령어가 수행할 연산을 연산 코드라 하고, 연산에 사용할 데이터 또는 연산에 사용할 데이터가 저장된 위치를 오퍼랜드라고 한다.

 

 

 

오퍼랜드 필드에는 숫자와 문자 등을 나타내는 데이터 또는 메모리나 레지스터 주소가 올 수 있다. 그래서 오퍼랜드 필드를 주소 필드라고 부르기도 한다.

 

다음은 오퍼랜드의 개수에 따른 명령어의 종류이다.

 

 

 

 

연산 코드의 종류는 매우 많으나, 크게 네 가지로 나눌 수  있다.

 

1. 데이터 전송

 

2. 산술/논리 연산

 

3. 제어 흐름 변경

 

4. 입출력 제어

 

 

 

 

오퍼랜드 필드에 메모리나 레지스터의 주소를 담는 이유는 명령어 길이 때문이다.

 

다음은 오퍼랜드 개수에 따른 명령어에서 표현할 수 있는 데이터 크기를 보여주는 그림이다.

 

2-주소 명령어가 3-주소 명령어보다 큰 데이터를 담을 수 있음을 확인 가능하다.

 

 

 

 

만약 오퍼랜드 필드에 메모리 주소가 명시된다면 표현할 수 있는 정보의 가짓수가 확 커지게 된다. 

2^4의 크기만을 담을 수 있었지만, 2^16을 담을 수 있게 되었다.

 

 

 

 

 

 

 

오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때 연산에 사용할 데이터 위치를 찾는 방법을 주소 지정 방식이라고 한다. 

 

 

 

1. 즉시 주소 지정 방식연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식이다.

 

 

2. 직접 주소 지정 방식오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식이다.

 

3. 간접 주소 지정 방식유효 주소의 주소를 오퍼랜드 필드에 명시한다. 다만 두 번의 메모리 접근이 필요하기 때문에 앞서 설명한 방식들보다 일반적으로 느리다.

 

 

4. 레지스터 주소 지정 방식은 직접 주소 지정 방식과 비슷하게 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방법이다.

 

 

5. 레지스터 간접 주소 지정 방식은 연산에 사용할 데이터를 메모리에 저장하고, 그 주소를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법이다. 간접 주소 지정 방식과 비슷하나, 메모리에 접근하는 횟수가 한번으로 줄어든다는 장점이 있다.


 

 

 

4장 CPU의 작동 원리

 

 

4-1. ALU와 제어장치

 

<ALU>

 

아래 그림은 ALU가 어떤 정보를 받아들이고 내보내는지를 표현한 그림이다.

 

ALU는 계산하는 부품이기에 두 개의 피연산자수행할 연산이 필요하다.

 

그래서 ALU는 레지스터(Register)를 통해 피연산자를 받아들이고, 제어장치(Control Unit)로부터 수행할 연산을 알려주는 제어 신호를 받아들인다.

 

 

 

ALU가 내보내는 정보에는 연산을 수행한 결과플래그가 있다.

 

연산을 수행한 결과는 특정 숫자나 문자가 될 수도 있고, 메모리 주소가 될 수도 있다. 그리고 이 결괏값은 일시적으로 레지스 터에 저장된다.(메모리 접근이 느리기 때문)

 

이진법 2의 보수의 개념에서 음수와 양수를 구분하기 위해 플래그를 사용한다고 했었다. ALU는 결괏값뿐만 아니라 연산 결과에 대한 추가적인 정보를 내보내야 할 때가 있다.

 

연산 결과에 대한 추가적인 상태 정보를 플래그(flag)라고 한다.

 



<제어장치(Control Unit)>

 

제어장치는 제어 신호를 내보내고, 명령어를 해석하는 부품이다.

 

그리고 제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호이다.

 

다음은 제어장치가 받아들이고 내보내는 것들을 표현한 그림이다.

 

 

제어장치가 받아들이는 정보에는 4가지가 존재한다.

 

  1. 제어장치는 클럭 신호를 받아들인다. 클럭이란 컴퓨터의 모든 부품을 움직일 수 있게하는 시간 단위이다. 
  2. 제어장치는 해석해야 할 명령어를 받아들인다. CPU가 해석해야 할 명령어는 명령어 레지스터라는 레지스터에 저장되며 제어장치는 이로부터 해석할 명령어를 받아들이고, 제어 신호를 발생시킨다.
  3. 제어장치는 플래그 레지스터플래그 값을 받아들인다. 제어장치는 이를 참고하여 제어 신호를 발생시킨다.
  4. 제어장치는 시스템 버스, 그 중에서 제어 버스로 전달된 제어 신호를 받아들인다.

 

 

 

제어장치가 내보내는 정보(제어 신호)는 크게 CPU 외부(메모리나 입출력 장치)와 CPU 내부(ALU와 레지스터)로 나뉜다.

 

 

 

4-2. 레지스터

 

다음은 반드시 알아야 할 레지스터의 종류이다.

 

 

 

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

 

2. 명령어 레지스터(IR:Instruction Register)는 해석할 명령어, 즉 방금 메모리에서 읽어 들인 명령어를 저장하는 레지스터이다.

 

3. 메모리 주소 레지스터(MAR:Memory Address Register)는 메모리의 주소를 저장하는 레지스터이다.

 

4. 메모리 버퍼 레지스터(MBR:Memory Buffer Register)는 메모리와 주고받을 값을 저장하는 레지스터이다.

 


다음의 예를 통해 위의 네 개의 레지스터(PC, IR, MAR, MBR)에 각각 어떤 값이 담기는지를 알아볼 수 있다.

 

 

1. CPU로 실행할 프로그램이 메모리의 1000번지부터 1500번지까지 저장되어 있다고 가정한다.

 

2. 프로그램을 처음부터 실행하기 위해 프로그램 카운터(PC)에는 1000이 저장된다.

 

3. 1000번지를 읽어 들이기 위해서는 주소 버스로 1000번지를 내보내야 한다. 이를 위해 메모리 주소 레지스터(MAR)에는 1000이 저장된다.

 

4. 메모리 읽기 제어 신호와 메모리 주소 레지스터 값이 각각의 버스를 통해 메모리로 보내진다.

 

 

5. 메모리 1000번지에 저장된 값은 데이터 버스를 통해 메모리 버퍼 레지스터(MBR)로 전달되고, 프로그램 카운터는 증가되어 다음 명령어를 읽어 들일 준비를 한다.

 

6. 메모리 버퍼 레지스터에 저장된 값은 명령어 레지스터(IR)로 이동한다.

 

7. 제어장치는 명령어 레지스터의 명령어를 해석하고 제어 신호를 발생시킨다.


 

 

 

 

5. 범용 레지스터데이터와 주소를 모두 저장할 수 있는, MBR(데이터)과 MAR(주소)과는 다른 레지스터이다.

 

 

6. 플래그 레지스터는 ALU 연산 결과에 따른 플래그를 저장하는 레지스터이다.

 

 

 

 

3장의 마지막에 레지스터를 이용한 주소 지정 방식 두 가지(레지스터 주소 지정 방식, 레지스터 간접 주소 지정 방식) 를 배웠었다.

 

7. 스택 포인터스택 주소 지정 방식이라는 주소 지정 방식에 사용되고, 스택 최상단의 위치를 저장한다.

 

8. 베이스 레지스터는 프로그램 카운터와 함께 변위 주소 지정 방식(상대 주소 지정, 베이스 레지스터 주소 지정)이라는 주소 지정 방식에 사용되고, 베이스 레지스터에 저장된 주소는 기준 주소로서의 역할을 한다.

 

 

 

 

 

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

 

3장에서 명령어, 4-1과 4-2를 통해 CPU의 각 부품(ALU, 제어장치, 레지스터)들이 하는 일을 배웠다.

 

CPU가 하나의 명령어를 처리하는 과정에는 정해진 흐름이 있고, CPU는 그 흐름을 반복하여 명령어들을 처리해 나간다.

 

이렇게 하나의 명령어를 처리하는 정형화된 흐름을 명령어 사이클이라고 한다.

 

간혹 이 흐름이 끊어지는 상황을 인터럽트라고 한다.

 

  • 메모리에 있는 명령어를 CPU로 가지고 오는 단계를 인출 사이클(fetch cycle)이라고 한다. 4-2 레지스터 파트에서 02단계에서 06단계까지가 인출 사이클의 과정이다.
  • CPU로 명령어를 인출했다면 명령어를 실행하는데 이를 실행 사이클(execution cycle)이라고 한다.
  • 우리는 간접 주소 지정 방식을 배웠었다. 명령어를 인출하여 CPU로 가져왔다 하더라도 메모리 접근을 한번 더 해야하는 특성으로 인해 간접 사이클(indirect cycle) 단계가 추가된다.

 

 

 

인터럽트의 종류에는 크게 동기 인터럽트와 비동기 인터럽트가 있다.

 

동기 인터럽트는 CPU에 의해 발생하는 인터럽트이며, 예외(exception)라고 부른다.

 

 

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

 

 

 

하드웨어 인터럽트는 알림과 같은 인터럽트이다.

 

다음은 하드웨어 인터럽트 처리 순서이다.

 

 

 

인터럽트 요청 신호란, 누군가(I/O장치)가 "지금 끼어들어도 되나요?"하고 CPU에 물어보는 행위이다.

 

 

 

이때, CPU가 인터럽트 요청을 수용하기 위해서는 플래그 레지스터의 인터럽트 플래그가 활성화되어 있어야 한다.

 

다만, 모든 하드웨어 입터럽트를 인터럽트 플래그로 막을 수는 없다. 정전이나 하드웨어 고장같은 경우들을 말한다.

 

 

 

CPU가 인터럽트 요청을 받아들이기로 했다면 CPU는 인터럽트 서비스 루틴이라는 메모리에 저장되어있는 프로그램을 실행한다. 이는 인터럽트 핸들러라고도 불린다.

 

 

 

 

 

그렇다면 CPU는 각기 다른 인터럽트 서비스 루틴을 구분할 줄 알아야 한다. 이를 위해 인터럽트 벡터를 이용한다. 

 

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

 

 

 

 

정리하자면, CPU가 인터럽트를 처리한다는 말은 인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다는 말과 같다.

 

 

 

그렇다면 고려해야 할 부분이 존재한다. 인터럽트가 발생하기 전까지 레지스터에 저장되어 있었던 값들은 어떻게 할 것인가?

 

다음의 그림처럼 프로그램 카운터에 저장되어 있던 1500은 인터럽트 요청 발생 시 값이 10(인터럽트 서비스 루틴 주소)으로 덮어지는 것인가?

 

 

 

 

그렇지 않다. 인터럽트 서비스 루틴이 끝나면 되돌아와서 마저 수행을 해야 하기 때문에 지금까지의 작업 내역들은 메모리의 스택 영역에 백업된다.

 

 

 

 

 

지금까지 하드웨어 인터럽트(비동기 인터럽트)에 대해서 알아봤다. 

 

동기 인터럽트(예외) 또한 여러 종류로 나뉜다.

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

 

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

 

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

 

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


 

 

 

5장 CPU 성능 향상 기법

 

 

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

 

 

<클럭>

 

4장에서 클럭이란 개념이 나왔었다. 배운 내용은 다음과 같다.

 

1. 컴퓨터 부품들은 클럭 신호에 맞춰 일사불란하게 움직인다.

2. CPU는 명령어 사이클이라는 정해진 흐름에 맞춰 명령어들을 실행한다.

 

 

그렇다면 클럭 속도가 빠른 CPU는 성능이 좋다고 말할 수 있을 것이다.

 

클럭 속도는 헤르츠(Hz)단위로 측정한다. 이는 1초에 클럭이 몇번 반복되는지를 나타낸다.

 

가령 클럭이 1초에 한 번 반복되면 CPU 클럭 속도는 1Hz라는 것이다.

그렇다면 위 컴퓨터의 클럭 속도는 2.5GHz(base) ~ 4.9GHz(max)번 반복된다는 것을 알 수 있다. 이는 1초에 클럭이 기본적으로 25억번, 순간적으로 최대 49억번 반복된다는 것이다.

 

 

클럭 속도를 무지막지하게 높이면 발열 문제가 심각해지기 때문에 클럭 속도만으로 CPU의 성능을 올리는 것에는 한계가 있다.

 

 

클럭 속도를 높이는 방법 외에 CPU의 성능을 높이는 방법엔 CPU의 코어와 스레드 수를 늘리는 방법이 있다.

 

 

위의 문구가 무엇을 의미하는가? 인텔 5세대 CPU를 탑재한 내 컴퓨터의 사양을 보여주고 있다.

 

위의 표를 참고하면 내 컴퓨터는 인텔 5세대(코어 i5) CPU를 탑재한 컴퓨터이고 6개의 코어와 12개의 스레드를 가지고 있음을 알 수 있다.

 

 

 

 

<코어>

 

코어를 이해하기 위해서는 CPU라는 용어를 재해석 해야한다.

 

CPU는 명령어를 실행하는 부품이였다. 오늘날 이 정의는 코어라는 용어로 사용된다.(의미가 전가된 것이다)

 

다시 말해, 오늘날의 CPU는 단순히 명령어를 실행하는 부품에서 명령어를 실행하는 부품을 여러 개 포함하는 부품으로 명칭의 범위가 확장되었다.

코어를 여러개 포함하고 있는 CPU를 멀티코어 CPU , 또는 멀티코어 프로세서라고 부른다.

가령 클럭 속도가 2.4GHz인 단일 코어 CPU와 / 클럭 속도가 1.9GHz인 멀티 코어 CPU를 비교하면 후자의 성능이 더 좋다.

 

그렇다고 코어를 많이 늘리면 늘릴수록 정비례로 연산 처리 속도가 빨라지지는 않는다.

 

이는 100인분의 도시락은 한 명의 요리사가 만드는 것보다 열 명의 요리사가 만드는 것이 열배가 빠르지만, 4인분의 도시락은 열명의 요리사가 만드는 게 다섯 명의 요리사가 만드는 것보다 특별히 더 빠르지 않은 것과 같다.

 

 

 

 

 

 

<스레드>

 

스레드의 사전적 의미는 실행 흐름의 단위이다. 스레드는 CPU와 프로그래밍에서 사용되는 용도가 다르므로 각각의 용도를 파악하고 있어야 한다.

 

 

CPU에서 사용되는 스레드는 하드웨어(HW)적 스레드라 부르며,

프로그램에서 사용되는 스레드는 소프트웨어(SW)적 스레드이다.

 

 

스레드를 하드웨어적(CPU에서 사용되는)으로 정의하면 '하나의 코어가 동시에 처리하는 명령어 단위'를 의미한다.

 

 

지금까지는 한 번에 하나의 명령어(1 스레드)를 실행하는 CPU를 가정했다.

 

 

위의 그림은 2코어 4스레드 CPU로 명령어를 실행하는 부품(코어)를 두 개 포함하고, 한 번에 네 개의 명령어를 처리(스레드)할 수 있는 CPU이다.

 

 

이처럼 하나의 코어로 여러 명령어를 동시에 처리하는 CPU를 멀티스레드 CPU, 멀티스레드 프로세서라고 한다.

 

 

 

 

스레드를 소프트웨어적으로 정의(프로그램에서 사용되는)하면 하나의 프로그램에서 독립적으로 실행하는 단위를 의미한다. 프로그래밍 언어나 운영체제를 학습할 때 접하는 스레드가 소프트웨어적으로 정의된 스레드이다.

 

하나의 프로그램은 실행되는 과정에서 한 부분만 실행될 수도 있지만, 프로그램의 여러 부분이 동시에 실행될 수도 있다.

 

 

 

 

 

 

 

멀티스레드 프로세서, 즉 하나의 코어로 여러 명령어를 동시에 처리하는 CPU는 하드웨어 스레드라고도 지칭된다.

 

멀티스레드 프로세서의 가장 큰 핵심은 레지스터이다.

 

하나의 코어로 여러 명령어를 동시에 처리하도록 만들려면 프로그램 카운터(PC), 스택 포인터,

데이터 버퍼 레지스터(MBR), 데이터 주소 레지스터(MAR)와 같이 하나의 명령어를 처리하기 위해 필요한 레지스터를 여러 개 가지고 있으면 된다.

 

 

꼭 필요한 레지스터들을 편의상 레지스터 세트라고 지칭하고 보면 멀티스레드 프로세서는 다음의 그림으로 나타내질 수 있다.

ALU와 제어장치가 두 개의 레지스터 세트에 저장된 명령어를 해석하고 실행하면 하나의 코어에서 두 개의 명령어가 동시에 실행된다.

(즉, 레지스터 세트가 스레드의 역할을 한다는 것이다)

 

하드웨어 스레드는 메모리 속 프로그램 입장(소프트웨어적)에서 봤을 때 마치 한 번에 하나의 명령어를 처리하는 CPU나 다름없다.

 

가령 2코어 4스레드 CPU는 한 번에 네 개의 명령어를 처리할 수 있는데, 이는 프로그램 입장에서 CPU가 네 개 있는 것 처럼 보인다. 그래서 하드웨어 스레드를 논리 프로세서라고 부르기도 한다.

 

 

 

정리하자면, 

 

코어명령어를 실행할 수 있는 하드웨어 부품이다.

 

CPU명령어를 실행하는 부품을 여러 개 포함하는 부품이다.

 

스레드명령어를 실행하는 단위이다.

 

멀티코어 프로세서명령어를 실행할 수 있는 하드웨어 부품이 CPU 안에 두 개 이상 있는 CPU를 의미한다.

 

멀티스레드 프로세서(하드웨어 스레드, 논리 프로세서)하나의 코어로 여러개의 명령어(스레드)를 동시에 실행할 수 있는 CPU를 의미한다.

 

 

 

 

 

5-2. 명령어 병렬 처리 기법

 

 

빠른 CPU를 위해서는 높은 클럭 속도, 멀티코어, 멀티스레드가 필요하지만, CPU가 놀지 않고 시간을 알뜰하게 쓰며 작동하게 만드는 것도 중요하다.

 

 

명령어를 동시에 처리하며 CPU를 한시도 쉬지 않고 작동시키는 기법인 명령어 병렬 처리 기법(명령어 파이프라이닝, 슈퍼스칼라, 비순차적 명령어 처리)을 알아보자.

 

 

 

 

 

<명령어 파이프라이닝>

 

명령어 파이프라인을 이해하기 위해서는 명령어 처리 과정을 클럭 단위로 나누어보아야 한다.

 

명렁어 처리 과정을 클럭 단위로 다음과 같이 나눌 수 있다.

 

1. 명령어 인출

2. 명령어 해석 

3. 명령어 실행

4. 결과 저장

파이프라이닝의 중요한 개념은 같은 단계가 겹치지만 않는다면 CPU는 각 단계를 동시에 실행할 수 있다는 것이다.

 

 

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

 

파이프라이닝이 높은 성능을 가져오지만 특정 상황에서는 성능 향상에 실패한다. 이 상황을 파이프라인 위험이라고 부르며, 크게 데이터 위험, 제어 위험, 구조적 위험이 있다.

 

 

데이터 위험(data hazard)명령어 간 데이터 의존성에 의해 발생한다.

위의 경우 명령어 1을 수행해야만 명령어 2를 수행할 수 있다. 명령어 2는 명령어 1의 데이터(R1)에 의존적인 것이다.

 

이 같이 데이터 의존적인 두 명령어를 실행하려 할 때 파이프라인이 작동하지 않는 것을 데이터 위험이라고 한다.

 

 

 

제어 위험(control hazard)은 분기 등으로 인한 프로그램 카운터의 갑작스러운 변화에 의해 발생한다.

만약 10번지 명령어가 60번지로 분기한다면 다음 프로그램 카운터는 61이 될 것 이므로 처리 중이었던 11번지 명령어와 12번지 명령어는 아무 쓸모가 없어진다. 이를 제어 위험이라고 한다.

 

 

 

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

 

 

 

 

 

<슈퍼스칼라>

 

슈퍼스칼라는 쉽게 말하자면 다중 파이프라인 구조이다. 즉 여러 개의 명령어 파이프라인을 포함한 구조가 슈퍼스칼라인 것이다.

 

슈퍼스칼라 구조로 명령어 처리가 가능한 CPU를 슈퍼스칼라 프로세서 또는 슈퍼스칼라 CPU라고한다. 가령 멀티스레드 프로세서(다중 레지스터 세트를 가진 CPU)는 한 번에 여러 명령어를 인출하고, 해석하고, 실행할 수 있기 때문에 슈퍼스칼라 구조를 사용할 수 있다.

 

 

 

 

 

<비순차적 명령어 처리 기법>

 

비순차적 명령어 처리 기법은 이름에서도 알 수 있듯 명령어들을 순차적으로 실행하지 않는 기법이다. 명령어의 합법적인 새치기라고 볼 수도 있다.

 

 

예를 들어 아래와 같은 명령어들로 이루어진 소스 코드가 있다고 해보자.

 

 

3번을 실행하기 위해서는 1번과 2번이 실행되어야만 한다. 즉 3번 명령어를 실행하기 위해서는 1번과 2번 명령어 실행이 끝날 때까지 기다려야 한다.

 

 

 

여기서 비순차적 명령어 처리 기법을 사용하여 3번을 제일 뒤로 보내면 명령어 파이프라인이 멈추는 것을 방지할 수 있게된다.

 

 

 

 

 

다만 아무 명령어나 순서를 바꿔서 수행할 수는 없다. 다음의 예시를 보자.

3번은 1번과 2번이 실행되어야만 실행되는 명령어이다.

 

4번은 2번과 3번이 실행되어야만 실행되는 명령어이다.

 

 

즉, 위 코드에서 3번 명령어와 1번 명령어를 바꿀 수 없을 뿐더러 마찬가지로 4번 명령어와 1번 명령어는 순서를 바꿀 수 없다.

 

1번 명령어를 토대로 3번 명령어가 수행되고, 3번 명령어를 토대로 4번 명령어가 수행되기 대문이다.

 

다만 위 코드에서 4번과 5번 명령어는 순서를 바꾸어 실행할 수 있다. 전체 프로그램의 실행 흐름에 영향을 끼치지 않기 때문이다.

 

 

 

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

 

 

 

 

5-3. CISC와 RISC

 

CPU가 파이프라이닝과 슈퍼스칼라 기법을 효과적으로 사용하려면 CPU가 인출하고 해석하고 실행하는 명령어가 파이프라이닝 하기 쉽게 생겨야 한다.

 

 

'파이프라이닝 하기 쉬운 명령어'를 알아보기 위해 CPU의 언어인 ISA와 각기 다른 성격의 ISA를 기반으로 설계된 CISC와 RISC를 알아볼 것이다.

 

 

<ISA>

 

CPU가 이해할 수 있는 명령어들의 모음을 명령어 집합 도는 명령어 집합 구조(ISA, Instruction Set Architecture)라 한다.

 

즉, CPU마다 ISA가 다를 수 있다는 것이다.

 

예를 들어 동일한 소스 코드를 작성하고 ISA가 각각의 컴퓨터(x86-64, ARM)에서 어셈블리어로 컴파일하면 아래와 같은 결과가 나온다.

 

 

 

ISA가 같은 CPU끼리는 서로의 명령어를 이해할 수 있지만, ISA가 다르면 서로의 명령어를 이해할 수 없다.

 

 

즉, ISA란 CPU의 언어이자 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속이다.

 

 

<CISC>

 

CISC란 Complex Instruction Set Computer의 약자로 위의 x86-64가 대표적인 CISC 기반의 ISA이다.

 

CISC는 가변 길이 명령어를 활용하고 메모리에 접근하는 주소 지정 방식도 다양하다.

다양하고 강력한 명령어를 활용한다는 말은 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다는 것을 의미한다.

 

그 때문에 위의 x86-64의 ISA가 어셈블리어로 컴파일했을 때의 결과 코드는 ARM보다 짧음이 확인 가능하다.

 

 

적은 수의 명령어로 프로그램을 동작시키는 것은 장점이다.

 

다만, 활용하는 명령어가 워낙 복잡하고 다양한 기능을 제공하는 탓에 명령어의 크기와 실행되기까지의 시간이 일정하지 않다.

위의 이유로 CISC는 명령어 파이프라인이 제대로 동작하지 않는다. 이는 높은 성능을 내기에는 큰 애로사항일 수 밖에 없다.

 

 

 

<RISC>

 

CISC에서의 교훈을 통해 RISC는 '자주 쓰이는 기본적인 명령어를 작고 빠르게 만드는 것'을 토대로 등장했다.

 

RISC는 Reduced  Instruction Set Computer의 약자로 CISC에 비해 명령어의 종류가 적다.

 

제일 중요한 것은 RISC가 고정 길이 명령어를 활용한다는 것이다.

 

 

 

명령어가 규격화되어 있고, 하나의 명령어가 1클럭 내외로 실행되는 RISC는 명령어 파이프라이닝에 최적화되어 있다.

 

 

또, RISC는 메모리 접근을 단순화, 최소화하는 대신 레지스터를 적극적으로 활용하며 높은 성능을 발휘한다.

 

다음은 CISC와 RISC의 차이를 정리한 표이다.

 

 

 


 

6장 메모리와 캐시 메모리

 

 

6-1. RAM의 특징과 종류

 

 

지금까지의 '메모리'라는 용어는 RAM을 지칭해왔다.

 

RAM(메모리)에는 실행할 프로그램의 명령어와 데이터가 저장된다.

 

중요한 것은 RAM은 전원을 끄면 저장된 데이터와 명령어가 모두 날라가는 휘발성 저장 장치이다.

 

반면, 전원이 꺼져도 유지되는 저장 장치는 비휘발성 저장 장치라고 하며, 하드 디스크나 SSD, CD-ROM, USB 메모리와 같은 보조기억장치이다.

 

 

 

비휘발성 저장 장치(보조기억장치, DISK)에는 보관할 대상을 저장하고, 휘발성 저장장치(메모리, RAM)에는 실행할 대상을 저장한다.

 

CPU가 실행하고 싶은 프로그램이 보조기억장치에 있다면 이를 RAM으로 복사하여 저장한 뒤 실행한다.

 

 

 

 

<DRAM>

 

DRAM은 Dynamic RAM의 준말이며, 시간이 지나면 저장된 데이터가 점차 사라지는 RAM이다.

 

그렇기에 DRAM은 데이터의 소멸을 막기 위해 일정 주기로 데이터를 재활성화(다시 저장)해야 한다.

 

 

<SRAM>

SRAM은 Static RAM의 준말이며, 시간이 지나도 저장된 데이터가 사라지지 않는다.

 

당연히 데이터를 재활성화 할 필요도 없으며, DRAM보다 일반적으로 속도도 더 빠르다.

 

다만! 시간이 지나도 데이터가 사라지지 않는다고 해서 비휘발성 메모리인 것은 아니다!! SRAM도 전원이 공급되지 않으면 저장된 내용이 날라간다.

 

 

SRAM의 장점에도 불구하고 메모리로 사용되는 RAM은 보통 DRAM이다. 

 

다음의 표를 통해 메모리를 DRAM을 사용하는 이유를 파악할 수 있다.

 

SRAM은 캐시 메모리에서 사용된다.

 

 

 

 

<SDRAM>

 

이름만 보면 SRAM과 연관이 있을 것 같지만 전혀 아니다.

 

Synchronous Dynamic RAM의 준말로, 클럭 신호와 동기화된, 발전된 형태의 DRAM이다.

 

즉, SDRAM은 클럭에 맞춰 동작하며 클럭마다 CPU와 정보를 주고받을 수 있는 DRAM이다.

 

 

 

<DDR SDRAM>

 

Double Data Synchronous Dynamic RAM의 준말인 DDR SDRAM은 대역폭을 넓혀 속도를 빠르게 만든 SDRAM이다.

 

 

여기서 대역폭이란 데이터가 주고받는 길의 너비를 의미한다.

 

폭이 하나인 SDRAM을 SDR SDRAM으로 부르기도 한다.

 

 

 

DDR2 SDRAM은 4(2^2)개의 대역폭을 가진 SDRAM이다. 

 

 

자연스럽게 DDR3는 8(2^3), DDR4는 16(2^4)임을 알 수 있다.

 

 

 

6-2. 메모리의 주소 공간

 

메모리에 저장된 정보의 위치는 주소로 나타낼 수 있다.

 

사실 주소에는 두 종류가 있는데, 바로 물리 주소와 논리 주소이다.

 

 

물리 주소는 메모리 하드웨어가 사용하는 주소이고, 논리 주소는 CPU와 실행 중인 프로그램이 사용하는 주소이다.

 

 

CPU와 실행 중인 프로그램은 현재 메모리 몇번지에 무엇이 저장되어 있는지 다 알지 못한다.

 

 

메모리가 사용하는 물리 주소는 말 그대로 정보가 실제로 저장된 하드웨어상의 주소를 의미한다.

 

반면, CPU와 실행 중인 프로그램이 사용하는 논리 주소는 실행 중인 프로그램 각각에게 부여된 0번지부터 시작되는 주소를 의미한다.

 

 

다음의 그림과 같이 각각의 프로그램은 본인의 논리 주소를 0번지부터 가지고 있으며, 하드웨어상의 실제 주소인 물리 주소에도 저장되어 있음을 확인 가능하다.

 

 

 

 

 

CPU가 이해하는 주소가 논리 주소라고는 해도 CPU(논리)가 메모리(물리)와 상호작용하려면 논리 주소와 물리 주소 간의 변환이 이루어져야 한다.

 

 

 

 

 

논리 주소와 물리 주소 간의 변환은 CPU와 주소 버스 사이에 위치한 메모리 관리 장치(MMU, Memory Management Unit)라는 하드웨어에 의해 수행된다.

 

MMU는 베이스 레지스터를 가지고 있으며, CPU가 발생시킨 논리 주소에 베이스 레지스터 값을 더하여 논리 주소를 물리 주소로 변환한다.

 

 

즉, 베이스 레지스터는 프로그램의 가장 작은 물리 주소, 다시 말해 프로그램의 첫 물리 주소를 저장하는 셈이고,

논리 주소는 프로그램의 시작점으로부터 떨어진 거리인 셈이다.

 

 

 

 

다만 MMU를 사용하면 프로그램의 논리 주소 영역을 벗어나는 실제 메모리(물리 주소)를 보호하지 못하는 경우가 발생한다.

 

 

 

이를 방지하기 위해서 한계 레지스터라는 레지스터가 실행 중인 프로그램이 다른 프로그램에 영향을 받지 않도록 보호해준다.

 

 

베이스 레지스터가 실행 중인 프로그램의 가장 작은 물리 주소를 저장한다면, 한계 레지스터는 논리 주소의 최대 크기를 저장한다.

 

 

 

만약 CPU가 한계 레지스터보다 높은 논리 주소에 접근하려고 하면 인터럽트(트랩)을 발생시켜 실행을 중단한다.

 

6-3. 캐시 메모리

 

CPU가 메모리에 접근하는 시간은 CPU의 연산 속도보다 느리다.

 

 

이를 극복하기 위한 저장 장치가 바로 캐시 메모리(SRAM)이다.

 

 

컴퓨터를 사용하는 저장 장치들은 CPU에 얼마나 가까운가를 기준으로 계층적으로 나타낼 수 있으며,

 

이를 저장 장치 계층 구조(Memory Hierachy)라고 한다.

 

 

캐시 메모리는 L1, L2, L3 캐시로 종류가 나뉘어져 있으며 코어와 가장 가까운 메모리를 L1, 그 다음을 L2, 그 다음을 L3라 지칭한다. 

 

일반적으로 L1 캐시와 L2 캐시는 코어 내부에, L3 캐시는 코어 외부에 위치해 있다.

 

 

 

 

 

캐시 메모리는 CPU가 사용할 법한 대상을 예측하여 저장한다.

 

예측한 데이터가 실제로 들어맞아 캐시 메모리 내 데이터가 CPU에서 활용된 경우를 캐시 히트라 한다.

 

예측이 틀려 메모리에서 필요한 데이터를 직접 가져와야 하는 경우를 캐시 미스라 한다.

 

캐시가 히트되는 비율을 캐시 적중률이라 하며, 다음과 같이 계산한다.

 

 

 

 

캐시 메모리는 참조 지역성의 원리에 따라 메모리로부터 가져올 데이터를 결정한다.

 

 

참조 지역성의 원리는 크게 시간 지역성, 공간 지역성으로 나뉜다.

 

시간 지역성은 최근에 접근했던 메모리 공간에 접근하려는 경향이다.

 

공간 지역성은 접근한 메모리 공간 근처를 접근하려는 경향이다.

 

 


 

 

7장 보조기억장치

 

 

7-1. 다양한 보조기억장치

 

가장 대중적인 보조기억장치는 하드 디스크와 플래시 메모리

 

 

플래시 메모리는 우리가 흔히 사용하는 USB 메모리, SD 카드, SSD와 같은 저장 장치를 말함

 

 

 

하드 디스크

 

하드 디스크(HDD:Hard Disk Drive)는 자기적인 방식으로 데이터를 저장하는 보조기억장치

 

 

하드 디스크를 뜯어보면 다음과 같은 구성요소들이 존재한다.

  • 플래터: 하드 디스크에서 실질적으로 데이터가 저장되는 동그란 원판
  • 스핀들: 플래터를 회전시키는 구성 요소, 스핀들이 플래터를 돌리는 속도를 분당 회전수를 나타내는 RPM(Revolution Per Minuter)이라는 단위로 표현
  • 헤드: 플래터를 대상으로 데이터를 읽고 쓰는 구성 요소
  • 디스크 암: 헤드를 원하는 위치로 이동시키는 구성요소
  • 트랙: 플래터를 여러 동심원으로 나누었을 때 그중 하나의 원
  • 섹터: 트랙을 피자조각처럼 나누었을 때 그중 한 조각, 하드 디스크의 가장 작은 전송 단위
  • 실린더: 여러 겹의 플래터 상에서 같은 트랙이 위치한 곳을 모아 연결한 논리적 단위

 

하드 디스크에 저장된 데이터에 접근하는 시간은 탐색 시간, 회전 지연, 전송 시간으로 나뉜다.

  • 탐색 시간은 접근하려는 데이터가 저장된 트랙까지 헤드를 이동시키는 시간이다.
  • 회전 지연은 헤드가 있는 곳으로 플래터를 회전시키는 시간을 의미한다.
  • 전송 시간은 하드 디스크와 컴퓨터 간에 데이터를 전송하는 시간을 의미한다.

 

 

 

플래시 메모리

 

플래시 메모리는 주기억장치 중 하나인 ROM(Read Only Memory)에 사용됨

 

USB 메모리, SD 카드, SSD가 모두 플래시 메모리 기반의 보조기억장치

 

플래시 메모리에는 셀(cell)이라는 단위가 있으며, 한 셀에 비트를 얼마나 저장하냐에 따라 SLC(Single Level Cell, 1비트), MLC(Multiple Level Cell, 2비트), TLC(Triple Level Cell, 3비트)로 나뉜다.

 

 

  • SLC 타입은 한 셀로 두 개의 정보(2^1)를 표현할 수 있다.
    • 한 셀로 두 개의 정보를 표현 가능
    • MLC나 TLC 타입에 비해 비트의 빠른 입출력 가능
    • 용량 대비 가격이 높음
    • 고성능의 빠른 저장 장치 필요시 사용
  • MLC는 네 개의 정보(2^2)를 표현할 수 있다.
    • 한 셀로 네 개의 정보를 표현 가능
    • SLC 타입보다 속도와 수명이 떨어지지만, SLC 타입보다 대용화하기 유리함
  • TLC는 여덟 개의 정보(2^3)를 표현할 수 있다.
    • SLC나 MLC보다 수명과 속도가 떨어지지만 용량대비 가격이 저렴함

플래시 메모리

  • 셀들이 모여 만들어진 단위를 페이지
  • 페이지가 모여 블록
  • 블록이 모여 플레인
  • 플레인이 모여 다이가 된다.

 

플래시 메모리에서 읽기와 쓰기는 페이지 단위로, 삭제는 페이지보다 큰 블록 단위로 이루어진다.

 

 

 

플래시 메모리의 페이지는 세 개의 상태를 가진다.

 

Free 상태는 어떠한 데이터도 저장하고 있지 않아 새로운 데이터를 저장할 수 있는 상태를 의미한다.

 

Valid 상태는 이미 유효한 데이터를 저장하고 있는 상태를 의미한다.

 

Invalid 상태는 쓰레기값이라 부르는 유효하지 않은 데이터를 저장하고 있는 상태를 의미한다.

 

 

 

7-2. RAID의 정의와 종류

 

1TB 하드 디스크 네 개로 raid를 구성하면 4TB 하드 디스크 한 개의 성능과 안전성을 능가할 수 있음

 

RAID(Redundant Array of Independent Disks)란 주로 하드 디스크와 SSD를 사용하는 기술로, 여러 개의 물리적 보조기억장치를 마치 하나의 논리적 보조기억장치처럼 사용하는 기술임

 

 

RAID의 종류

 

RAID 0

  • 여러 개의 보조기억장치에 데이터를 단순히 나누어 저장하는 구성 방식
  • 데이터를 저장할 때 각 하드 디스크는 위와 같이 메모리에서 번갈아 가며 데이터를 저장
  • 줄무늬 처럼 분산되어 저장된 데이터를 스트라입(stripe)이라 하며, 분산하여 저장하는 것을 스트라이핑이라고 함
  • 여러 번에 걸쳐 읽고 썼을 데이터를 동시에 읽고 쓸 수 있기 때문에 위의 장치는 이론상 4TB 저장 장치 한 개를 읽고 쓰는 속도보다 네 배가량 빠름
  • 다만 하나의 하드 디스크가 고장나면 다른 모든 하드 디스크를 쓸 수 없다는 문제점이 있음

 

 

RAID 1

  • RAID 0의 단점을 보완하고자 나온 방식
  • 복사본을 만드는 방식이며, 미러링(mirroring)이라고도 부름
  • RAID 0처럼 데이터 스트라이핑을 사용하지만 거울같은 디스크의 형식을 구성하여 복구를 매우 간단하게 함
  • 다만 RAID 0보다 많은 양의 하드 디스크를 필요로 하며 비용이 증가한다는 단점이 존재

 

 

RAID 4

  • RAID 1처럼 복사본을 만드는 대신 오류를 검출하고 복구하기 위한 정보를 따로 디스크에 저장하는 방식
  • 패리티를 저장한 디스크를 통해 다른 장치들의 오류를 검출하고 복구
  • 이로써 RAID 1보다 적은 하드 디스크로도 데이터를 안전하게 보관
  • 다만 새로운 데이터가 저장될 때마다 패리티를 저장하는 디스크에도 데이터를 쓰게 되므로 패리티를 저장하는 장치에 병목 현상이 발생한다는 문제가 있음

 

RAID 5

  • RAID 4와는 달리 패리티 정보를 분산하여 디스크에 저장하여 병목 현상을 해소

 

RAID 6

  • RAID 6의 구성은 기본적으로 RAID 5와 같으나, 서로 다른 두 개의 패리티를 디스크에 두는 방식임
  • RAID 4나 RAID 5보다 안전한 구성이나, 새로운 정보를 저장할 때마다 함께 저장할 패리티가 두 개이므로, 쓰기 속도는 RAID 5보다 느림.
  • RAID 6은 저장 속도를 희생하나, 데이터 안정성이 뛰어남

 


 

8장 입출력장치

 

 

8-1. 다양한 보조기억장치

 

장치 컨트롤러

  • 입출력 장치는 종류가 너무 많음
  • 일반적으로 CPU와 메모리의 데이터 전송률은 높지만 입출력장치의 데이터 전송률은 낮음
  • 이와 같은 이유로 입출력장치는 컴퓨터에 직접 연결되지 않고 장치 컨트롤러(device controller)라는 하드웨어를 통해 연결됨
  • 장치 컨트롤러는 입출력 제어기, 입출력 모듈등으로 다양하게 불림
  • 장치컨트롤러는 대표적으로 다음과 같은 역할이 있음
    • CPU와 입출력장치 간의 통신 중개
    • 오류 검출
    • 데이터 버퍼링

 

  • 장치 컨트롤러의 내부 구조에는 데이터 레지스터, 상태 레지스터, 제어 레지스터가 존재함
  • 데이터 레지스터는 버퍼 역할을 하여 데이터 버퍼링으로 전송률 차이를 완화함
  • 상태 레지스터는 입출력장치가 입출력 작엄을 할 준비가 되었는지, 작업이 완료되었는지 등의 상태 정보를 저장함
  • 제어 레지스터는 입출력장치가 수행할 내용에 대한 제어 정보와 명령을 저장함

 

 

 

 

장치 드라이버

  • 장치 드라이버란 장치 컨트롤러의 동작을 감지하고 제어함으로써 장치 컨트롤러가 컴퓨터 내부와 정보를 주고받을 수 있게 하는 프로그램임(ex. 프린터 드라이버)
  • 프로그램이기 때문에 메모리에 저장되어 있음
  • 장치 컨트롤러가 입출력장치를 연결하기 위한 하드웨어적 통로라면 장치 드라이버는 소프트웨어적인 통로

 

 

 

8-2. 다양한 입출력 방법

 

 

프로그램 입출력

  • 프로그램 속 명령어로 입출력장치를 제어하는 방법
  • CPU가 장치 컨트롤러의 레지스터(데이터, 상태, 제어) 값을 읽고 씀으로써 이루어짐
  • 다만 CPU 내부에 있는 레지스터들과는 달리 CPU는 여러 장치 컨트롤러 속 레지스터들을 모두 알고 있기 어려움
  • 그렇기에 명령어가 처리되는 방법이 다음과 같이 두 가지로 나뉘움

 

 

  • 메모리 맵 입출력
    • 메모리에 접근하기 위한 주소 공간과 입출력장치에 접근하기 위한 주소 공간을 하나의 주소 공간으로 간주
    • 가령 1024개의 주소를 표현할 수 있는 컴퓨터가 있다면, 512개는 메모리 주소를, 512개는 장치 컨트롤러의 레지스터를 표현하기 위해 사용
  • 고립형 입출력
    • 메모리를 위한 주소 공간과 입출력장치를 위한 주소 공간을 분리하는 방법
    • 메모리에도 1024개의 주소 공간을 활용하고, 입출력장치도 1024개의 주소 공간을 활용
    • 자세한 건 다음 그림으로 이해

 

 

인터럽트 기반 입출력

  • 입출력장치에 의한 하드웨어 인터럽트는 정확히 말하자면 입출력장치가 아닌 장치 컨트롤러에 의해 발생
  • 장치 컨트롤러가 입출력 작업을 끝낸 뒤 CPU에게 인터럽트 요청 신호를 보내면 CPU는 하던 일을 잠시 백업하고 인터럽트 서비스 루틴을 실행, 이를 인터럽트 기반 입출력이라고 함
  • 만약 입출력장치가 여러개일 경우, 각각의 장치들은 어떻게 처리되어야 하는가?
    • 간단하게 인터럽트가 발생한 순서대로 인터럽트를 처리하는 방법이 존재함
    • 이는 CPU가 플래그 레지스터 속 인터럽트 비트를 비활성화하면 다른 입출력 장치에 의한 하드웨어 인터럽트를 받아들이지 않아 가능한 방법
    • 하지만 만약 플래그 레지스터 속 인터럽트 비트가 활성화되어 있는 경우 CPU는 우선순위가 높은 인터럽트부터 처리함
    • 우선순위를 반영하여 다중 인터럽트를 처리하는 방법으로는, PIC(프로그래머블 인터럽트 컨트롤러)라는 하드웨어를 사용함

 

 

 

DMA 입출력

  • 입출력장치와 메모리 간의 데이터 이동은 CPU가 주도하고, 이동하는 데이터도 반드시 CPU를 거침
  • 가뜩이나 바쁜 CPU는 입출력장치를 위한 연산 때문에 시간을 뺏기게 됨
  • 입출력장치와 메모리가 CPU를 거치지 않고도 상호작용할 수 있는 입출력 방식이 바로 DMA(Direct Memory Access)
  • DMA 입출력을 하기 위해서는 시스템 버스에 연결된 DMA 컨트롤러라는 하드웨어가 필요하며, 바로 이것이 CPU의 역할을 대신함

 

다만, DMA를 위해 시스템 버스를 너무 자주 사용하면 그만큼 CPU가 시스템 버스를 이용하지 못함

 

이 문제는 DMA 컨트롤러와 장치 컨트롤러들을 입출력 버스라는 별도의 버스에 연결하여 해결함

 

입출력 버스에는 PCI(Peripheral Component Interconnect)버스, PCI Express 버스 등 여러 종류가 존재함