Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>
컴퓨터 구조

2. 컴퓨터 구조

언어를 이해하려면 그 밑바탕이 되는 문화를 이해하고 역사를 이해해야 하듯이 프로그래밍을 이해해서 프로그램을 만들고자 한다면 그 밑바탕이 되는 컴퓨터에 대해서 이해하고 있어야 한다. 물론 여러분이 전자공학을 공부할 필요는 없겠지만 적어도 컴퓨터에서 프로그램이 어떻게 실행될 수 있는지와 같은 기본적인 것에 대한 이해 하고 있어야 한다.

현재 컴퓨터의 구조는 구조를 만든 창시자의 이름을 딴 Von Neumann(폰 노이만)이라고 불리우는 구조에 기반을 두고 있다. 폰 노이만은 컴퓨터의 구조를 CPU(Central Processing Unit)와 메모리(memory)의 두개의 주요 부분으로 나누어서 구성했다. 이 구조는 개인 컴퓨터, 슈퍼 컴퓨터, 메인 프레임 심지어는 핸드폰과 같은 모든 현대적인 컴퓨터가 채택하고 있다. 간단히 말해서 "연산"과 "저장"의 두 부분으로 나누었다.

2.1. 컴퓨터의 메모리 구조

컴퓨터가 메모리를 보는 방식을 쉽게 이해하려면 다세대 주택에 비치되어 있는 우편함을 생각하면된다. 우편함은 기본적으로 해당 호수에 사는 사람이 염람이 가능하며 열람해야할 우편함을 쉽게 찾을 수 있도록 번호(보통 호수)가 메겨져 있음을 알 수 있다. 컴퓨터가 메모리를 보는 관점역시 이와 비슷하다. 컴퓨터는 각 메모리 영역을 쉽게 찾아내어서 데이터를 저장하거나 가져올 수 있도록 하기 위해서 번호가 메겨져 있다. 예를 들어서 당신의 컴퓨터가 256Mbyte의 메모리를 가지고 있다는 것은 당신의 컴퓨터가 256*백만의 저장 공간을 가지고 있음을 의미한다. 256*백만 개의 우편함을 가지고 있는 것이다. 각각의 영역은 유일하게 구별될 수 있는 번호가 메겨 진다.

그림 1. 메모리 영역은 우편함과 비슷하다

컴퓨터가 위와 같은 방법으로 메모리를 관리하는 이유는 간단한 관리가 가능하기 때문이다. 만약 컴퓨터가 데이터의 크기에 따른 가변크기의 다양한 크기의 메모리 영역의 조합을 관리해야 한다면 이들 메모리영역을 다루기가 매우 어려울 것이다.

메모리에는 컴퓨터의 연산에 필요한 모든 정보가 저장된다. 지금 당신이 사용하고 있는 컴퓨터를 예로 들어보도록 하자. 지금 당신이 사용하는 컴퓨터의 메모리에는 다음과 같은 내용들이 저장되어 있을 것이다.

  • 커서의 스크린상에서의 위치

  • 스크린상에 존재하는 각 윈도우의 위치와 크기들

  • 사용하고 있는 폰트의 정보들

  • 각 윈도우에서 사용하고 있는 위젯들(버튼, 박스, 메뉴)

  • 아이콘의 그래픽 정보

  • 대화상자 등에 표시되는 메시지들

  • 기타

메모리에 데이터가 있다면 데이터를 다루는 프로그램들도 있을 것이다. 이 프로그램은 메모리 데이터를 쓰거나 읽는 일을 할 것이다. 데이터와는 좀 다른 특성을 가지고 있으므로 데이터와 좀 다르게 취급될 수 있을거라 생각될 수 있지만 폰 노이만 구조에 의해 이들 프로그램역시 데이터와 동일하게 메모리에 저장된다. 폰 노이만 구조를 따르는 컴퓨터의 입장에서 보자면 프로그램 역시 데이터일 뿐이다.

2.2. CPU

