Skip to content

Latest commit

 

History

History
281 lines (183 loc) · 14.3 KB

File metadata and controls

281 lines (183 loc) · 14.3 KB

컴퓨터 구조에 대한 첫 번째 이야기

시스템 프로그래밍의 이해와 접근

시스템 프로그래밍 이란?

컴퓨터 시스템을 동작시키는 프로그램

즉, 컴퓨터를 동작시키기 위해 필요한 프로그램을 말한다.

어셈블리 언어나 C언어를 이용하여 하드웨어를 직접 컨트롤하는 개발자들을 가리켜 시스템 프로그래머라 부른다. 그러나 Windows 나 UNIX 같은 운영체제에서 제공하는 라이브러리를 사용하여 프로그램을 개발하는 개발자들도 시스템 프로그래머라 부를 수 있다.

보통 컴퓨터 시스템이라고하면 하드웨어만을 뜻하는 것이 아니다. 하드에어가 실제 일을 하게끔 도와주는 운영체제를 포함하는 것이 보통이다.

컴퓨터 시스템의 주요 구성요소

img.png

컴퓨터 구조와 운영체제를 이해하게 되면, 시스템 프로그래밍만 가능하게 되는 것이 아니다. 언어의 문법적 요소만을 이해하고 바로 프로그래밍하는 프로그래머들보다 효율적인 프로그램을 구현하는 것이 가능해진다.

컴퓨터 하드웨어의 구성

img_1.png

CPU(Central Processing Unit)

우리가 흔히 말하는 "중앙처리장치"가 바로 CPU 이다. 기본적으로 CPU가 연산을 담당한다.

CPU는 컴퓨터 프로그램의 실행에 있어서 핵심적인 역할을 담당한다.

메인 메모리(Main Memory)

램(RAM) 이라는 저장장치로 구성되는 메인 메모리는 컴파일이 완료된 프로그램 코드가 올라가서 실행되는 영역이라고 정의할 수 있다.

예를 들어 아주 재미있는 게임 하나를 인터넷을 통해 내려받았다고 가정해 보자. 이 게임은 당연히 하드디스크에 저장된다. 이 게임을 실행하기 위해서 Window 탐색기를 띄운 다움, 저장된 디렉터리로 찾아 들어가서 더블클릭을 한다. 그러면 해당 프로그램은 메인 메모리로 올라가서 실행된다. 즉, 메인 메모리는 프로그램 실행을 위해 존재하는 메모리라고 생각하면 된다.

입,출력 버스(Input/Output Bus)

입.출력 버스는 컴퓨터를 구성하는 구성요소 사이에서 데이터를 주고 받기 위해 사용되는 경로이다. 주고 받는 데이터의 종류와 역할에 따라서 어드레스 버스(Address Bus) , 데이터 버스(Data Bus) , 컨트롤 버스(Control Bus) 이렇게 세 가지로 구분이 된다.

하드디스크, 메인 메모리 ,CPU 등등이 모두 버스에 연결되어 있다. 때문에 이러한 버스 시스템을 기반으로 하드디스크에 있는 데이터를 메인 메모리로, 메인 메모리에 있는 데이터를 하드디스크로 전송하는 것이 가능하고, 메인 메모리와 CPU 사이에서의 데이터 입.출력도 가능하다.

CPU에 대한 이해

img_2.png

ALU(Arithmetic Logic Unit)

  • CPU 내부에는 실제 연산을 담당하는 ALU 라는 블록이 있다.
  • ALU 가 처리하는 기본적인 연산은 크게 두 가지로 나뉜다.
  • 덧셈이나 뺄셈과 같은 산술 연산
  • AND 나 OR 와 같은 논리 연산

컨트롤 유닛(Control Unit)

프로그래머가 작성한 프로그램을 컴파일하면 실행파일이 생성된다. 이 실행파일에는 CPU에게 일을 시키기 위한 명령어들이 저장되어 있다. 어떤 경로를 거치던 간에 이 명령어가 CPU 내부로 흘러 들어가야 CPU 에게 일을 시킬 수 있다.

