이 글은 혼자 공부하는 컴퓨터 구조+운영체제 교재와 강의를 참고하여 정리한 글입니다. 오타나, 잘못된 내용이 있으면 언제든지 알려주세요! 감사합니다.😊
명령어
소스코드와 명령어
컴퓨터는 명령어를 처리하는 기계이다.
모든 소스 코드는 컴퓨터 내부에서 명령어로 변환되는데, 우리가 작성한 소스코드가 어떻게 컴퓨터를 동작시키는 명령어로 변환될까?
고급 언어와 저급 언어
고급 언어(high-level)
- 개발자가 이해하기 쉽게 만든 언어로, 대부분의 프로그래밍 언어가 고급 언어에 속한다.
- 예) Java, Python. C++ 등등
- 고급 언어가 실행되려면 반드시 저급 언어, 명령어로 변환되어야 한다. (고급 언어 -> 저급 언어)
저급 언어(low-level)
- 컴퓨터가 직접 이해하고 실행할 수 있는 언어이다.
- 즉, 저급 언어는 명령어이다.
- 저급 언어는 두 가지 종류가 존재한다.
- 기계어
- 어셈블리어
기계어
- 기계어는 0과 1로 이루어진 명령어로 구성된 저급 언어이다.
- 기계어를 이진수로 나열하면 너무 길어지기 때문에 십육진수로 표현하기도 한다.
- 사람이 읽으면 어떤 의미인지 이해하기 어렵다.
- 기계어는 오로지 컴퓨터만을 위해 만들어진 언어
어셈블리어
- 어셈블리어는 0과 1로 이루어진 기계어를 읽기 편한 형태로 번역한 저급 언어이다.
- 어셈블리어 한 줄 한 줄이 컴퓨터를 동작시키는 명령어이다.
컴파일 언어와 인터프리터 언어
고급 언어는 저급 언어로 어떻게 변환될까?
고급 언어가 저급 언어로 변환되는 과정에는 크게 2가지 방식이 있다.
- 컴파일 방식
- 컴파일 언어: 컴파일 방식으로 작동하는 프로그래밍 언어
- 인터프리트 방식
- 인터프리터 언어: 인터프리트 방식으로 작동하는 프로그래밍 언어
컴파일 언어
- 컴파일 언어는 컴파일러에 의해 소스 코드 전체가 목적 코드, 저급 언어로 변환되어 실행되는 고급 언어이다.
- 컴파일: 컴파일 언어로 작성된 소스 코드가 컴파일러에 의해 저급 언어로 변환되는 과정
- 컴파일러: 컴파일을 수행해 주는 도구
- 컴파일 결과로 저급 언어인 목적 코드가 생성된다.
- 소스 코드 컴파일 중 오류가 발생하면 소스 코드 전체가 실행되지 않는다.
참고: 목적 파일 vs 실행 파일
목적 파일은 목적 코드로 이루어진 파일을 말한다. 목적 파일과 실행 파일은 둘 다 기계어로 이루어진 파일이다.
하지만, 목적 파일과 실행 파일은 다르다. 목적 파일은 링킹(linking)을 거쳐야 실행 파일이 된다.
링킹이란? 각기 다른 목적 코드를 하나의 실행 파일로 연결시켜주는 작업
인터프리터 언어
- 인터프리터 언어는 인터프리터에 의해 소스 코드가 한 줄씩 실행되는 고급 언어이다.
- 대표적인 예시) Python
- 소스 코드 전체가 저급 언어로 변환되기까지 기다릴 필요가 없다.
- 인터프리터: 소스 코드를 한 줄씩 저급 언어로 변환하여 실행해주는 도구
- 소스 코드 인터프리트 중 오류가 발생하면 오류 발생 전까지의 코드는 실행된다.
컴파일 언어 vs 인터프리터 언어
- 예시) 독일어로 쓰인 책을 한국어로 번역한다고 가정해보자.
- 컴파일 방식: 책 전체를 한국어로 번역한 뒤 번역된 책(목적 코드)을 건네준다.
- 인터프리트 방식: 책 한 줄씩 한국어로 번역해 준 뒤 설명해 준다.
모든 프로그래밍 언어는 컴파일 언어와 인터프리터 언어로 명확하게 구분될까? -> X
양분된 개념이 아니다. 즉, 하나의 프로그래밍 언어가 반드시 컴파일과 인터프리트 방식 중 하나의 방식으로만 작동하는 것은 아니다.
예) Java의 경우 저급 언어가 되는 과정에서 컴파일과 인터프리트를 동시에 수행한다.
'고급 언어가 저급 언어로 변환되는 대표적인 방법에는 컴파일 방식과 인터프리트 방식이 있다'라고 이해하자.
명령어의 구조
저급 언어는 명령어들로 이루어져 있다.
명령어 하나하나는 어떻게 생겼으며 어떻게 동작할까?
연산 코드와 오퍼랜드
- 명령어는 '무엇을 대상으로, 어떤 작동을 수행하라'라는 구조로 되어 있다.
- 예) 더해라 100과 120을, 저장해라 10을 메모리 128번지에
- 명령어는 연산 코드와 오퍼랜드로 구성되어 있다.
- 연산 코드는 명령어가 수행할 연산이다. 연산자라고도 부른다.
- 오퍼랜드는 연산에 사용할 데이터 또는 연산에 사용할 데이터가 저장된 위치이다. 피연산자라고도 부른다.
- 연산 코드 필드: 연산 코드가 담기는 영역. 색칠된 부분
- 오퍼랜드 필드: 오퍼랜드가 담기는 영역, 색칠되지 않은 부분
- 기계어와 어셈블리어 또한 명령어이기 때문에 연산 코드와 오퍼랜드로 구성되어 있다.
오퍼랜드
- 오퍼랜드는 연산에 사용할 데이터 또는 연산에 사용할 데이터가 저장된 위치를 의미한다.
- 대부분 경우에 연산에 사용할 데이터가 저장된 위치, 즉 메모리 주소나 레지스터 이름이 담긴다.
- 그래서 오퍼랜드 필드를 주소필드라고 부르기도 한다.
- 오퍼랜드는 명령어 안에 하나도 없을 수도 있고, 한 개만 있을 수도 있고, 여러 개가 있을 수도 있다.
- 오퍼랜드의 개수에 따른 명령어
- 0-주소 명령어: 오퍼랜드가 하나도 없는 명령어
- 1-주소 명령어: 오퍼랜드가 하나인 명령어
- 2-주소 명령어: 오퍼랜드가 2개인 명령어
- 3-주소 명령어: 오퍼랜드가 3개인 명령어
연산코드
- 연산 코드는 명령어가 수행할 연산이다.
- 예시) 더해라, 빼라, 저장해라
- 연산 코드 종류는 매우 많지만, 크게 4가지로 나눌 수 있다.
- 데이터 전송
- 산술/논리 연산
- 제어 흐름 변경
- 입출력 제어
- 명령어의 종류와 생김새는 CPU마다 다르기 때문에 연산 코드의 종류와 생김새 또한 CPU마다 다르다.
대표적인 연산 코드의 종류
외우지 말고 이러한 유형이 있구나 하고 넘어가자.
- 데이터 전송
- MOVE: 데이터를 옮겨라. (레지스터에서 다른 레지스터로)
- STORE: 메모리에 저장하라
- LOAD (FETCH): 메모리에서 CPU로 데이터를 가져와라
- PUSH: 스택에 데이터를 저장하라
- POP: 스택의 최상단 데이터를 가져와라
- 산술 논리 연산
- ADD / SUBTRACT / MULTIPLY / DIVIDE: 덧셈, 뺄셈, 곱셈, 나눗셈을 수행하라
- INCREMENT / DECREMENT: 오퍼랜드 1을 더하라, 오퍼랜드에 1을 빼라
- AND / OR / NOT: AND, OR, NOT 연산을 수행하라
- COMPARE: 두 개의 숫자 또는 TRUE / FALSE 값을 비교하라
- 제어 흐름 변경
- JUMP: 특정 메모리 주소로 실행 순서를 옮겨라. 예) JUMP 120, 120번지에 있는 명령어를 실행해라
- CONDITIONAL JUMP: 특정 조건에 부합할 때 특정 주소로 실행 순서를 옮겨라
- HALT: 프로그램의 실행을 멈춰라
- CALL: 리턴 주소를 저장한 채 특정 주소를 실행해라. 함수를 호출하는 명령어
- RETURN: CALL을 호출할 때 저장했던 주소로 돌아가라.
- 입출력 제어
- READ(INPUT): 특정 입출력 장치로부터 데이터를 읽어라
- WRITE(OUTPUT): 특정 입출력 장치로 데이터를 써라
- START IO: 입출력 장치를 시작하라
- TEST IO: 입출력 장치의 상태를 확인하라
주소 지정 방식
왜 오퍼랜드 필드에 굳이 위치, 메모리나 레지스터의 주소를 담는 걸까? 그냥 오퍼랜드필드에 연산에 사용될 데이터를 담으면 안 되나?
명령어 길이 때문이다. 즉, 명령어에서 표현할 수 있는 데이터 크기가 제한되어 있기 때문이다.- 명령어의 크기가 16비트이고 그중 연산 코드 필드가 4비트라고 가정해 보자.
- 2-주소 명령어이기 때문에 오퍼랜드가 2개이며, 각 오퍼랜드 필드당 6비트를 가진다.
- 즉, 하나의 오퍼랜드 필드로 표현할 수 있는 정보의 가짓수는 26개 밖에 없다.
만약 여기서 오퍼랜드 개수가 늘어난다면 어떻게 될까?
- 명령어의 크기가 16비트이고 그중 연산 코드 필드가 4비트라고 가정해 보자.
- 3-주소 명령어이기 때문에 오퍼랜드가 3개이며, 각 오퍼랜드 필드당 4비트를 가진다.
- 즉, 하나의 오퍼랜드 필드로 표현할 수 있는 정보의 가짓수는 24, 16개 밖에 없다.
하지만 오퍼랜드 필드 안에 위치, 메모리나 레지스터의 주소를 담을 경우 표현할 수 있는 데이터의 크기는 하나의 메모리 주소에 저장할 수 있는 공간만큼 커지게 된다.
- 한 주소에 16비트를 저장할 수 있는 메모리가 있다고 가정해 보자.
- 표현할 수 있는 정보의 가짓수는 216으로 엄청 커지게 된다.
- 메모리 주소가 아닌 레지스터 이름을 명시할 때도 마찬가지
명령어 주소 지정 방식
- 유효 주소(effective address)
- 연산의 대상이 되는 데이터가 저장된 위치
- 예시) 위 그림에서의 유효 주소는 10번지이다.
- 명령어 주소 지정 방식(addressing modes)
- 연산에 사용할 데이터가 저장된 위치를 찾는 방법
- 유효 주소를 찾는 방법
- 다양한 명령어 주소 지정 방식들이 있다.
즉시 주소 지정 방식(immediate addressing mode)
- 연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식
- 가장 간단한 형태의 주소 지정 방식이다.
- 연산에 사용할 데이터의 크기가 작아진다는 단점이 있다.
- 하지만, 연산에 사용할 데이터를 메모리나 레지스터로부터 찾는 과정이 없기 때문에 빠르다.
직접 주소 지정 방식(direct addressing mode)
- 오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식 (유효 주소로 갔더니 데이터가 있더라~)
- 유효 주소를 표현할 수 있는 크기가 연산 코드만큼 줄어든다.
간접 주소 지정 방식(indirect addressing mode)
- 직접 주소 지정 방식을 극복하기 위한 방식 중 하나이다.
- 오퍼랜드 필드에 유효 주소의 주소를 명시하는 방식
- 직접 주소 지정 방식보다 표현할 수 있는 유효 주소의 범위가 더 넓어졌다.
- 하지만 2번의 메모리 접근이 필요하기 때문에 앞의 주소 지정 방식들보다 일반적으로 느린 방식이다.
참고: CPU가 메모리에 접근하는 시간은 굉장히 속도가 느리다.
레지스터 주소 지정 방식(register addressing mode)
- 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방식
- CPU가 메모리에 접근하는 속도보다 레지스터에 접근하는 것이 빠르다. (메모리는 CPU 밖, 레지스터는 CPU 안에 있다.)
- 직접 주소 지정 방식과 유사하지만, 보다 빠르게 데이터에 접근할 수 있다.
- 하지만, 표현할 수 있는 레지스터의 크기에 제한이 생길 수 있다.
레지스터 간접 주소 지정 방식(register indirect addressing mode)
- 연산에 사용할 데이터를 메모리에 저장하고, 그 유효 주소를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방식
- 간접 주소 지정 방식과 비슷하지만, 메모리에 접근하는 횟수가 한 번으로 줄어든다는 장점이 있다.
- 즉, 간접 주소 지정 방식보다 빠르다.
'Computer Science > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] 메모리와 캐시 메모리 (1) | 2023.04.14 |
---|---|
[컴퓨터 구조] CPU의 성능 향상 기법 (0) | 2023.04.12 |
[컴퓨터 구조] CPU의 작동 원리 (0) | 2023.04.06 |
[컴퓨터 구조] 0과 1로 데이터를 표현하는 방법 (0) | 2023.03.31 |
[컴퓨터 구조] 컴퓨터 구조의 큰 그림 (0) | 2023.03.30 |