문타쿠, 공부하다.
[혼공컴운] Chapter 03. 명령어 본문
03-1. 소스 코드와 명령어
컴퓨터는 명령어를 처리하는 기계이다.
명령어는 컴퓨터를 실질적으로 작동시키는 매우 중요한 정보이다.
그렇다면 우리가 프로그래밍 언어로 만든 소스 코드는 무엇일까?
-> 모든 소스 코드는 컴퓨터 내부에서 명령어로 변환된다.
"고급 언어와 저급 언어"
컴퓨터는 프로그래밍 언어를 이해할 수 있을까? -> NO
우리가 프로그램을 만들 때 사용하는 프로그래밍 언어는 컴퓨터가 이해하는 언어가 아닌 사람이 이해하고 작성하기 쉽게 만들어진 언어이다. 그리고 컴퓨터는 이 언어를 이해하지 못한다.
고급 언어
- 사람을 위한 언어
- 대부분의 프로그래밍 언어가 고급 언어에 속한다.
- 사람이 읽고 쓰기 편한 것은 물론이고, 더 나은 가독성, 변수나 함수 같은 편리한 문법을 제공하기 때문에 어떤 복잡한 프로그램도 구현할 수 있다.
저급 언어
- 컴퓨터가 직접 이해하고 실행할 수 있는 언어
- 저급 언어는 명령어로 이루어져 있다.
- 컴퓨터가 이해하고 실행할 수 있는 언어는 오직 저급 언어뿐이다.
고급 언어로 작성된 소스 코드가 실행되려면 반드시 저급 언어, 즉 명령어로 변환되어야 한다.
<저급 언어의 두 가지 종류>
- 기계어
- 0과 1의 명령어 비트로 이루어진 언어 = 0과 1로 이루어진 명령어 모음
- 컴퓨터는 0과 1로 이루어진 기계어를 이해하고 실행
- 가독성을 위해 16진수로 표현하기도 함
- 어셈블리어
- 기계어는 오로지 컴퓨터만을 위해 만들어진 언어이기 때문에 사람이 읽으면 그 의미를 이해하기 어렵다. 그래서 등장한 저급 언어가 어셈블리어.
- 0과 1로 표현된 명령어(기계어)를 읽기 편현 형태로 번역한 저급 언어
<왜 저급 언어를 알아야 할까?>
- 어떤 개발자가 되길 희망하는지에 따라 저급 언어의 중요성은 달라진다.
- 어셈블리어를 읽으면 컴퓨터가 프로그램을 어떤 과정으로 실행하는지, 즉 프로그램이 어떤 절차로 작동하는지를 가장 근본적인 단계에서부터 하나하나 추적하고 관찰할 수 있다.
"컴파일 언어와 인터프리터 언어"
개발자들이 고급 언어로 작성한 소스 코드는 저급 언어로 변환되어 실행된다고 했는데, 고급 언어는 어떻게 저급 언어로 변환되는걸까?
대표적으로 1) 컴파일 방식과 2)인터프리트 방식이 있다.
컴파일 방식으로 작동하는 프로그래밍 언어를 컴파일 언어, 인터프리트 방식으로 작동하는 프로그래밍 언어를 인터프리터 언어라고 한다.
컴파일 언어
- 컴파일러에 의해 소스 코드 전체가 저급 언어로 변환되어 실행되는 고급 언어(ex. C언어)
- 컴파일: 컴파일 언어로 작성된 소스 코드 전체가 저급 언어로 변환되는 과정
- 컴파일러: 컴파일을 수행해 주는 도구
- 컴파일이 성공적으로 수행되면 소스 코드는 컴퓨터가 이해할 수 있는 저급 언어로 변환되고, 컴파일러를 통해 저급 언어로 변환된 코드를 목적 코드라고 한다.
인터프리터 언어
- 인터프리터에 의해 소스 코드가 한 줄씩 실행되는 고급 언어(ex. 파이썬)
- 인터프리터: 소스 코드를 한 줄씩 차례로 저급 언어로 변환하여 실행해 주는 도구
컴파일러는 개발자가 작성한 소스 코드 전체를 보면서 문법적인 오류는 없는지, 실행 가능한 코드인지 등을 따지며 소스 코드를 처음부터 끝까지 저급 언어로 컴파일한다. 이때 코드 내에 오류가 있다면 해당 코드는 컴파일에 실패한다.
반면에 인터프리터는 소스 코드를 한 줄씩 실행하기 때문에 소스 코드 n번째 줄에 문법 오류가 있더라도 n-1번째 줄까지는 올바르게 수행된다.
다만, 인터프리터 언어는 소스 코드 마지막에 이를 때까지 한 줄 한 줄씩 저급 언어로 해석하며 실행하기 때문에 일반적으로 컴파일 언어보다 느리다.
좀 더 알아보기
"목적 파일 VS 실행 파일"
목적 코드로 이루어진 파일을 목적 파일, 실행 코드로 이루어진 파일을 실행 파일이라고 한다.
윈도우의 .exe 확장자를 가진 파일이 대표적인 실행 파일이다.
목적 코드는 컴퓨터가 이해하는 저급 언어라고 했는데, 목적 파일과 실행 파일은 같은 의미인가? -> NO
목적 코드가 실행 파일이 되기 위해서는 링킹이라는 작업을 거쳐야 한다.
03-2. 명령어의 구조
"연산 코드와 오퍼랜드"
명령어
- 명령어는 '무엇을 대상으로', '어떤 작동을 수행하라'는 구조로 되어 있다.
- 즉, 명령어는 '연산 코드'와 '오퍼랜드'로 구성되어 있다.
- 연산 코드(=연산자): 어떤 작동을 수행하라 = 명령어가 수행 할 연산
- 오퍼랜드(=피연산자): 무엇을 대상으로 = 연산에 사용할 데이터 or 연산에 사용할 데이터가 저장된 위치
- 연산 코드가 담기는 영역을 연산 코드 필드, 오퍼랜드가 담기는 영역을 오퍼랜드 필드(=주소 필드) 라고 한다.
- 기계어와 어셈블리어 또한 명령어이기 때문에 연산 코드와 오퍼랜드로 구성되어 있다.
연산 코드
- 명령어가 수행 할 연산
- 명령어의 종류와 생김새는 CPU마다 다르기 때문에, 연산 코드의 종류와 생김새 또한 CPU마다 다르다.
오퍼랜드
- 연산에 사용할 데이터 or 연산에 사용할 데이터가 저장된 위치
- 오퍼랜드 필드에는 숫자와 문자 등을 나타내는 데이터 또는 메모리나 레지스터 주소가 올 수 있다.
- 다만 오퍼랜드 필드에는 숫자나 문자와 같이 연산에 사용할 데이터를 직접 명시하기보다는, 연산에 사용할 데이터가 저장된 위치, 즉 메모리 주소나 레지스터 이름이 담긴다.
- 그래서 오퍼랜드 필드를 주소 필드라고 부르기도 함
- 오퍼랜드는 명령어 안에 하나도 없을 수도 있고, 한 개만 있을 수도 있고, 두 개 또는 세 개 등 여러 개가 있을 수도 있다.
- 오퍼랜드가 하나도 없는 명령어를 0-주소 명령어, 오퍼랜드가 하나인 명령어를 1-주소 명령어, 두 개인 명령어를 2-주소 명령어, 세 개인 명령어를 3-주소 명령어라고 한다.
"주소 지정 방식"
- 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때, 연산에 사용할 데이터의 위치를 찾는 방법
- =유효 주소를 찾는 방법
- 유효 주소: 연산의 대상이 되는 데이터가 저장된 위치
왜 오퍼랜드 필드에 메모리나 레지스터의 주소를 담는 것인가?
그냥 <연산 코드, 연산 코드에 사용 될 데이터> 형식으로 명령어를 구성하면 되는 것 아닌가?
✔️그렇게 구성해도 되긴 한데, 명령어의 길이 때문에 주소를 사용하는 것!
하나의 명령어는 n비트로 구성되어 있고, 그 중 연산 코드가 m비트라고 가정한다면,
오퍼랜드 필드에 가장 많은 공간을 할당할 수 있는 1-주소 명령어라 할지라도 오퍼랜드 필드의 길이는 n-m비트가 된다.
2-주소 명령어, 3-주소 명령어라면 오퍼랜드 필드의 길이는 더욱 작아지게 되고, 표현할 수 있는 정보의 가짓수도 줄어들게 된다.
✔️이때 만약 오퍼랜드 필드 안에 메모리 주소가 담긴다면, 표현할 수 있는 데이터의 크기는 하나의 메모리 주소에 저장할 수 있는 공간만큼 커지게 된다.
✔️오퍼랜드 필드에 메모리 주소가 아닌 레지스터 이름을 명시할 때도 마찬가지로, 표현할 수 있는 정보의 가짓수는 해당 레지스터가 저장할 수 있는 공간만큼 커진다.
1) 즉시 주소 지정 방식
- 연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식
- 표현할 수 있는 데이터의 크기가 작아진다는 단점이 있지만,
- 연산에 사용할 데이터를 메모리나 레지스터로부터 찾는 과정이 없어 빠르다.
2) 직접 주소 지정 방식
- 오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식
- 오퍼랜드 필드에서 표현할 수 있는 데이터의 크기는 즉시 주소 지정 방식보다 커졌지만, 여전히 유효 주소를 표현할 수 있는 범위가 연산 코드의 비트 수만큼 줄어들었다.
3) 간접 주소 지정 방식
- 유효 주소의 주소를 오퍼랜드 필드에 명시
- 직접 주소 지정 방식보다 표현할 수 있는 유효 주소의 범위가 더 넓어졌지만,
- 두 번의 메모리 접근이 필요하기 때문에 느리다.
4) 레지스터 주소 지정 방식
- 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방법
- CPU 외부에 있는 메모리에 접급하는 것보다 CPU 내부에 있는 레지스터에 접근하는 것이 더 빠르기 때문에
- 레지스터 주소 지정 방식은 직접 주소 지정 방식보다 빠르게 데이터에 접근할 수 있다.
- 직접 주소 지정 방식과 비슷하게, 표현할 수 있는 레지스터 크기에 제한이 생길 수 있다,
5) 레지스터 간접 주소 지정 방식
- 연산에 사용할 데이터를 메모리에 저장하고, 그 주소(유효 주소)를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법
- 간접 주소 지정 방식에 비해 메모리에 접근하는 횟수가 한 번으로 줄어든다는 차이점이자 장점이 있다.
- CPU 외부에 있는 메모리에 접급하는 것보다 CPU 내부에 있는 레지스터에 접근하는 것이 더 빠르기 때문에
- 레지스터 간접 주소 지정 방식은 간접 주소 지정 방식보다 빠르다.
좀 더 알아보기
"스택과 큐"
스택
- 나중에 저장한 데이터를 가장 먼저 빼내는 '후입선출' 데이터 관리 방식
- LIFO 자료 구조
- 스택에 새로운 데이터를 저장하는 명령어 PUSH
- 스택에 저장된 데이터를 꺼내는 명령어 POP
큐
- 가장 먼저 저장된 데이터부터 빼내는 '선입선출' 데이터 관리 방식
- FIFO 자료 구조
'컴퓨터 구조 > 혼자 공부하는 컴퓨터 구조+ 운영체제' 카테고리의 다른 글
[혼공컴운] Chapter 04. CPU의 작동 원리 (0) | 2023.08.24 |
---|---|
[혼공컴운] Chapter 02. 데이터 (0) | 2023.08.10 |
[혼공컴운] Chapter 01. 컴퓨터 구조 시작하기 (0) | 2023.08.03 |
[혼자 공부하는 컴퓨터 구조+운영체제] 2023.08.03 ~ 책 실종... (0) | 2023.08.03 |