메모리에 데이터가 저장되어 있다고는 하지만 이것만 가지고는 아무런 의미가 없다. 단지 비트의 나열 뿐으로 데이터를 쓸모 있는 정보로 바꾸기 위해서는 데이터를 읽어들이고, 수정하고, 옮기는 등의 일을 해야만한다. 이러한 일은 CPU가 담당하게 된다.

CPU는 한번의 시간에 메모리로 부터 명령(instruction)을 읽어 들이고 이것들을 실행한다. 이것을 fetch-execute cycle 라고 하는데, 이 명령에는 다음과 같은 요소들이 포함되어 있다.

  • Program Counter

  • Instruction Decoder

  • Data bus

  • General-purpose register

  • Arithmetic and logic unit

program counter는 컴퓨터에게 다음 수행해야될 명령(instruction)을 알려주기 위해서 사용한다. 우리는 앞서 컴퓨터의 입장에서 프로그램과 데이터가 메모리에 저장되는 방식에 의해서는 어떠한 차이도 없다고 배웠었다. 단지 해석에 있어서 차이가 있을 뿐이다. program counter은 실행될 다음 명령이 저장되어 있는 메모리주소값을 가지고 있다. instruction decoder는 수행해야될 명령의 형식을 알려주기 위해서 사용된다. 수행해야될 명령의 형식이란 다름 아닌 더하기, 빼기, 곱하기, 데이터 이동과 같은 것들이다. 이상에서 컴퓨터의 수행은 명령들과 명령이 저장된 메모리 위치의 목록에 의해서 이루어 짐을 알 수 있다.

이제 컴퓨터는 어떤 일을 수행할 준비가 되어있다. 일을 수행(계산)하기 위해서는 데이터가 있어야 한다. data bus는 계산할 데이터가 있는 메모리의 위치를 가진다. data bus라고 불리우는 이유는 CPU와 Memory사이를 연결해주기 때문이다. 버스라는건 하나의 객체에 필요로 하는 여러개의 다른 객체를 연결하는 구조를 말한다. 운송수단으로 이용하는 버스를 생각하면 될것이다.

전형적으로 보자면 메모리는 CPU(이하 프로세서)의 외부에 위치하고 있다. 그렇지만 프로세서도 register라고 불리우는 빠르게 접근 가능한(물리적으로 가깝기 때문에) 자체 메모리를 가지고 있다. 이러한 레지스터는 일반목적(general-purpose) 레지스터와 특별목적(special-purpose) 레지스터의 두가지 종류로 나뉜다. 일반 목적 레지스터는 말그대로 더하기, 빼기, 곱하기, 비교와 같은 일반적인 명령을 위해서 사용된다. 컴퓨터는 제한된 몇개만의 일반 목적 레지스터를 가지고 있을 뿐이며 대부분은 주(main)메모리를 이용한다.

이제 CPU가 필요로 하는 데이터를 가져왔다면 decoded instruction에 따라서 수치연산(arithmetic)과 논리연산(logic)을 수행한다. 이것들은 실제 수행되는 명령들로써 연산수행 결과는 data bus를 통해서 주 메모리공간 이나 레지스터리에 저장된다.

CPU의 이러한 작동은 매우 심플하다(만약 그렇지 않다면 CPU제작 단가가 극적으로 올라갈 것이다). 비록 초기 프로세서에 비해서 현재의 프로세스가 매우 많은 발전을 하고 매우 복잡해지기는 했지만 기본적인 작동방식은 초기의 모델을 따르고 있다. 다만 여기에 chache hierarchies, superscalar processors, pipelining, branch prediction, out-of-order execution, microcode translation, coprocessors등의 (매우 생소한)기술이 추가 되어서 성능을 향상 시켰다는 것만 다르다고 할 수 있다. 이러한 성능향상 기술들은 옵션으로 붙은 사항이라고 보면 되겠다. 위의 단어들중 pipelining와 coprocessors(수치연산 프로세스) 외에는 처음 접해본 단어들이 많을 건데, 그렇다고 해서 그리 걱정할 필요는 없다. 저것들을 모른다고 해도 CPU의 기본작동 방식을 이해하는데 별 문제는 없다. 꼭 알아야 겠다면 인터넷을 통해서 CPU에 대한 더욱 자세한 내용을 찾아 보길 바란다.

