💻 혼자 공부하는 컴퓨터구조 + 운영체제 1주차
2024년 모두에게 행복하고 건강한 한해가 되기를 바랍니다!
안녕하세요! 저는 올해 4학년이 되는 19학번 컴공 학생입니다. 😊
어느덧 학교에 입학한지 5년차. . .
이번 겨울 방학을 알차게 보내고 싶어 컴퓨터 구조와 운영체제를 복습해보는 시간을 가지도록 마음먹었습니다!
마침 혼공학습단 11기 를 알게되어 공부할 계기를 확실하게 마련할 수 있었습니다. ㅋㅋ
저 같은 경우는 아침형 인간이라 일찍 일어나서 하루에 2시간씩 공부하기로 정했습니다.
이번 1주차에 공부한 내용은 1. 컴퓨터 구조를 알아야 하는 이유. 2. 컴퓨터가 데이터를 표현하는 방법. 3. 컴퓨터 명령어에 대해 학습하였습니다.
목차 |
---|
1. 컴퓨터 구조 시작하기 |
1-1. 컴퓨터 구조를 알아야 하는 이유 |
1-2. 컴퓨터 구조의 큰 그림 |
2. 데이터 |
2-1. 0과 1로 숫자를 표현하는 방법 |
2-2. 0과 1로 숫자를 표현하는 방법 |
3. 명령어 |
3-1. 소스 코드와 명령어 |
3-2. 명령어의 구조 |
컴퓨터 구조과목을 듣긴 했지만 2년만에 다시 보는거라 기억이 가물가물하네요. ㅋㅋ
그래도 열심히해야죠! 💪
당시 컴퓨터 구조에서 어려웠던 부분은 디지털 논리 회로 부분과 마이크로 명령어 부분이었어요.
플립플롭이 뭐라니 . . . 전가산기가 뭐라니 . . .
PC(Program Counter)에서 명령어가 담겨 있는 메모리 주소를 가져와서 EAX에 저장하고 . . .
이런 내용이었던 거 같습니다.
그래서 혼자 공부하는 컴퓨터 구조 + 운영체제 교재를 통해 2년 전의 기억을 복습하고 집에 박혀있는 컴퓨터 구조책도 다시 한번 봐야할 것 같아요.
1장이니 산뜻하게 출발해볼게요!
작년을 요약하자면 인공지능의 해라고 할 수 있을 것 같습니다.
대규모 언어 모델 LLM(Large Language Model)인 Chat GPT는 우리 사회에 큰 충격을 가져다 주었습니다.
특히, Chat GPT의 코딩 능력은 예상한 수준 이상이었습니다.
예를 들면, 어플리케이션 프로그래밍을 할 때 원하는 기능을 Chat GPT에서 상세히 설명하면 Chat GPT는 빠른 시간 내에 실행이 가능한 코드나 그럴듯한 코드를 내뱉기도 했습니다.
잠시 화제를 돌려보겠습니다. 지금 세상은 누구나 공개된 라이브러리들을 활용하여 새로운 서비스를 개발할 수 있는 시대입니다.
이는 프로그래머들이 직접 기능 모듈을 작성하지 않더라도 잘 활용하기만 할 줄만 안다면 서비스를 개발할 수 있다는 뜻입니다.
그러면 한 가지 질문을 할 수 있습니다.
이런 편한 세상에 프로그래머인 우리가 컴퓨터 구조를 배워야하는 이유가 무엇일까요?
저자는 이 질문에 대해 아래와 같이 답하였습니다.
- 컴퓨터 구조를 이해하면 문제 해결 능력이 향상된다.
- 컴퓨터 구조를 이해하면 문법만으로는 알기 어려운 성능/용량/비용을 고려하여 개발할 수 있다.
현대의 컴퓨터 시스템의 초안은 폰 노이만 구조 입니다.
https://en.wikipedia.org/wiki/Von_Neumann_architecture
폰 노이만 구조 의 가장 큰 특징은 데이터와 명령어 모두 메모리에 저장되는 것 입니다.
현대의 컴퓨터는 다음과 같은 요소로 이루어져 있습니다.
컴퓨터는 크게 흔히 프로그램이라고 부르는 정보와 프로그램을 처리할 장치인 부품으로 이루어져 있습니다.
컴퓨터가 이해하는 정보
이름 | 설명 |
---|---|
데이터 | 0과 1로 이루어진 정적인 이진 정보 |
명령어 | 컴퓨터를 작동시키는 정보 |
컴퓨터의 네 가지 핵심 부품
이름 | 설명 |
---|---|
CPU | 중앙처리 장치로 ALU, CU, 레지스터로 구성된 장치 |
메모리 | 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 장치(휘발성 기억장치) |
보조기억장치 | 현재 실행되지 않는 프로그램의 데이터를 저장(비휘발성 기억장치) |
입출력장치 | HCI(Human Computer Interaction)를 구성하는 장치 |
메인보드와 시스템 버스
이름 | 설명 |
---|---|
메인보드 | 컴퓨터의 각 부품에 전원을 공급하고 부품간에 신호를 주고받는 통로 |
시스템버스 | 컴퓨터 안의 부품 또는 여러 장치 사이를 연결해 데이터와 주소, 제어 신호 등 정보를 전송하는 통로 |
메모리를 이해하는데 있어 가장 중요한 것은 주소 개념입니다.
메모리 주소는 보통 16진수로 표시됩니다. C언어 코드를 통해 살펴보겠습니다.
#include<stdio.h>
void main() {
int number = 10;
printf("%x", &number);
}
위 코드를 실행시키면 16진수 형태로 이루어진 메모리 주소를 얻을 수 있습니다.
이는 해당 주소에 int형 값 10이 저장되어 있음을 알려줍니다.
또한, 명령어와 데이터 모두 메모리에 저장된다는 특징을 가지고 있습니다.
컴퓨터는 메모리에 저장된 명령어와 데이터를 사용하여 프로그램을 실행시킵니다.
다음 그림은 폰 노이만 구조를 보여줍니다.
Central Processing Unit이 Control Unit과 Arithmetic/Logic Unit을 가지고 있는 것을 볼 수 있습니다. 이를 참고하여 다음 그림을 보겠습니다.
이름 | 설명 |
---|---|
연산장치(ALU) | 덧셈, 뺄셈 같은 두 숫자의 산술연산과 배타적 논리합, 논리곱, 논리합 같은 논리연산을 계산하는 디지털 회로 |
레지스터(Register) | 프로세서에 위치한 고속 메모리로 극히 소량의 데이터나 처리 중인 중간 결과와도 같은 프로세서가 바로 사용할 수 있는 데이터를 담고 있는 영역 |
제어장치(CU) | 제어신호를 보내고 명령어를 해석 |
용어가 어려울 수 있으나 일상 속 비유를 통해 설명하면 간단한 내용입니다.
이름 | 비유 |
---|---|
메모리 | 창고 |
제어장치 | 수레 |
시스템 버스 | 도로 |
레지스터 | 작업대 |
CPU | 작업자 |
보조기억장치와 입출력장치는 주변기기로 일컬어 부르기도 합니다.
리눅스 시스템에서는 주변기기를 모두 파일로 관리합니다.
앞서 메인보드와 시스템 버스가 하는 역할을 알아보았습니다.
그렇다면 왜 시스템 버스를 사용할까요?
각각의 장치들이 독립적인 전송 라인을 사용한다면 매무 많은 라인이 필요하기 때문입니다.
시스템 버스의 종류
이름 | 설명 |
---|---|
주소 버스 | 주소를 주고받는 통로 |
데이터 버스 | 명령어와 데이터를 주고받는 통로 |
제어 버스 | 제어 신호를 주고받는 통로 |
컴퓨터는 0과 1로 이루어진 디지털 신호만 이해할 수 있습니다.
10진법을 2진수로 바꾸면 다음과 같습니다.
10진법 | 2진법 | 16진법 |
---|---|---|
10 | 1100 | A |
255 | 11111111 | FF |
보시다시피 큰 수를 2진수로 바꾸면 자리수가 무척 커지게 됩니다.
이를 위하여 16진법으로 표기하기도 합니다.
2진수와 16진법을 계산하는 방법은 10진수와 다를 것이 없습니다.
계산방법 |
---|
10(10) = 1 * 10^1 + 0 * 10 ^ 0 = 10(10) |
10(2) = 1 * 2^1 + 0 * 2 ^ 0 = 2(10) |
10(16) = 1 * 16^1 + 0 * 16 ^ 0 = 15(10) |
음수를 표현하는 방법
2진수를 음수로 바꾸는 방법은 그 수의 보수를 이용합니다.
간단히 말해서 보수는 모든 비트를 반전 시킨 다음, 1을 더하는 것입니다.
예를 들면
1100(2) = 10(10)
0011(2) + 1(2) = 0100(2) = -10(10)
정말 음수인지 확인하기 위해서 두 수를 더해보겠습니다.
1100(2) + 0100(2) = (1)0000(2)이 되어 최상위비트가 짤리므로 0이 됨을 확인할 수 있습니다.
앞서 말했다시피 컴퓨터는 2진수만을 이해할 수 있습니다. 따라서 컴퓨터가 문자를 이해하기 위해서는 특별한 방법이 필요합니다.
문자집합이란 컴퓨터가 인식할 수 있는 문자의 모음입니다.
흔히 사용하는 문자집합은 이런 것들이 있습니다.
문자집합 | 크기(bit) |
---|---|
ASCII | 2^7 |
EUC-KR | 2^16 |
UNICODE | 가변적 |
문자집합은 일종의 암호와 같습니다.
출처: https://stepbystep1.tistory.com/10(frost00님)
예를 들어 ASCII 테이블을 참조하여 65 66 67 이란 데이터가 있다면 이는 A B C를 뜻합니다.
다만 ASCII 코드로는 한글 인코딩을 진행할 수 없습니다.
이를 해결하기 위해 EUC-KR, UNICODE 같은 방법이 등장하였습니다.
이 부분은 다른 포스트에서 다시 다루도록 하겠습니다.
컴퓨터(Computer)는 영단어에서 알 수 있듯이 계산하는 기계입니다.
우리가 1 + 1 이라는 문제를 컴퓨터에게 주면 컴퓨터는 해당 연산을 수행합니다.
여기서 1은 데이터가 되고 +는 연산자(Operator)가 됩니다.
즉, 컴퓨터의 명령어는 이런 형태를 컴퓨터가 이해할 수 있도록 2진수로 표현한 것을 의미합니다.
고급언어로 작성된 원시코드는 컴파일러를 거쳐 기계어로 해석됩니다.
그럼 코드를 작성하면서 진행해보겠습니다.
#include<stdio.h>
int main() {
printf("Hello World!");
return 0;
}
1. 전처리 과정
이 과정에서는 메크로(#include, #define)과 같은 구문을 처리합니다.
결과로 helloworld.c 파일에서 helloworld.i 파일을 얻을 수 있습니다.
2. 컴파일 과정
전처리된 코드을 컴파일합니다.
결과로 helloworld.i 파일에서 helloworld.o 파일을 얻을 수 있습니다.
3. 링크 과정
라이브러리들을 연결합니다.
결과로 helloworld.o 파일에서 helloworld.out(실행파일) 파일을 얻을 수 있습니다.
4.실행결과
컴퓨터 명령어도 1+1 과 다른 것이 없습니다.
연산자 + 피연산자 = 컴퓨터 명령어
어셈블리(Assembly) 언어는 기계어를 사람이 이해할 수 있게 기호화한 언어입니다.
출처: https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming
연산 코드(OP Code)
간단한 연산 코드들만 살펴보겠습니다.
OP Code | 기능 |
---|---|
MOVE | 데이터를 옮겨라 |
ADD | 덧셈 |
SUBTRACT | 뺄셈 |
MULTIPLY | 곱셉 |
DIVIDE | 나눗셈 |
연산 코드는 무엇을 하느냐를 나타냅니다. 즉 영어의 동사와 비슷하다고 볼 수 있습니다.
영어 문법을 배울 때 우리는 1형식, 2형식 등 동사가 목적어를 필요로 하느냐에 따라 나눴던 기억이 있습니다.
연산 코드도 마찬가지로 오퍼랜드 필요 유무와 갯수에 따라서 분류할 수 있습니다.
오퍼랜드
다음은 연산코드의 재료가 되는 오퍼랜드에 대해 알아보겠습니다.
우리가 요리할 때 손에 이미 들고 있는 재료를 바로 넣을 수도 있으나 선반에 있는 재료나 냉장고에 있는 재료를 사용할 때도 있을 것입니다.
오퍼랜드도 마찬가지입니다.
CPU가 읽어들일 수 있는 데이터 단위인 워드(Word) (보통 32bit | 64bit)가 한정되어 있다보니 데이터를 직접 명세하는 방식에는 한계가 있습니다.
따라서 보통 주소 지정 방식을 사용합니다.
주소 지정 방식 |
---|
직접 주소 지정 방식 |
간접 주소 지정 방식 |
레지스터 주소 지정 방식 |
레지스터 간접 주소 지정 방식 |
주소를 한번만 찾느냐 아니면 여러번 찾느냐의 차이가 있습니다.
다음 설명의 빈칸에 들어갈 알맞은 내용을 써 보세요.
프로그램이 실행되려면 반드시 메모리 에 저장되어 있어야 합니다.
이는 폰 노이만 구조의 특성을 나타냅니다.
1101(2)의 음수를 2의 보수 표현법으로 구해보세요.
- 비트를 반전시킵니다.
0010- 반전시킨 비트에 1을 더합니다.
0011
숫자둘을 더해 0이 되는지 확인하겠습니다.
- 1101 + 0011 = 0000
스택과 큐의 개념은 매우 중요한 개념이므로 따로 포스트를 작성해서 링크를 올리도록 하겠습니다! 😊
2024년 1월 6일 최초 작성