* '혼자서 공부하는' 컴퓨터구조+운영체제 이지만, 혼자보단 여럿이하면 더 좋으니 혼공 학습단 13기와 함께합니다 :)
[1주차 학습 목록] ( ੭ ・ᴗ・ )੭
Ch01. 컴퓨터 구조 시작하기
1-1. 컴퓨터 구조를 알아야 하는 이유
1-2. 컴퓨터 구조의 큰 그림
Ch02. 데이터
2-1. 0과 1로 숫자를 표현하는 방법
2-2. 0과 1로 문자를 표현하는 방법
Ch03. 명령어
3-1. 소스 코드와 명령어
3-2. 명령어의 구조
Ch01. 컴퓨터 구조 시작하기
1-1. 컴퓨터 구조를 알아야 하는 이유
우리는 흔히 '컴퓨터 구조'를 생각하면 떠오르는 복잡한 회로 혹은 많은 컴퓨터 부품 등 이러한 이미지는 프로그램 개발과는 크게 관련이 있다고 느껴지지 않는다. 왜냐면 지금까지 컴퓨터의 구조를 몰라도 프로그래밍 언어 문법만 알면 개발하고 실행하는 데 딱히 지장이 없었기 때문이다.
하지만 실력 있는 개발자가 되기 위해서는 반드시 알아야 하는 기본 지식이 바로 '컴퓨터 구조' 이다.
실무에서 개발을 다 하고 실행을 할 때에 내 컴퓨터에서는 잘 돌아가지만 다른 사람의 컴퓨터에서 실행하려고 하면 제대로 작동하지 않는 이러한 경우는 코드상의 문법적인 오류만이 원인이 아닐 것이다. 이럴 때 컴퓨터 구조를 제대로 이해하고 있는 개발자라면 문제 상황을 빠르게 진단할 수 있고, 문제 해결의 실마리를 다양하게 찾을 수 있을 것이다.
또한, 우리가 개발한 사이트가 유명세를 타서 매일 새로운 회원 100명이 가입하고, 매일 새로운 글 100개씩, 새로운 댓글이 1,000개씩 생성되는 상황에서 이들의 정보를 어딘가에 저장을 해야하는 상황에서 어떠한 저장 장치가 필요한지, 그리고 어느 정도의 용량을 갖춰야 적절한지 등등 실력 있는 개발자라면 스스로 판단할 줄 알아야 할 것이다. 이러한 성능, 용량, 비용은 컴퓨터 구조에서 배우는 내용들과 직결되어 있기에 컴퓨터 구조를 이해한다면 앞선 상황에서 적절한 판단을 할 수 있다.
-> 따라서 컴퓨터 구조를 알게되면 문제 해결 능력이 향상되고, 프로그래밍 문법만으로는 알기 어려운 성능, 용량, 비용들을 고려하며 개발을 할 수가 있다!!
1-2. 컴퓨터 구조의 큰 그림
우리가 알아야 할 컴퓨터 구조 지식은 크게 두가지이다!
1. 컴퓨터가 이해하는 정보 / 2. 컴퓨터의 4가지 핵심 부품
1. 컴퓨터가 이해하는 정보 : 데이터, 명령어
컴퓨터는 0과 1로 표현된 정보만을 이해한다.
0과 1로 표현되는 정보 즉, 컴퓨터가 이해하는 정보에는 크게 '데이터'와 '명령어' 이렇게 2가지 종류가 있다.
- 데이터(data)란, 컴퓨터가 이해하는 숫자, 문자, 이미지, 동영상과 같은 정적인 정보를 가리킨다.
- 명령어(instruction)란, 데이터를 움직이고 컴퓨터를 작동시키는 정보이다.
즉, 명령어는 컴퓨터를 작동시키는 정보이고, 데이터는 명령어를 위해 존재하는 일종의 재료이다!
* 이 둘 중 컴퓨터를 실질적으로 작동시키는 더 중요한 정보는 명령어이다. 데이터는 명령어 없이는 아무것도 할 수 없는 정보 덩어리일뿐이지만, 명령어는 데이터를 움직이고 컴퓨터를 작동시키는 정보이기 때문이다.
2. 컴퓨터의 4가지 핵심 부품 : 중앙처리장치(CPU), 주기억장치(메모리), 보조기억장치, 입출력장치
세상에는 아두이노, 라즈베리 파이와 같은 작은 컴퓨터부터 스마트폰, 노트북, 데스크톱, 서버 컴퓨터에 이르기까지 크기와 용도가 제각각인 다양한 종류의 컴퓨터가 있다.
하지만 외관과 용도 상관없이 컴퓨터를 이루는 핵심 부품은 크게 다르지 않다.
컴퓨터를 이루고 있는 핵심부품은 '중앙처리장치(CPU)', '주기억장치(메모리)', '보조기억장치, '입출력장치' 이렇게 4가지이다.
* 주기억장치 종류는 크게 RAM(Random Access Memory), ROM(Read Only Memory) 2가지인데, '메모리'라는 용어는 보통 RAM을 지칭한다.
- 주기억장치(=메모리, main memory)란, 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품이다.
따라서, 프로그램이 실행되기 위해서는 반드시 메모리에 저장되어 있어야 한다. 메모리에 저장된 값들의 위치는 주소로 알 수 있어 컴퓨터는 이 주소를 가지로 메모리 내 원하는 위치에 접근할 수가 있게 된다.
- 중앙처리장치(=CPU, Central Processing Unit)란, 메모리에 저장된 명령어를 읽어 들이고, 해석하고, 실행하는 부품이다. CPU 내부 구성 요소 중 가장 중요한 세가지는 '산술논리연산장치(=ALU, Arithmetic Logic Unit)', '레지스터(register)', '제어장치(Control Unit)' 이다.
-> ALU란, 쉽게 말해 계산기이다. 컴퓨터 내부에서 수행되는 대부분의 계산을 수행한다.
-> 레지스터란, CPU 내부의 작은 임시 저장 장치이다. 프로그램 실행하는 데 필요한 값들을 임시로 저장한다. 따라서 CPU에는 각기 다른 이름과 역할을 가진 여러개의 레지스터가 존재한다.
-> 제어장치란, '제어신호(control signal)'라는 전기 신호를 발생시켜 명령어를 해석하는 장치이다.
* CPU는 메모리에 저장된 값을 읽고 싶을 땐 메모리 읽기라는, 또는 메모리에 어떤 값을 저장하고 싶을 땐 메모리 쓰기라는 제어신호를 메모리를 향해 보낸다.
- 보조기억장치(secondary storage)란, 전원이 꺼져도 보관될 프로그램을 저장하는 부품이다. 앞선 메모리는 전원이 꺼지면 저장된 내용을 잃게 된다. 이러한 치명적인 단점이 있는 메모리를 보조하는 것이 바로 보조기억장치이다. 메모리가 현재 '실행되는' 프로그램을 저장한다면, 보조기억장치는 '보관할' 프로그램을 저장한다고 생각해도 좋다.
ex) 하드디스크, SSD, USB 메모리, DVD, CD-ROM 등등
- 입출력장치(input/output(I/O) device)란, 컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환할 수 있는 부품이다.
ex) 마이크, 스피커, 프린터, 모니터, 키보드, 마우스 등등
* 보조기억장치는 관점에 따라 입출력장치의 일종으로 볼 수도 있다. 실제로 보조기억장치와 입출력장치를 '컴퓨터 주변에 붙어있는 장치'라는 의미에서 '주변장치(peripheral device)'라 통칭하기도 한다.
[PLUS]
- 메인보드(main board)란, 여러 컴퓨터 부품을 연결하는 판이다.
- 시스템 버스(system bus)란, 컴퓨터의 네 가지 핵심 부품이 서로 정보를 주고받는 통로이다. 여기서 버스(bus)란, 메인보드에 연결된 부품들이 서로 정보를 주고받을 때 사용하는 통로를 말한다. 컴퓨터 내부에는 다양한 종류의 버스가 존재한다. 시스템 버스는 주소 버스, 데이터 버스, 제어 버스로 구성되어 있다.
-> 주소 버스(address bus) : 주소를 주고받는 통로
-> 데이터 버스(data bus) : 명령어와 데이터를 주고받는 통로
-> 제어 버스(control bus) : 제어 신호를 주고받는 통로
* CPU 구성 요소 중 제어장치는 제어 버스를 통해 제어 신호를 내보낸다.
(사진)
Ch02. 데이터
2-1. 0과 1로 숫자를 표현하는 방법
비트(bit)란, 0과 1을 표현할 수 있는 가장 작은 정보 단위이다. 즉, 컴퓨터가 이해하는 가장 작은 정보 단위를 말한다. 한개의 비트로는 0 또는 1 이렇게 2가지를 표현할 수 있으므로 n개의 비트로는 2^n가지 정보를 표현할 수 있게 된다.
프로그램을 말할 때는 표현의 편의를 위해 비트보다 큰 단위인 바이트, 킬로바이트, 메가바이트, 기가바이트, 테라바이트 등을 사용한다. 여기서 먼저 바이트(byte)란, 여덟 개의 비트를 묶은 단위를 말한다. 그러면 하나의 바이트가 표현할 수 있는 정보는 2^8(=256)개가 된다. 그 이상의 큰 단위까지 표로 한번에 알아보자.
1 바이트(1 byte) | 8 비트(8 bit) |
1 킬로바이트(1 kB) | 1,000 바이트(1,000 byte) |
1 메가바이트(1 MB) | 1,000 킬로바이트(1,000 kB) |
1 기가바이트(1 GB) | 1,000 메가바이트(1,000 MB) |
1 테라바이트(1 TB) | 1,000 기가바이트(1,000 GB) |
* 바이트를 제외한 kB, MB, GB 등 그 이상의 단위들은 모두 이전 단위를 1,000개 묶어 표현한 단위라는 점
* 이전 단위를 1,024개씩 묶어 표현한 단위는 KiB, MiB, GiB, TiB 이다.
[PLUS]
또 다른 중요한 정보 단위 -> 워드
- 워드(word) : CPU가 한 번에 처리할 수 있는 데이터 크기
- 하프 워드(half word) : 워드의 절반 크기
- 풀 워드(full word) : 워드의 1배 크기
- 더블 워드(double word) : 워드의 2배 크기
-> CPU가 한 번에 16비트를 처리할 수 있다면 1워드는 16비트가 된다.
-> 워드 크기는 CPU마다 다르지만, 현대 컴퓨터의 워드 크기는 대부분 32비트 혹은 64비트이다.
이진법(binary)이란, 1을 넘어가는 시점에 자리 올림을 하여 0과 1만으로 모든 수를 표현하는 방법이다. 우리가 일상적으로 사용하는 것은 십진법(decimal)이다. 십진법은 숫자가 9를 넘어가는 시점에 자리 올림을 하여 0부터 9까지 표현하는 방법이다. 이렇게 이진법으로 표현한 수를 이진수, 십진법으로 표현한 수를 십진수라고 한다.
10만 보고 십진수인지 이진수인지 구분하기 어려워 이진수를 표기할 때는 아래와 같이 표현한다.
1000(2) / 0b1000
그러면 십진수에 음수가 있듯, 이진수에도 음수가 있을까? Yes, 그렇다.
이진법에서 음수는 2의 보수로 표현한다. 2의 보수(two's complement)란, 0과 1만으로 음수를 표현하는 방법 중 가장 널리 사용되는 방법이다. 사전적 의미로 2의 보수는 어떤 수를 그보다 큰 2^n에서 뺀 값이지만, 더 쉽게 표현할 수 있다.
2의 보수는 '모든 0과 1을 뒤집은 수인 1의 보수에, 1을 더한 값'이다. 예를 들어 이진수 1011(2)을 음수(2의 보수)로 표현해보자. 먼저 모든 0과 1을 뒤집으면, 0100 이 된다. 이 수를 1의 보수라고 한다. 그리고 여기에 1을 더한 값인 0101(2)가 2의 보수가 된다. 즉, 1011(2)을 음수로 표현한 값은 0101(2)이다.
우리는 어떤 수의 음수를 두 번 구하면 처음의 그 수가 된다고 알고 있다. 이진수도 마찬가지이다.
1011(2)의 음수인 0101(2)를 다시 한번 더 음수로 표현해보자. 0101(2) -> 1010(2) -> 1011(2) 즉, 0101(2)의 음수로 표현된 값은 원래 본인 값인 1011(2)이다.
여기서 '근데 1011(2)의 음수인 0101(2) 값과 십진수 5를 표현한 이진수 0101(2) 값이 똑같이 생겼는데 이걸 어떻게 구분 하는거지?' 라는 생각을 가질 수 있다.
실제로 보기에는 양수인지 음수인지 구분하기 어렵지만, 컴퓨터 내부에서는 이 수가 양수인지 음수인지 구분하기 위해 플래그(flag)를 사용한다.
십육진법(hexadecimal)이란, 수가 15를 넘어가는 시점에 자리 올림하여 수를 표현하는 방법이다. 십진수 10, 11, 12, 13, 14, 15를 십육진법 체계에선 각각 A, B, C, D, E, F로 표기한다. 이진수로만 데이터를 표현하기에는 큰 숫자를 표현하게 되면 자리수가 길어지는 단점이 있게된다. 그래서 데이터 표현할 때 이진법 외에 십육진법도 자주 사용한다. 십육진법으로 표현한 수를 십육진수라고 하는데 십육진수도 이진수와 비슷하게 15(16) / 0x15 로 표현을 한다. 십진법도 있는데 십육진법을 굳이 사용하는 이유 중 하나는, 이진수 <-> 십육진수의 변환이 쉽기 때문이다.
- 십육진수 -> 이진수 변환 방법
: 십육진수를 이루는 각 글자를 따로따로 이진수로 변환하고 그대로 이어 붙이면 된다.
ex) 1A2B(16) 변환
1) 각 글자 하나씩 이진수로 만든다.
1 -> 0001(2) / A -> 10 -> 1010(2) / 2 -> 0010(2) / B -> 11 -> 1011(2)
2) 순서대로 이어 붙인다.
1A2B(16) = 0001101000101011(2)
- 이진수 -> 십육진수 변환 방법
: 이진수를 이루는 숫자를 네 개씩 끊고 각각 하나의 십육진수로 변환하여 그대로 이어 붙이면 된다.
ex) 11010101(2) 변환
1) 네 개씩 끊어서 각각 십육진수로 변환한다.
1101 -> 13 -> D(16) / 0101 -> 5(16)
2) 순서대로 이어 붙인다.
11010101(2) = D5(16)
2-2. 0과 1로 문자를 표현하는 방법(문자 집합, 아스키 코드, EUC-KR, 유니코드)
문자 집합(character set)이란, 컴퓨터가 인식하고 표현할 수 있는 문자의 모음을 말한다. 컴퓨터는 문자 집합에 속해 있는 문자를 이해할 수 있고, 문자 집합에 속하지 않은 문자는 이해할 수 없다. 하지만, 문자 집합에 속한 문자라고 해서 컴퓨터가 그대로 이해할 수 있는건 아니다.
속해 있는 문자들 또한 0과 1로 변환해야 비로소 컴퓨터가 이해할 수 있다. 이 변환 과정을 문자 인코딩(character encoding)이라고 한다. 같은 문자 집합에 대해서도 여러 다양한 인코딩 방법이 있을 수 있다.
이와 반대로 0과 1로 이루어진 문자 코드를 사람이 이해할 수 있는 문자로 변환하는 과정을 문자 디코딩(character decoding)이라고 한다.
아스키(ASCII: American Standard Code for Information Interchange) 코드란, 아스키 문자(=아스키 문자 집합에 속한 문자)에 대응된 고유한 수를 의미한다. 아스키란, 초창기 문자 집합 중 하나로, 영어 알파벳과 아라비아 숫자, 그리고 일부 특수 문자를 포함한다. 아스키 문자는 각각 7비트로 표현되는데, 7비트로 표현할 수 있는 정보의 가짓수는 2^7개로 총 128개(0 ~ 127까지)의 문자들을 표현할 수 있다.
* 실제로는 하나의 아스키 문자는 8비트(1 바이트)를 사용한다. 하지만 그 중 1비트는 패리티 비트(parity bit) 즉, 오류 검출을 위해 사용되는 비트이기 때문에 실질적 사용되는 비트는 7비트이다.
아스키 코드는 매우 간단하게 인코딩된다는 장점이 있지만, 한글을 표현할 수 없다는 단점도 있다. 그래서 한국을 포함한 영어권 외의 나라들은 자신들의 언어를 0과 1로 표현할 수 있는 고유한 문자 집합과 인코딩 방식이 필요하다고 생각했다. 이러한 이유로 EUC-KR 이라는 한글 인코딩 방식이 등장한 것이다.
ECU-KR이란, 한글을 2바이트 크기로 인코딩할 수 있는 완성형 인코딩 방식이다.
한글 인코딩에는 '완성형 인코딩', '조잡형 인코딩' 두가지 방식이 있다.
- 완성형 인코딩 : 초성, 중성, 종성의 조합으로 이루어진 완성된 하나의 글자에 고유한 코드를 부여하는 인코딩 방식
- 조합형 인코딩 : 초성, 중성, 종성에 해당하는 코드를 합하여 하나의 글자 코드를 만드는 인코딩 방식
-> EUC-KR 인코딩은 완성형 인코딩으로 한글에 2바이트(2byte=2*8bit=16bit) 크기의 코드를 부여한다.
* EUC-KR 인코딩 방식으로 아스키 코드보다 표현할 수 있는 문자가 많아졌지만 '쀍', '쀓', '믜' 등과 같은 글자는 EUC-KR로 표현할 수 없다. 이러한 문제를 조금이나마 해결하기 위해 등장한 것이 EUC-KR 확장 버전인 마이크로소프트의 CP949(Code Page 949)이다.
만일 여러 각 나라마다 언어별로 인코딩을 각각 해야한다면, 다국어를 지원하는 프로그램을 만들 때 각 나라언어의 인코딩을 모두 알아야하는 번거로움이 생긴다. 이러한 번거로움을 해결할 수 있도록 등장한 통일된 표준 인코딩 방식이 바로 유니코드(unicode)이다.
아스키 코드나 EUC-KR은 글자에 부여된 값을 그대로 인코딩 값으로 삼았는데, 유니코드는 다르게 값을 다양한 방법으로 인코딩한다. 이러한 인코딩 방법에는 크게 UTF-8, UTF-16, UTF-32 등이 있다. 그 중 가장 대중적인 방법인 UTF-8으로 통상 1바이트 ~ 4바이트까지의 인코딩 결과를 만들어낸다.
Ch03. 명령어
3-1. 소스 코드와 명령어
우리는 개발을 할 때, C, Java, Python 등과 같은 언어로 개발을 한다. 이러한 언어로 프로그램을 만들고 실행을 하면 컴퓨터는 잘 작동을 한다. 그렇다보니 컴퓨터가 이러한 언어를 이해하고 프로그램을 실행시키는 것이라고 생각이 들 수 있다. 하지만, 그렇지 않다.
우리가 개발을 하기 위해 사용하는 프로그래밍 언어는 오히려 컴퓨터가 아닌 사람이 이해하고 작성하기 쉽도록 만들어진 언어이다. 이렇게 '사람이 쉽게 이해하고 작성할 수 있도록 사람을 위한 언어'를 고급 언어(high-level programming language)라고 한다. 대부분의 프로그래밍 언어가 여기에 속한다.
이와 반대로 사람보다 '컴퓨터가 직접 이해하고 실행할 수 있는 언어'를 저급 언어(low-level programming language)라고 한다. 컴퓨터가 이해하고 실행할 수 있는 언어는 오직 저급 언어뿐인데, 이러한 저급 언어는 명령어로 이루어져 있다. 따라서 고급 언어로 작성되는 소스 코드가 실행이 되려면 반드시 저급 언어 즉, 명령어로 변환이 되어야 한다. 저급 언어에는 '기계어'와 '어셈블리어' 두가지 종류가 있다.
기계어(machine code)란, 0과 1로 이루어진 명령어로 구성된 저급 언어이다. 예를 들어 01111111 01001001 00000000 11111110 .... 와 같은 것들로 이루어진 것이 바로 기계어이다. 그런데 이렇게 0과 1 이진수로 이루어진 기계어가 쭉 나열되면 많이 길어져 가독성이 떨어지기 때문에 십육진수로 표현이 되기도 한다. 이렇게 기계어를 보다보면 이것이 어떠한 것을 의미하고 어떻게 컴퓨터를 작동시키는지 감이 오지 않는다. 오직 컴퓨터만을 위해 만들어진 언어이기 때문에 사람이 읽으려고 하면 그 의미를 파악하기가 어렵다.
그래서 등장한 저급 언어가 '어셈블리어'이다. 어셈블리어(assembly language)란, 0과 1로 이루어진 명령어(기계어)를 읽기 편한 형태로 번역한 저급 언어이다. 기계어 0101 0101 을 읽기 편한 형태의 언어인 어셈블리어로 번역이 되면 push rbp 가 되는 것이다.
사실 프로그래밍 개발을 하다보면 사람이 읽고 쓰기 편한 고급 언어만 사용하다 보니, 굳이 위와같은 저급 언어를 꼭 알아야 하는지 의문이 들 수 있다. 일부러 저급 언어로 개발을 할 일은 없지 않을까 하는 생각을 할 수도 있지만, 어떤 종류 혹은 어떤 분야의 개발자가 되고싶어 하는지에 따라 저급 언어의 중요성이 달라진다. 실제로 어느 분야의 개발자는 어셈블리어를 볼 일이 별로 없을 수 있다. 하지만, 하드웨어와 밀접하게 닿아있는 개발자인 임베디드, 게임 또는 정보 보안 분야의 개발자는 어셈블리어를 많이 이용하게 된다.
자, 앞서서 고급 언어로 작성된 코드가 결국에 저급 언어로 변환되어 실행이 된다고 했다. 여기서 고급 언어에서 저급 언어로 변환되는 방식에는 크게 '컴파일 방식', '인터프리트 방식' 두가지 방식이 있다. 각 방식으로 작동하는 프로그래밍 언어를 '컴파일 언어', '인터프리터 언어'라고 한다.
컴파일 언어란, 컴파일러에 의해 소스 코드가 전체 저급 언어로 변환되어 실행되는 고급 언어이다. 대표적으로 C언어가 있다. 여기서 컴파일러란, 컴파일을 수행해 주는 도구이다. 그렇다면 컴파일이란 또 무엇인가? 컴파일(compile)이란, 컴파일 언어로 작성된 소스 코드는 컴파일러(compiler)에 의해 저급 언어로 변환되는 과정을 말한다. 컴파일이 성공적으로 수행되면 개발자가 작성한 소스 코드가 저급 언어로 변환된다. 그렇게 컴파일러를 통해 저급 언어로 변환된 코드를 목적 코드(object code)라고 한다.
* 소스 코드(고급 언어) -> 컴파일(by.컴파일러) -> 목적 코드(저급 언어)
인터프리터 언어란, 인터프리터에 의해 소스 코드가 한 줄씩 실행되는 고급 언어이다. 대표적으로 Python이 있다. 여기서 인터프리터(interpreter)란, 소스 코드를 한 줄씩 저급 언어로 변환하여 실행해 주는 도구를 말한다.
소스 코드 전체가 저급 언어로 변환되는 컴파일 언어와 달리, 소스 코드를 한 줄씩 한 줄씩 차례대로 실행을 한다.
-> 컴파일 언어 : 소스 코드 컴파일 중 오류가 발생하면 소스 코드 전체가 실행되지 않음
-> 인터프리어 언어 : 소스 코드 인터프리트 중 오류가 발생하면 오류 발생 전까지의 코드는 실행함
[PLUS]
- 목적 파일 : 목적 코드로 이루어진 파일
- 실행 파일 : 실행 코드로 이루어진 파일 ex) 윈도우 .exe 파일
* 목적 파일과 실행 파일은 서로 다른 파일이므로, 목적 코드가 실행 파일이 되기 위해서는 '링킹(linking)'이라는 작업을 거쳐야 한다.
3-2. 명령어의 구조(명령어, 연산 코드, 오퍼랜드, 주소 지정 방식)
앞에서 저급 언어는 명령어들로 이루어져 있다 말했는데, 이러한 명령어 하나하나들은 어떻게 생겼을지 알아보자.
명령어는 연산 코드와 오퍼랜드로 구성이 되어 있다. 연산 코드(operation code)란, 명령어가 수행할 연산을 의미한다. 오퍼랜드(operand)란, 연산에 사용할 데이터 혹은 연산에 사용할 데이터가 저장된 위치를 의미한다.
* 연산 코드 -> 연산자, 오퍼랜드는 -> 피연산자 라고도 부른다.
여기서 연산 코드가 담기는 영역을 '연산 코드 필드', 오퍼랜드가 담기는 영역을 '오퍼랜드 필드'라고 한다.
오퍼랜드 필드에는 오퍼랜드 즉, 연산에 사용할 데이터 혹은 연산에 사용할 데이터가 저장된 위치가 담겨진다. 즉, 숫자와 문자 등을 나타내는 데이터 or 데이터가 저장된 메모리나 레지스터의 주소가 올 수 있게 되는 것이다. 다만 데이터를 직접 담기보단 데이터가 저장된 위치 즉, 메모리 주소나 레지스터 이름이 담긴다. 그래서 보통 오퍼랜드 필드를 주소 필드라고 많이들 부른다. 오퍼랜드는 하나도 없을 수도 있고, 한 개만 있을 수도 있고, 두 개 또는 세 개 등 여러개가 있을 수도 있다. 이렇게 오퍼랜드의 개수에 따라 명령어 이름이 정해진다.
-> 오퍼랜드가 하나도 없는 명령어('0-주소 명령어'), 오퍼랜드가 하나인 명령어('1-주소 명령어'), 오퍼랜드가 두 개인 명령어('2-주소 명령어'), 오퍼랜드가 세 개인 명령어('3-주소 명령어')
명령어가 수행할 연산인 연산 코드는 크게 4가지 유형으로 나눌 수 있다.
-> 1) 데이터 전송, 2) 산술/논리 연산, 3) 제어 흐름 변경, 4) 입출력 제어
각 유형에 따른 대표적인 연산 코드는 다음과 같다.
1) 데이터 전송
: MOVE(데이터를 옮겨라), STORE(메모리에 저장하라), LOAD(=FETCH, 메모리에서 CPU로 데이터를 가져와라), PUSH(스택에 데이터를 저장하라), POP(스택의 최상단 데이터를 가져와라)
2) 산술/논리 연산
: ADD / SUBTRACT / MULTIPLY / DIVIDE(덧셈 / 뺄셈 / 곱셈 / 나눗셈을 수행하라), INCREMENT / DECREMENT (오퍼랜드에 1을 더하라 / 오퍼랜드에 1을 빼라), AND / OR / NOT(AND / OR / NOT 연산을 수행하라), COMPARE(두 개의 숫자 또는 TRUE / FALSE 값을 비교하라)
3) 제어 흐름 변경
: JUMP(특정 주소로 실행 순서를 옮겨라), CONDITIONAL JUMP(조건에 부합할 때 특정 주소로 실행 순서를 옮겨라), HALT(프로그램의 실행을 멈춰라), CALL(되돌아올 주소를 저장한 채 특정 주소로 실행 순서를 옮겨라), RETURN(CALL을 호출할 때 저장했던 주소로 돌아가라)
4) 입출력 제어
: READ(=INPUT, 특정 입출력 장치로부터 데이터를 읽어라), WRITE(=OUTPUT, 특정 입출력 장치로 데이터를 써라), START IO(입출력 장치를 시작하라), TEST IO(입출력 장치의 상태를 확인하라)
앞서 오퍼랜드 필드에 메모리나 레지스터의 주소를 담는다고 말했다. 이때 문득 그냥 <연산 코드, 연산 코드에 사용될 데이터> 형식으로 명령어를 구성하지 왜 굳이 메모리나 레지스터 주소를 담는 것인지 의문이 들 수 있다. 이러한 이유는 명령어의 길이 때문이다.
예를 들어 하나의 명령어가 16비트로 구성되어 있고, 그중에서 연산 코드 필드가 4비트라고 가정을 해보자. 이때 '2-주소 명령어'인 경우에 16-4인 12비트로 오퍼랜드 당 6비트정도밖에 할당이 되지 않는다. 즉, 2^6정도 표현이 된다. 그리고 '3-주소 명령어'인 경우에는 12비트로 오퍼랜드 당 4비트정도 할당되어 2^4정도 표현을 할 수 있게된다. 이렇게 오퍼랜드 수가 많아질수록 각 오퍼랜드가 할당되는 크기는 더욱 작아진다.
하지만, 이때 오퍼랜드 필드 안에 메모리 주소가 담기게 된다면 표현할 수 있는 데이터의 크기는 하나의 메모리 주소에 저장할 수 있는 공간만큼 커진다. 예를 들어 한 주소에 16비트를 저장할 수 있는 메모리가 있다고 하자. 이 메모리 안에 데이터를 저장하고, 오퍼랜드 필드 안에 이것에 해당하는 메모리 주소를 명시한다면 표현할 수 있는 정보의 가짓수는 2^16이 된다. 이렇게 오퍼랜드 필드에 메모리 주소가 아닌 레지스터 이름을 명시할 때도 마찬가지로 해당 레지스터가 저장할 수 있는 공간만큼 정보의 가짓수는 커지게 된다.
이렇게 연산 코드에 사용할 데이터가 저장된 위치 즉, 연산의 대상이 되는 데이터가 저장된 위치를 유효주소(effective address)라고 한다. 앞에서 말했듯, 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때 연산에 사용되는 데이터 위치를 찾는 방법을 주소 지정 방식(addressing mode)이라고 한다.
주소 지정 방식에는 다음과 같이 대표적으로 5가지 방식이 있다.
1. 즉시 주소 지정 방식(immediate addressing mode)
: 연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식
- 표현할 수 있는 데이터의 크기가 작아지는 단점 존재
- 메모리나 레지스터로부터 찾는 과정이 없기에 다른 방식들보다 빠름
2. 직접 주소 지정 방식(direct addressing mode)
: 오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식
- 표현할 수 있는 오퍼랜드 필드의 길이가 연산 코드의 길이만큼 짧아져
표현할 수 있는 유효 주소에 제한이 생길 수 있음
3. 간접 주소 지정 방식(indirect addressing mode)
: 유효 주소의 주소를 오퍼랜드 필드에 명시하는 방식
- 직접 주소 지정 방식보다 표현할 수 있는 유효 주소 범위가 더 넓음
- 두 번의 메모리 접근이 필요하기 때문에 앞선 방식보다 일반적으로 느림
4. 레지스터 주소 지정 방식(register addressing mode)
: 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방식
- 일반적으로 CPU 외부에 있는 메모리 접근보다 내부에 있는 레지스터 접근이 더 빠르기에,
직접 주소 지정 방식보다 빠르게 데이터 접근이 가능함
- 직접 주소 지정 방식과 비슷한 문제인 표현할 수 있는 레지스터 크기에 제한이 생길 수 있음
5. 레지스터 간접 주소 지정 방식(register indirect addressing mode)
: 연산에 사용할 데이터를 메모리에 저장하고, 그 주소(유효주소)를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방식
- 메모리에 접근하는 횟수가 한번이기에 간접 주소 지정 방식보다 빠름
[과제]
- 필수 과제
01) 51p
03. 다음 설명의 빈칸에 들어갈 알맞은 내용을 작성해라.
프로그램이 실행되려면 반드시 [ ]에 저장되어 있어야 합니다.
답) 메모리
* 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품이 메모리이기 때문에, 프로그램이 실행되기 위해서는 반드시 메모리에 저장되어 있어야 한다.
02) 65p
03. 1101(2)의 음수를 2의 보수 표현법으로 구해 보세요.
답) 0011
* 쉽게 2의 보수를 구하는 방법은 이진수의 0과 1을 각각 뒤집고, 그 수에 1을 더하는 것이다.
1101(2) ----- (각각 0과 1 뒤집기) -----> 0010 ----- (1 더하기) -----> 0011
- 선택 과제
01) 100p
Q. 스택과 큐의 개념 정리하기.
스택(stack)이란, 한쪽 끝이 막혀 있는 통과 같은 저장 공간이다.
막혀있지 않은 쪽으로 데이터를 차곡차곡 저장하고, 저장한 자료를 빼낼 때는 마지막으로 저장한 데이터부터 빼낸다.
-> 나중에 저장한 데이터를 가장 먼저 빼내는 데이터 관리 방식(후입선출)이라는 점에서 LIFO(Last In First Out) 자료 구조이다.
* 새로운 데이터 저장하는 명령어 : PUSH / 저장된 데이터 꺼내는 명령어 : POP
큐(queue)란, 양쪽이 뚫려 있는 통과 같은 저장 공간이다.
한쪽으로는 데이터를 저장하고, 다른 한쪽으로는 먼저 저장한 순서대로 데이터를 빼낸다.
-> 가장 먼저 저장된 데이터부터 빼내는 데이터 관리 방식(선입선출)이라는 점에서 FIFO(First In First Out) 자료 구조이다.
'Studying > 혼공학습단' 카테고리의 다른 글
[혼공컴운]6주차_Ch.14 - 15 (0) | 2025.02.23 |
---|---|
[혼공컴운]5주차_Ch.12 - 13 (0) | 2025.02.18 |
[혼공컴운]4주차_Ch.09 - 11 (0) | 2025.02.13 |
[혼공컴운] 3주차_Ch.06 - 08 (0) | 2025.02.03 |
[혼공컴운] 2주차_Ch.04 - 05 (0) | 2025.01.20 |