2.3. 몇 가지 용어들

컴퓨터의 메모리는 고정된 크기를 가지는 연속된 숫자를 가지는 저장공간의 연속이다. 이들 숫자는 저장공간의 위치를 가리키는데 이를 '''주소(address)'''라고 한다. 고정된 크기를 가지는 단일 공간을 X86 프로세서에서는 '''byte'''라고 부르며 0에서 255사이의 값을 가진다.

주소공간의 크기가 0에서 255의 값을 가진다고 했다. 아마도 화면에 표시되는 문자와 그림을 표현하기 위해서는 훨씬 큰 값이 필요할 것이다. 이런것들은 어떻게 표현할까 ? 이러한 표현은 그래픽 카드(graphics card)가 있음으로 가능해 진다. 그래픽 카드는 연속된 여러개의 값들을 해석해서 화면에 출력시킨다. 화면에 데이터를 출력할 때는 읽어들인 값을 ASCII 코드에 맵핑 시켜서 여기에 있는 값을 화면에 뿌려주게 된다. 예를 들어 읽어들인 값이 65라면 'A'가 화면에 출력된다. 화면에 "HELLO"를 출력하기 위해서는 72, 69, 76, 76, 79의 연속된 값들을 필요로 한다. 다음은 ASCII 코드표이다.

그림 2. ASCII 테이블

분명 0에서 255까지의 값이라고 했는데 왜 127까지 밖에 없지? 라고 생각할 수 있을 것 같다. 실제 화면출력과 제어를 위해서는 0-127까지의 값을 사용한다. 128에서 255는 Extended ASCII Codes라고 불리우며 영문외의 다른 문자들(특히 2바이트 문자)과 특수 문자들을 나타내기 위해서 사용 한다.

그렇다면 255보다 더큰 값은 어떻게 해야 다룰 수 있을까 ? 이것은 바이트를 두개 이상 결합함으로서 가능해 진다. 두 바이트라면 0에서 65536까지 표현 가능 하다. 4 바이트로 할경우 0에서 4294967295까지의 값을 표시할 수 있을 것이다. 큰 수를 표현하기 위해서 바이트 조합을 해야한다면 프로그래밍 할 때 꽤나 귀찮을 거라고 생각할 수 있지만 다행이도 컴퓨터는 4바이트를 기본단위로 묶어서 관리하고 있으니 크게 걱정할 필요는 없다.

앞서 우리는 컴퓨터가 내부적으로 사용하는 레지스터라고 불리우는 저장공간에 대해서 알아 보았다. 레지스터는 컴퓨터가 (빠른)계산을 하기위한 용도로 사용한다. 여러분의 책상으로 비유해 보자. 여러분의 책상에는 작업에 사용하기 위한 많은 책, 문서, 보고서들이 한 귀퉁이를 차지하고 있을 것이다. 그러나 분명 여러분이 지금 처리해야할 일과 관련된 문서는 여러분과 가까운 곳에 위치하고 있을 것이다. 아마도 모니터 옆이나, 책받이 정도가 될건데, 이렇게 하는 이유는 작업에 필요한 데이터를 좀더 빨리 찾기 위해서이다. 이러한 장소가 컴퓨터의 레지스터에 해당한다. 레지스터에는 컴퓨터가 현재 작업중인 데이터가 놓여서 좀더 빠른 작업이 가능하도록 한다.

아마도 여러분의 대부분은 X86프로세스를 사용하는 컴퓨터를 사용하고 있을 것이다. x86 프로세스는 4바이트 크기의 레지스터를 가진며 이를 word 라고 한다. 즉 1워드는 4바이트가 된다. 레지스터의 크기를 4바이트로 정한건 컴퓨터가 계산을 하기 위한 가장 편한 자료의 크기이기 때문이다. 4바이트는 40억정도의 크기를 가진다.

주소(address)는 레지스터의 크기에 맞도록 4바이트(1워드)의 크기를 가진다. 주소가 4바이트 크기를 가지게 되므로 최대 4294967296바이트 만큼을 다룰 수 있을 것이다. 이것은 4기가 바이트의 크기로 일반적인 컴퓨터가 제어가능한 물리적인 메모리의 크기가 된다.

