컴퓨터의 작동원리 기초 : A to Z
컴퓨터의 구성 요소들
- 메인보드
- 파워 : 주전원 포트에 끼우고. 필요 전력보다 넉넉하게 구입하는 것이 좋다.
- CPU + 쿨러 : 소켓에 맞춰서 살짝 올려놓으면 된다. 제발 돌기가 망가지지 않게 조심하자.
- 주기억장치(RAM) : 메모리 슬롯에 꽂고. 대개 CPU 소켓 옆에 있다. 크기도 딱 맞아서 알아보기 쉽다. 휘발성. DDR 버전을 잘 보고 구입하자.
- 보조기억장치 : 디스크(HDD, SSD) 최근 NVMe SDD가 빠르다 카더라. 비휘발성. 보통 OS를 SDD에 올려놓고 깡용량은 HDD로 사용.
- 그래픽 카드(GPU) : 정확히는 그래픽 카드 내에 GPU 칩이 들어 있는 것이다만 두 용어를 혼용해서 사용하고 있다. 일반 레벨에서는 둘을 구분하는 이점이 없다... 병렬처리에 특화. ML할 때 자주 사용하게 될 것이다. GPU 자체에 쿨러 달려 있는 제품이 많다.
- 디스플레이 : HDMI 딱~ 꽂아서 사용.
FDD(플로피 디스크)나 자기 테이프는 이제 안 쓴다.
메모리 계층은 아래 다른 포스트 참고.
여튼, RAM이 빠르니까 Redis니 Memcache니 쓰는 것이고, 평소엔 Disk를 사용.
darrengwon.tistory.com/818?category=911757
컴퓨터를 켤 때 일어나는 일들(부팅절차)
(1) 전원을 킨다 => 파워가 메인보드에 전기를 공급한다. 메인보드를 경유하여 각 부품에 전기가 동작된다. 아마 사용자가 이를 통해 듣는 소리는 팬이 돌아가는 소리일 것이다.
(2) 메인보드 제조사 로고가 뜨며 메인보드에 내장된 ROM(Read Only Momery)의 BIOS가 작동한다. 이는 Read Only라는 이름답게 수정할 수 없다. 정확히는 POST(Power On Self Test) 프로그램을 ROM에서 가져와 실행한다.
POST는 일종의 하드웨어 검사로 모니터는 끼워져있는가, 키보드는 꽂아져 있나, 메모리는 얼마인가 등을 확인하는 프로그램
(3) POST를 통과했다면 부트로더(Boot loader)를 ROM에서 가져와 실행한다. 부트로더는 disk에 있는 OS를 RAM으로 가져온다(이를 부팅이라 한다). OS 설치해봐서 알겠지만, OS를 갈아 엎고 싶다면 USB로 부팅해서 재설치해도 되고, 보통은 SSD에 저장해서 초기 로딩(부팅) 시간을 줄인다.
"로딩"은 disk에 있는 내용을 사용하기 위해 RAM으로 복사하는 것을 말한다. 그것이 OS이든, 응용 프로그램이든.
당연히 메모리 계층대로, disk의 OS를 RAM으로 복사하여 CPU가 이를 사용하는 순으로 간다.
(4) OS가 로드되고, 이제 컴퓨터를 사용하면 된다!
운영체제(OS)는 무슨 일을 하는가?
운영체제의 종류 : Unix(그리고 Unix를 뿌리로 둔 Linux), Window, Android, iOS 등등...
"컴퓨터 자원을 프로세스에게 적절히 분배한다", "커널을 통해 하드웨어를 제어 한다" 라고 알고 있었고 맞았다.
컴퓨터는 왜 2진수를 사용하는가 : 진공관에서 트랜지스터로
- 에디슨 효과(리처드슨 효과, 열전자방출효과)
필라멘트에 열이 오르면 전자(-)를 방출함. -를 양극(+)으로 이동하고, 전자의 흐름이 곧 전류이므로, 열이 오르고 양극을 제공해주면 전류가 흐른다(전기가 발생한다) 라고 요약할 수 있다.
- 진공관의 원리
에디슨 효과를 이용하여 진공관을 만들었다. (작동 중인 진공관이 뜨거운 것은 이 때문이다. 열을 가해야 전자가 방출되니까)
방출된 전자를 흘렀다, 막았다 하는 on/off의 기능을 가진 것이 진공관이다. 당연히 전자(-)가 흐를 수 있도록 양극(+)를 제공하느냐 마느냐로 on/off가 된다. 정확히는 control grid가 양극(+)으로의 차단을 막느냐 푸느냐에 따라 on/off가 되는 것이다.
0과 1이란 정보를 표기할 수 있으므로 진공관을 이용해 컴퓨터를 만들 수 있을 것이다. 이를 이용한 컴퓨터가 애니악이다. (현대는 진공관 대신 트랜지스터를 사용한다)
현대는 진공관이 아닌 반도체를 이용한 트랜지스터를 사용한다.
트랜지스터는 벨 연구소에서 발명되었고, 관련 속성은 아래 포스트로 갈음한다.
darrengwon.tistory.com/548?category=911757
현대적 컴퓨터의 구조
- 폰 노이만 구조(Von Neumann architecture) = 내장형 프로그램 방식의 컴퓨터(stored program computer)
현재 컴퓨터들은 이 구조를 따르고 있다. 그 이전의 컴퓨터들은 스위치를 설치하고 전선을 연결하여 데이터를 전송하고 신호를 처리하는 식으로 프로그래밍하였다. (즉, 컴퓨터 밖의 전선을 이용해야 했다.)
그러나 폰 노이만 구조가 제시된 후에는 내장형 프로그램 방식으로 바뀌었다. 즉, 프로그램이 메모리에 들어가게 된 것이다. 프로그램을 구성하는 명령어들을 임의 접근이 가능한 메모리(RAM)상에 순차적으로 배열하고, 동시에 조건 분기를 무제한적으로 허용하며 이는 튜링 완전하다.
특징
* 연산 장치와 기억 장치가 분리되어 있고, 서로 통신하며 작동한다
- 현대적인 아키텍쳐, System bus
현대는 전통적인 폰 노이만 구조가 아니라 조금 더 개량된 아키텍쳐를 가지고 있다.
cpu, memory, io 장치는 익숙한데 bus라는 개념이 새로 등장한다.
각 장치가 서로 바로 Memory로 통신하는 것이 아니라 System bus를 경유하여 소통한다는 사실이 중요하다.
bus란 이진수를 나르는 커뮤니케이션 시스템이다.
bus는 크게 3가지가 있고 이를 통칭하여 System bus라고 부른다.
- Control bus : 제어 신호를 실고 나른다.
- Address bus : 메모리 구조를 공부할 때 중요하다. 주소 bus. 메모리와 함께 후술
- Data bus : 메모리 구조를 공부할 때 중요하다. 데이터 bus. 메모리와 함께 후술
메모리의 기본 구조
RAM에 필요한 내용을 가져놨다가 CPU가 RAM에서 가져와 연산을 한다.
매번 소통하는 것보다 빠르게 만들기 위해 L1 ~ L3 캐시 메모리가 있다.
* 순차 접근 / 임의 접근
RAM은 random access memory이다. 임의 접근. 이가 가능한 이유는 '주소'를 활용하기 때문
순차 접근 메모리는 자기 테이프이고, 이제는 사용되지 않는다. 주소가 없어 일일히 다 찾아야 한다.
메모리의 주소를 참고하여 데이터가 있는 주소로 곧바로 이동할 수 있어서 임의 접근이 더 진보된 기술이다.
row 레벨 언어가 포인터를 가지는 것은, 임의 접근하는 메모리에서 특정 데이터를 찾아야하기 때문에 존재하는 것이다.
포인터는 해당 데이터가 저장된 메모리 주소를 담은 것이다. (Golang할 때 편하게 익힌 바 있다)
* System bus와 RAM의 임무
각 bus가 기판 위에 새겨진 것을 직접 확인할 수 있다.
Ram socket에 꽂힌 메모리는 딱 2가지 일을 한다.
- CPU가 요청한 정보를 찾아 보내주는 것
- CPU가 연산한 결과를 저장하는 것
그 외에 메모리 관련하여 작성한 포스트들.
darrengwon.tistory.com/1007?category=907676
darrengwon.tistory.com/840?category=911757
CPU의 기본 구조
(1) CPU의 언어
CPU가 이해할 수 있는 언어는 기계어(1000101010010...)이다.
- 기계어 : 별 다른 트랜스파일없이 CPU가 곧바로 이해할 수 있는 언어. 단, 기계어라해도 CPU의 종류에 따라 명령의 값이 다르다. 8051 CPU와 AVR CPU의 명령어에는 차이가 난다.
- 어셈블리어 : 기계어는 CPU가 채택한 ISA에 따라 다 다르기 때문에 어셈블리어의 명령어 역시 통일된 규격이 없다. 그리고 그냥 언어일 뿐이다. C, python, javascript... 다만 많이 row할 뿐이지
- 고수준 언어 : 우리가 아는 프로그래밍 언어들.
더 나아간 내용은 아래 포스트를 참고해보자.
darrengwon.tistory.com/776?category=907676
(2) CPU 명령어 집합
어셈블리어의 니모닉(Mnemonic)으로 추상화된 CPU 명령어 집합으로 CPU가 할 수 있는 동작의 종류를 이해할 수 있다. CPU의 기본 동작들을 응용하여 더 복잡한 동작이 이루어지는 것이다.
- add : 숫자 2개를 더한다
- compare : 숫자를 비교한다
- in : 입력장치(ex - 키보드)로 부터 정보를 받는다.
- jump : 지정된 메모리 주소로 점프한다
- jump if : 조건에 따라 점프한다
- load : 메모리에서 cpu로 정보를 가져온다
- out : 출력 장치로 정보를 출력한다
- store : 메모리에 정보를 저장한다
- 그 외 더 많은 동작들...
(3) CPU의 구성 요소들
1. 산술논리연산장치(ALU)
실제로 사칙연산 등 연산 작업이 이루어지는 곳
2. 레지스터 (Register)
Regist(등록부) 라는 이름답게 ALU가 일을 하기 위한 작업공간 정도로 이해하면 좋다.
기능적으로 무언가가 저장된다고 알고 있자. 그러나 메모리(RAM) 과는 다르다!
- 메모리 주소 레지스터(memory address register, MAR) : 읽거나 쓸 메모리 주소 저장
- 프로그램 카운터(program counter, PC) : 다음 명령어의 메모리 주소 저장. (프로그램 명령의 실행 위치)
- 메모리 데이터 레지스터(memory data register, MDR) : 메모리에서 읽어온 데이터 저장
- 명령어 레지스터(instruction register, IR) : 메모리에서 읽어온 명령어 저장
- 어큐뮬레이터(accumulator, Acc) : 연산에 사용되는 데이터 저장
CPU가 구체적으로 동작하면서 레지스터가 빈번히 사용된다.
프로그램 카운터에 주소 저장, 메모리 주소 레지스터에 해당 주소 저장, 메모리 데이터 레지스터에 명령어 저장
명령어 레지스터에 해당 명령어 옮김... 동작이 복잡하다.
3. 제어장치
건네 받은 명령어를 decode한다.
CPU가 동작하는 방법
완벽하지는 않지만 대략 이런 방식으로 레지스터와 상호작용하면서 cpu가 동작하는구나, 하는 감을 잡을 수 있다.
임베디드 관련 공부와 기계에 가까운 작업을 한다면 훗날에 공부해보기로 한다...
(1) OS가 RAM으로 프로그램을 불러온 후 프로그램 카운터 레지스터에게 해당 주소를 넘김
OS가 disk에 있는 프로그램을 특정 메모리 주소에 올린 후 해당 프로그램을 실행하는 instruction(예를 들어 LOAD 0x00000001)이 담긴 메모리 주소를 CPU의 프로그램 카운터에게 넘긴다.
이로써 프로그램 카운터는 다음 번에 수행해야 하는 instruction이 메모리의 특정 주소에 있는 것을 알게 된다.
(2) 프로그램 카운터 레지스터에서 메모리 주소 레지스터로 주소를 넘긴다.
프로그램 카운터에서 메모리 주소 레지스터로 실행해야 하는 instruction이 담긴 메모리의 주소를 넘긴다.
(3) 메모리 주소를 참고하여 instruction을 메모리 데이터 레지스터에 가져온다.
(4) 메모리 데이터가 가져온 instruction을 명령어 레지스터에 옮긴다.
동시에 프로그램 카운터가 하나 오른다.
(5) 명령어 레지스터는 해당 명령어를 제어 장치에 넘겨 decode
제어 장치는 받은 명령어를 decode한 후 해당 명령어에 따라 적절하게 레지스터를 활용한다.
LOAD 0x00000001 라면 해당 주소에 있는 주소를 메모리 주소 레지스터에 넣는다.
해당 메모리 주소에 있는 값은 메모리 데이터 레지스터에 담긴다.
(6) 얻은 값은 어큐뮬레이터에 저장한다.
ALU(산술논리장치)는 어큐뮬레이터를 이용하여 적절한 연산을 처리한다.
정보의 단위
* 측정 데이터(Data) => 처리, 분석 (Data analysis) => 정보(information)
* 정보의 기본 단위 : bit(off/on, 0/1)
* bit byte(8bit, 메모리 주소의 기본 단위) KB(1024byte) MB(1024KB) GB(1024MB) TB(1024GB)
* byte는 8진수를 사용하는 메모리 주소의 기본 단위
* word : CPU가 데이터를 다루는 기본 단위 = 레지스터의 크기
word는 고정되어 있는 것이 아니라 시스템마다 다르다. 16비트(2byte), 32비트(4byte), 64비트(8btye) 다양하다.
32비트 컴퓨터 => CPU가 32비트
64비트 아이폰 => CPU가 64비트
추가로, 정보 이론 기초에 대해서 간단히 읽어보자.
ratsgo.github.io/statistics/2017/09/22/information/
이진수와 진법
프로그래머는 2진수(0b), 8진수(0), 10진수, 16진수(0x)에 익숙해야 한다.
int octNum = 010; // 앞에 0이 붙으면 8진수. 10(8) 이므로 값은 8
int hexNum = 0x10; // 0x가 붙으면 16진수 10(16) 이므로 값은 16
int binNum = 0b10; // ob가 붙으면 2진수 10(2) 이므로 값은 2
10진수, 2진수 변환은 중학생 때 배웠기도 했으니 생략하겠다.
보수는 뺄셈은 음의 정수를 더하는 꼴로 계산해야 하기 때문에 필요하다. 구하는 방법은 간단하다.
- 1의 보수 : 0과 1을 반전하면 1의 보수가 된다.
- 1010의 1의 보수는 0101이다.
- 2의 보수 : 1의 보수에 1을 더한 값.
- ex) 1010의 2의 보수는 0101 에 1을 더한 0110이 된다.
bit를 넘어 overflow되면 정확한 값을 출력할 수 없다.
darrengwon.tistory.com/863?category=907676