CPU 내부에 있는 ALU 까지 명령어가 전송되었는데 ,사실 ALU 는 명령어를 이해하지 못한다. 산술 연산과 논리 연산만 할 줄 알기 때문이다. 따라서 ALU 대신에 명령어를 해석해줘야 하는 데 그게 바로 컨트롤 유닛이다.

컨트롤 유닛이 하는 일은 CPU가 처리해야 할 명령어들을 해석하는 것이다. CPU 내부로 흘러 들어오는 명령어를 보고선 다음과 같은 결정을 내린다.

"아하 이 명령어는 덧셈을 하라는 뜻이군! 그렇다면 ALU에게 덧셈을 하도록 신호를 보내줘야 겠다."

이처럼 컨트롤 유닛은 명령어를 해석하고, 그 해석된 결과에 따라 적절한 신호를 CPU의 다른 블록에 보내는 일을 한다. CPU의 총 사령관 정도로 생각하면 되겠다.

CPU 내부에 존재하는 레지스터들(Register Set)

명령어는 컨트롤 유닛으로 피연산자는 ALU 로 보내면 된다. 그런데 만약, ALU는 연산 중이고 컨트롤 유닛은 앞서 들어온 명령어를 해석하고 있는 상황이라면 이것이 불가능할 수도 있다. 그래서 이보다는 컨트롤 유닛이나 ALU가 필요로 하는 명령어 및 데이터들을 어디엔가 저장해 두고 상황이 허락될 때 직접 가져가도록 하면 좋을 것이다.

다시 말해 CPU 내부에도 임시적으로 데이터를 저장하기 위한 조그마한 메모리 공간이 필요하다는 뜻이다. 다행히도 이러한 메모리가 CPU에 존재한다.

레지스터(Register)라는 아주 작은 메모리가 CPU 내에 존재한다. 레지스터란 CPU 내부에 존재하는 2진 데이터 저장을 위한 저장장치이다. 크기가 큰 메인 메모리나 하드디스크와 달리, CPU에 따라서 16비트,32비트,64비트 정도의 데이터를 저장 할 수 있는 크기로 구성된다.

이러한 레지스터들은 CPU 내부에 여러 개가 존재하는 데 CPU의 종류에 따라서 그 개수와 형태가 다양하다. 레지스터들은 각각의 용도가 정해져 있는 것이 일반적이며 이들은 CPU가 연산을 하기 위해서 반드시 필요하다. 아주 기본적인 레지스터만 해도 8개가 넘는다.

버스 인터페이스 (Bus Interface)

명령어와 데이터들이 CPU 안으로 잘 흘러들어갔다고 가정해보면 이것이 가능한 이유는 버스 인터페이스가 있기 때문이다.

img_6.png

컴퓨터에는 CPU , 하드디스크 , RAM , 사운드 카드, 그래픽 카드 등이 있는데 이들은 서로 독립적으로 동작하는 것이 아니라 서로 데이터를 주고 받으면서 동작한다. 그렇다면 서로 데이터를 주고 받기 위해서는 어떠한 매개체가 있어야 하는데 그것이 바로 I/O 버스 이다.

CPU 내에는 I/O 버스의 통신 방식을 이해하고 있는 그 무엇인가가 있어야 한다.

이 역할을 해주는 것이 바로 버스 인터페이스이다.

이 버스인터페이스 장치는 버스가 어떻게 데이터를 전송하는지, 그에 대한 프로토콜 혹은 통신방식을 알고 있는 녀석이다.

클럭 신호 (Clock Pulse)

클럭 신호는 CPU를 구성하는 요소는 아니다. 그러나 CPU를 구성하는 구성 요소에 제공되어야 하는 신호로 아주 중요한 의미를 지닌다.

클럭 신호는 타이밍을 제공하기 위해서 필요한 것이다.

여러분의 CPU 사양은 어떻게 되는가? 예를 들어서 필자의 CPU 클럭 속도는 1.6Mhz 인데, 이 경우 필자의 컴퓨타에 있는 클럭발생기는 1초당 1,600,000 번의 클럭을 발생시키게 설정된다. 그리고 CPU는 매 클럭이 발생할 때마다 그 클럭에 맞춰서 일을 한다.

