1. 소스 코드와 명령어
📍고급 언어와 저급 언어
고급 언어(일반적인 프로그래밍 언어)로 작성된 소스 코드가 실행되려면 반드시 저급 언어(컴퓨터만 이해할 수 있는 명령어)로 변환되어야 한다
저급언어 종류
- 기계어
- 어셈블리어
기계어
- 0, 1(이진수)로 이루어진 명령어 모음
- 가독성을 위해 십육진수로 표현하기도 함
어셈블리어
- 기계어를 사람이 어느정도 이해할 수 있게 번역
- 하드웨어와 밀접한 분야에서는 실제로 사용 (임베디드, 보안 등)
- 예시
📍컴파일 언어와 인터프리터 언어
고급 언어가 저급 언어로 변환되는 방식에 따라 언어를 2가지로 나눌 수 있음
- 컴파일 언어
- 인터프리터 언어
컴파일 언어
- 컴파일러에 의해 소스코드 전체가 저급 언어(결과물 - 목적 코드)로 변환되어 실행됨
- 소스 코드에 오류가 있다면 컴파일 실패
- C언어
인터프리터 언어
- 인터프리터에 의해 소스 코드가 한 줄씩 변환되며 실행됨
- 소스 코드 N번째 줄에서 오류가 발생했다면, N-1번째 줄까지는 정상적으로 수행됨
- 해석, 실행이 한 줄마다 이뤄지므로 컴파일 언어에 비해 느리다
- Python
컴파일 언어와 인터프리터 언어간 경계가 모호하다
- Python에서 아예 컴파일이 없지는 않다
- Java의 경우 컴파일과 인터프리트가 동시에 수행됨
목적 파일 vs 실행 파일
- 목적 파일: 목적 코드로 이루어진 파일
- 실행 파일: 실행 코드로 이루어진 파일 (예-윈도우의 .exe 파일)
- 링킹: 목적 코드의 별개 파일들 간의 참조 관계를 확인해서 하나의 실행 파일을 만드는 과정
2. 명령어의 구조
📍연산 코드와 오퍼랜드
명령어의 구성
- 연산 코드: 명령어가 수행할 연산(연산자)
- 오퍼랜드(operand): 연산에 사용될 데이터 및 데이터가 저장된 위치(피연산자)
- 기계어와 어셈블리어도 명령어이기 때문에 연산 코드와 오퍼랜드로 구성됨
오퍼랜드
- 숫자, 문자 등의 데이터
- 데이터의 메모리 or 레지스터 이름
- 대개 데이터보다 데이터의 메모리 주소나 레지스터 이름이 저장되기 때문에 주소 필드라고도 함
- 명령어에 오퍼랜드가 없을 수도 있고 (0-주소 명령어)
- 여러 개가 있을 수도 있음(1-주소 명령어, ... , 3-주소 명령어)
연산 코드
- 크게 4가지 유형 존재
1) 데이터 전송
- MOVE: 데이터를 옮겨라
- STORE: 메모리에 저장하라
- LOAD(FETCH): 메모리에서 CPU로 데이터를 가져와라
- PUSH: 스택에 데이터 저장하라
- POP: 스택의 최상단 데이터를 가져와라
2) 산술/논리 연산
- ADD, SUBSTRACT, MULTIPLY, DIVIDE: 사칙연산
- INCREMENT, DECREMENT: 오퍼랜드에 +1, -1
- AND, OR, NOT: 논리연산
- COMPARE: 두 개의 숫자 또는 T/F 비교
3) 제어 흐름 변경
- JUMP: 특정 주소로 실행 순서를 옮겨라
- CONDITIONAL JUMP: 조건에 부합할 때 특정 주소로 실행 순서를 옮겨라
- HALT: 프로그램의 실행을 멈춰라
- CALL: 되돌아올 주소를 저장한 채 특정 주소로 실행 순서를 옮겨라
- RETURN: CALL을 호출할 때 저장했던 주소로 돌아가라
4) 입출력 제어
- READ(INPUT): 특정 입출력 장치로부터 데이터를 읽어라
- WRITE(OUTPUT): 특정 입출력 장치로 데이터를 써라
- START IO: 입출력 장치를 시작하라
- TEST IO: 입출력 장치의 상태를 확인하라
📍주소 지정 방식
오퍼랜드에 데이터 자체를 저장하지 않는 이유
- 데이터를 담게 되면 데이터를 표현하는데 많은 공간이 필요하다
- 그런데 메모리 주소를 담으면, 오퍼랜드에 허용된 크기보다 더 큰 데이터도 저장할 수 있다
- 예) 한 주소에 16비트 저장 가능한 메모리가 있을 때,
메모리 안에 데이터를 저장하고, 오퍼랜드 필드 안에 해당 메모리 주소를 명시한다면 표현할 수 있는 정보의 가짓수가 2^16이 됨
유효 주소(effective address)
- 연산의 대상이 되는 데이터가 저장된 위치
- 메모리 주소 또는 레지스터 이름이 될 수 있음
주소 지정 방식(addressing mode)
- 오퍼랜드 필드에 데이터 주소가 저장됐을 때, 이 주소(유효 주소)를 찾는 방법
- 5가지 방식이 존재
1) 즉시 주소 지정 방식
- 오퍼랜드 필드에 데이터를 직접 명시
- 표현할 수 있는 데이터의 크기가 작아지지만, 속도 가장 빠름
2) 직접 주소 지정 방식
- 오퍼랜드 필드에 유효 주소를 직접 명시
- (전체 메모리 - 연산 코드)의 비트 수 만큼 사용 불가
3) 간접 주소 지정 방식
- 유효 주소의 메모리 주소를 오퍼랜드 필드에 명시
- 표현할 수 있는 범위가 가장 넓지만, 메모리에 2번 접근 필요해서 속도 가장 느림
4) 레지스터 주소 지정 방식
- 레지스터 이름을 오퍼랜드 필드에 직접 명시
- CPU 외부의 메모리보다 CPU 내부의 레지스터에 접근이 더 빠름
5) 레지스터 간접 주소 지정 방식
- 데이터를 메모리에 저장하고, 그 유효 주소를 저장한 레지스터 이름을 오퍼랜드 필드에 명시
- 유효 주소를 찾을 때만 메모리에 접근하므로 (1번) 속도가 빠르면서도 표현할 수 있는 가짓수 큼