주소는 결국 데이터가 저장된 메모리의 위치를 가리키게 되는데, 이러한 가리킨다는 특징 때문에 pointers라고 부르기도 한다.

2.4. interpreting Memory

컴퓨터는 매우 엄격하게 작동되는 논리기계다. 때문에 컴퓨터를 다루는 프로그래머 역시 매우 엄격해질 수 밖에 없다. 컴퓨터는 혼자서는 어떠한 일도 수행할 수 없으며 반드시 프로그램이 있어야 하며, 프로그램역시 엄격한 규칙을 따르도록 작성되어야 하기 때문이다. 컴퓨터가 원하는 일을 하는 걸 보고 싶다면 여러분은 컴퓨터에게 컴퓨터가 수행해야 할 일을 명확하게 명령할 수 있어야 한다.

컴퓨터가 대략 알아서 해줄거라고 기대하지 말라. 컴퓨터는 문자건, 그림이건, 음악이건 웹페이지건 단지 숫자로 저장할 뿐이며, 연속된 숫자의 나열로 볼 뿐이다. 문자, 그림, 음악들을 들을 수 있는건 이러한 숫자의 나열을 해석할수 있는 (프로그래머가 작성한)특별한 프로그램이 있어야지 가능하다.

메모리에 고객정보를 저장하는 걸 예로 들어보자. 여러분은 고객의 이름과 주소를 저장하기 위해서 각각 10개와 50개 정도의 ASCII 문자를 사용해야 하는걸 쉽게 생각해 낼 수 있을 것이다. 고객의 나이와 고객의 아이디를 저장하기 위해서는 숫자가 필요함을 알아 낼 수 있을 것이다. 이 경우 메모리 블럭에는 다음과 같은 형태로 고객의 정보가 저장될 수 것이다.

레코드의 시작 :
   고객의 이름 (10 바이트)   = 레코드의 시작 
   고객의 주소 (50 바이트)   = 레코드의 시작 + 10 바이트
   고객의 나이 (4 바이트)    = 레코드의 시작 + 10 + 50 
   고객의 아이디 (4 바이트)  = 레코드의 시작 + 10 + 50 + 4
			
고객 데이터가 저장된 레코드의 주소(address)를 알고 있다면 우리는 간단한 연산(덧셈)을 통해서 고객 레코드에서 원하는 가져올 수 있다. 그러나 위의 방법으로 데이터를 저장하는 방식은 한가지 단점을 가지고 있다. 위의 예에서는 고객의 주소가 50바이트로 제한되어 있는데, 이런 이유로 50바이트 보다 더 큰 주소가 입력된 경우 50바이트 이후의 주소 데이터는 분실해 버린다.

위의 데이터 저장방식에 따른 제한을 없애기 위해서 데이터의 위치만을 가리키는(포인트)하는 방법이 사용된다. 고객의 이름을 예로 들자면 고객의 이름의 실제 데이터는 메모리의 임의의 영역에 저장되고 레코드에는 단지 고객의 데이터가 저장된 메모리의 주소 값만을 명시하는 방법이다. 이 경우 메모리는 다음과 같이 구성될 것이다.

레코드의 시작	
    고객의 이름 포인터(4 바이트)  = 레코드의 시작
    고객의 주소 포인터(4 바이트)  = 레코드의 시작 + 4
    고객의 나이 (4 바이트)        = 레코드의 시작 + 4 + 4 
    고객의 아이디 (4 바이트)      = 레코드의 시작 + 4 + 4 + 4 
			
이렇게 되면 고객의 실제 데이터는 메모리의 임의의 위치에 저장될 수 있음으로 입력가능한 주소의 길이에 제한을 받지 않아도 된다.

2.5. 데이터 접근 방법

프로세스는 addressings mode라고 불리우는 데이터에 접근하는 몇 가지 방식을 가지고 있다. 가장 간단한 mode는 immediate모드라고 부리는 것으로 데이터 접근이 명령(instruction)자신에게서 이루어지는 방식이다.