즉 클럭 속도가 1.6Mhz 인 CPU는 1초에 1백 6십 만 번 일을 하게 된다. 따라서 CPU의 클럭 속도가 높으면 초당 처리하는 명령어의 개수가 많아지므로 컴포터의 전체적인 성능은 좋아지기 마련이다.

"클럭 발생기에 의해 발생되는 클럭 신호는 CPU를 구성하는 요소 요소에 제공되며, 이 신호에 맞춰서 CPU가 일을 한다."

"CPU는 왜? 클럭 신호에 맞춰서 일을 해야만 하는가?"

클럭 신호가 발생할 때에만 일을 한다니까 CPU가 많이 논다는 생각이 들기도 한다. 클럭이 발생하든지, 안 하든지, 힘 닿는 데까지 무조건 일을 하면 훨씬 빠른데 말이다. 맞는 말이다. 그러나 컴퓨터 시스템은 동기화를 필요로 한다.

프로그램의 실행 과정

위대한 수학자 폰 노이만

초창기 컴퓨터는 임의의 연산을 하고자 할 때마다 여러 명의 엔지니어가 달라 붙어서 진공관 회로의 스위치를 변경해 줘야 했다.

img_3.png

위 그림에서 중요하게 봐야 할 요소는 메모리와 프로그램이다. 이전 까지는 프로그램이란 단순히 진공관 회로의 스위치 구성을 의미하는 것이었으므로 오늘날 말하는 컴퓨터 프로그램과 거리가 멀었다.

그라나 폰 노이만은 프로그램이 컴퓨터 내부에 저장되는 구조를 생각해 낸 것이다. 따라서 많은 사람들이 오늘날의 컴퓨터에 대한 개념을 만든 사람이 폰 노이만이라고 말한다.

결론적으로 폰 노이만이 주장한 컴퓨터 구조는 다음과 같다.

"프로그램이라는 것이 존재하고, 이 프로그램은 컴퓨터 내부에 저장되어서 순차적으로 실행되어야 한다."

폰 노이만이 생각해낸 컴퓨터 구조는 "폰 노이만 아키텍처" 라는 이름으로 불리기 시작하였으며, 이를 바탕으로 한 최초의 컴퓨터가 EDSAC이라는 이름으로 약 7년 후 탄생하기에 이른다.

프로그램의 실행 과정

img_4.png

단계 1: 전처리기에 의한 치환작업

실팽파일 생성의 가장 첫 번째 단계가 전처리기에 의해서 이뤄짐을 알 수 있다. 전처기는 "#include" , "#define"과 같이 "#"으로 시작하는 지시자의 지시에 따라서 소스코드를 적절히 변경하는 작업을 한다.

단계 2 : 컴파일러에 의한 번역

단계 1에 의해서 변경된 소스코드는 여전히 C언어로 구성되어 있어서 우리가 눈으로 봐도 이해할 수 있는 내용이다. 이제 이 소스코드는 컴파일러에 의해서 어셈블리 코드로 번역된다.

단계 3 : 어셈블러에 의한 바이너리 코드 생성

보통 바이너리 코드라고 하면 어렵게 생각한다. 그러나 텍스트 코드에 상대되는 뜻이라고 생각하면 쉽다. 즉, 1과 0으로만 구성되는 코드를 말한다.

  • 단계 1. Fetch : 메모리 상에 존재하는 명령어를 CPU로 가져오는 작업
  • 단계 2. Decode : 가져다 놓은 명령어를 CPU가 해석하는 단계
  • 단계 3. Execution : 해석된 명령어의 명령대로 CPU가 실행하는 단계

단계 4 : 링커에 의한 연결과 결합

링커는 프로그램 내에서 참조하는 함수나 라이브러리들을 하나로 묶는 작업을 말한다. 이 과정이 끝나면 실제로 실행 가능한 실행파일이 생성된다. 물론 이 실행파일은 컴퓨터가 실행해야 하는 바이너리 코드로 구성된다.

img_7.png

위 그림에 대한 부연 설명

실행파일은 링커에 의해서 최종적으로 만들어진 파일로서, 이 안에는 컴퓨터에게 일을 시키기 위한 명령어(바이너리 코드 형식의 명령어)가 들어 있다.

이것이 메모리 공간에 올라가고 난 다음 CPU에 의해서 실행되기 시작한다. 메모리 공간에 올라가는 명령어들은 CPU에 의해서 순차적으로 실행된다. 위 그림에서 보면 메모리상에 명령어 A , 명령어 B , 그리고 명령어 C가 올라가 있다. 이 명려어들은 CPU에 의해서 순차적으로 실행되는 데, 메모리상에서 실행되는 것이 아니라 CPU 내부로 하나씩 이동한 다음 실행하게 된다.

  • 단계 1. Fetch : 메모리 상에 존재하는 명령어를 CPU로 가져오는 작업 위 그림에서 보면 메모리 상에 존재하는 명령어 A를 CPU로 이동시키고 있다.
  • 단계 2. Decode: 가져다 놓은 명령어를 CPU가 해석하는 단계이다. 다시 말해 무슨 일을 하는 명령어 인지 분석하는 단계이다.
  • 단계 3. Execution : 해석된 명령어의 명령대로 CPU가 실행하는 단계이다.

결국 , 프로그램의 기본 실행은 Fetch , Decode , Execution 단계를 거친다고 말할 수 있다.

하드웨어의 구성의 재접근

img_8.png

데이터 이동의 기반이 되는 버스 시스템

데이터를 이동하는 데 있어서 사용되는 전송 경로를 버스 시스템 이라 한다.

버스 시스템은 주고 받는 데이터의 종류에 따라서 어드레스 버스(Address Bus) , 데이터 버스(Data Bus) , 컨트롤 버스(Control Bus) 이렇게 세 가지로 구분이 된다.

I/O 버스를 통해서 CPU, 키보드, 하드디스크 등등 컴퓨터 내,외부에 존재하는 주변 장치들이 연결되어 있다.

I/O 버스는 여러 장치들이 데이터를 주고받기 위한 통로의 역할을 한다.

CPU와 메인 메모리도 데이터를 주고 받기 위해 버스로 연결되어 있다.

지금 까지는 메인 메모리에 저장되어 있는 명령어들을 가져오는 연산(Fetch) 에 대해서만 언급했지만, 역으로 CPU의 레지스터에 저장되어 있는 데이터를 메인 메모리에 저장하는 일들도 발생한다. CPU에서 계산된 덧셈 결과를 메인 메뢰에 저장하는 작업 정도를 예로 들 수 있겠다.

img_5.png

  • 데이터 버스 : 데이터를 이동하기 위해 필요한 버스이다.
  • 어드레스 버스 : 주소값을 이동하기 위해 필요한 버스이다. 그렇다면 왜 주소값을 이동해야 할까? CPU가 0x1024 번지에 저장되어 있는 데이터 4바이트를 읽으려고 한다고 가정해보자 그렇다면 메모리 영역에 주소값 0x1024를 먼저 전달해야 한다. (메모리를 단순히 저장만 하는 바보로 생각하지 말고, 주소가 전달되면 해당 주소의 데이터를 전송하는 컨트롤러가 포함되어 있는 것으로 생각하자) 이때 사용되는 것이 어드레스 버스이다. 메모리는 0x1024 번지에 존재하는 4바이트 데이터를 데이터 버스를 통해서 전달받게 된다.
  • 컨트롤 버스 : CPU가 원하는 바를 메모리에 전달할 때 사용된다. 쉽게 말해서 CPU와 메모리가 서로 특별한 사인을 주고받는 용도로 사용되는 버스이다.

무엇 때문에 컨트롤 버스를 이용해서 CPU가 메모리에 사인을 전달해야 하는가? CPU는 메모리로부터 데이터를 가져오기도 하지만, 반대로 메모리에 데이터를 저장하기도 한다.