<본 카테고리는 "혼자 공부하는 컴퓨터구조 + 운영체제" 책과 강의를 기반으로 작성하였습니다>
명령어
저급 언어와 고급 언어
우리가 프로그램을 만들 때 사용하는 프로그래밍 언어는 컴퓨터가 이해하는 언어와 인간이 이해하는 언어로 나뉜다. 여기서 사람을 위한 언어는 고급(high-level) 언어라고 하고, 컴퓨터를 위한 언어는 저급(low-level) 언어라고 한다. 즉, 고급 언어로 작성된 소스 코드가 실행되려면 반드시 저급 언어, 즉 명령어로 변환되어야 한다. 먼저 명령어로 이루어진 저급 언어에 대해 다뤄보자.
저급 언어에는 기계어와 어셈블리어 두 가지 종류가 있다. 기계(machine)어는 0과 1의 명령어 비트로 이루어진 명령어 모음이다. 기계어는 이진수로 이루어져 있지만, 가독성을 위해 아래와 같이 16진수로 표현하기도 한다.
하지만 오로지 컴퓨터만을 위해 만들어진 기계어는 사람이 읽으면 그 의미를 이해하기 힘들다. 그래서 등장한 저급 언어와 고급 언어의 중간 단계인 어셈블리어가 등장하였다. 어셈블리어(assembly)는 0과 1로 표현된 기계어를 읽기 편한 형태로 번역한 언어다.
위 어셈블리어 한 줄 한 줄이 무엇을 의미하는지 몰라도 된다. 다만, 위 어셈블리어 한 줄이 명령어라는 사실만 기억해 두면 된다. 이러한 어셈블리어는 개발자들에게 '작성의 대상'일 뿐만 아니라 '관찰의 대상' 이기도 하다. 즉, 프로그램이 어떤 절차로 작동하는지를 갖아 근본적인 단계에서부터 하나하나 추적하고 관찰할 수 있다.
컴파일 언어와 인터프리트 언어
프로그래밍 언어는 일반적으로 고급 언어와 저급 언어로 분류된다. 사람이 이해하기 쉽게 작성된 고급 언어는 컴퓨터가 이해할 수 있는 저급 언어로 변환되어야 한다. 이 과정에서 고급 언어가 저급 언어로 바뀌는 방식에는 주로 컴파일 언어 방식과 인터프리터 언어 방식, 두 가지 방법이 있다.
먼저 컴파일 언어 방식에 대해 알아보자. 컴파일 언어는 소스 코드 전체가 컴파일러에 의해 저급 언어로 변환되는 프로그래밍 언어를 지칭한다. 여기서 컴파일(compile)은 코드 전체를 저급 언어로 변환하는 과정을 의미하며, 컴파일러(compiler)는 이 과정을 수행하는 도구를 가리킨다. 컴파일러는 개발자가 작성한 소스 코드를 전반적으로 검토하여 문법적 오류가 있는지, 실행 가능한 코드인지 등을 분석하고, 소스 코드를 처음부터 끝까지 저급 언어로 컴파일한다. 이렇게 컴파일러를 통해 저급 언어로 변환된 코드는 목적(object) 코드라고 부른다. 대표적인 컴파일 언어로는 C가 있다.
반면 인터프리터 방식은 인터프리터에 의해 소스 코드가 한 줄씩 실행되는 프로그래밍 언어다. 여기서 인터프리터(interpreter)란 소스 코드를 한 줄씩 저급 언어로 변환하여 실행해 주는 도구를 의미한다. 이 방식은 컴퓨터와 대화하듯 소스 코드를 한 줄씩 실행하기 때문에 소스 코드 전체를 저급 언어로 변환하는 시간을 기다릴 필요가 없다. 또한 N번째 줄에 문법적 오류가 있더라도 그 이전 줄들은 올바르게 수행된다. 하지만 컴파일 언어보다 처리 속도가 느리다는 단점이 있다. 대표적인 인터프리터 언어로는 파이썬이 있다.
여기서 주의해야 할 점은, 컴파일 언어와 인터프리터 언어는 양분되는 개념이 아니라는 것이다. C와 C++처럼 명확히 구분되는 언어도 있지만, 현대의 많은 프로그래밍 언어는 컴파일 언어와 인터프리터 언어 사이의 경계가 불분명하다. 따라서, 하나의 프로그래밍 언어가 반드시 이 두 가지 중 하나만을 따르는 것이 아니라는 점에 유념하자. 즉, 고급 언어가 저급 언어로 변환되는 대표적인 방법에는 컴파일 방식과 인터프리트 방식이 있다고 이해하는 것이 바람직하다.
명령어의 구조
앞서 우리는 기계어와 어셈블리어의 형태로 명령어를 접했다. 이번엔 명령어를 자세히 들여다보며 그 구조를 이루는 연산 코드, 오퍼랜드, 주소 지정 방식이라는 개념에 대해 학습해 보자.
연산 코드와 오퍼랜드
명령어는 '무엇을 대상으로, 어떤 작동을 수행하라'는 구조로 되어 있다. 즉, 수행할 연산인 연산 코드(operation code)와 연산에 사용할 데이터 또는 연산에 사용할 데이터가 저장된 위치인 오퍼랜드(operand)로 구성되어 있다. 여기서 오퍼랜드는 명령어 안에 0개 이상 존재한다. 이를 간단히 그림으로 표현하면 다음과 같다.
오퍼랜드는 주로 데이터의 위치, 즉 메모리나 레지스터의 주소를 담는다. 이런 선택은 주로 효율성과 메모리 관리에 기인한다. 컴퓨터 메모리는 한정된 자원으로, 모든 데이터를 직접 저장하게 되면 메모리 소비가 빠르고 비효율적일 수 있다. 반면, 데이터의 위치를 저장하면 일정한 크기의 메모리만 사용하여 효율적으로 관리할 수 있다. 또한, 연산 시 실제 데이터를 사용하면 매번 데이터의 복사나 이동이 필요할 수 있지만, 위치를 활용하면 동적으로 데이터를 변경하거나 업데이트할 수 있어 연산 과정이 더욱 효율적이다. 이런 이유들로, 오퍼랜드 필드에는 대부분의 경우 데이터가 저장된 위치가 주로 담기게 된다.
예를 들어 한 주소에 16비트를 저장할 수 있는 메모리가 있다고 가정해 보자. 연산 코드가 4 비트라고 가정하면, 오퍼랜드 필드는 필드당 4비트 정도밖에 남지 않는다. 따라서 하나의 오퍼랜드 필드로 표현할 수 있는 정보의 가짓수는 2^4개 밖에 없다. 하지만 오퍼랜드 필드 안에 메모리 주소가 담긴다면, 표현할 수 있는 데이터의 크기는 하나의 메모리 주소에 저장할 수 있는 공간만큼 커진다.
연산 코드는 종류가 매우 많고 CPU마다 다르지만, 가장 기본적인 연산 코드 유형은 크게 데이터 전송, 산술/논리 연산, 제어 흐름 변경, 입출력 제어 4가지로 나뉜다는 점만 기억해 두면 된다.
주소 지정 방식
앞서 오퍼랜드 필드에 메모리나 레지스터의 주소를 담는 이유를 밝히며, 이를 통해 효율적인 메모리 관리를 가능하게 한다는 점을 언급하였다. 그렇다면 연산 대상의 위치를 어떻게 파악할까? 이것은 바로 주소 지정 방식(addressing mode)에 따라 달라진다. 이는 연산에 사용되는 데이터가 위치한 유효 주소를 추출하는 방법을 설명한다. 이제 대표적인 주소 지정 방식 다섯 가지를 각각 살펴보자.
1. 즉시(immediate) 주소 지정 방식
- 연산에 필요한 데이터를 직접 명시하여 속도가 빠름
- 오퍼랜드 필드의 크기에 제한이 있어, 사용 가능한 데이터의 크기가 제한됨
- 유효 주소: 오퍼랜드 값이 저장된 기억장치 주소
2. 직접(direct) 주소 지정 방식
- 오퍼랜드 필드에 유효 주소를 직접 명시하여 데이터에 접근 가능. 주소 표현의 범위가 즉시 주소 지정 방식보다 넓어짐
- 연산 코드의 비트 수에 따라 주소 표현 범위에 제한이 생길 수 있음
- 유효 주소: 주소 필드 값
3. 간접(indirect) 주소 지정 방식
- 주소를 참조하여 유효 주소를 찾을 수 있으므로 주소 표현 범위가 넓어짐
- 유효 주소를 찾기 위해 두 번의 메모리 접근이 필요하여 속도가 느려짐
- 유효 주소: 주소 필드 값이 가리키는 기억장치 값
4. 레지스터 주소 지정 방식
- CPU 내부에 있는 레지스터를 활용하여 데이터에 접근하기 때문에 빠른 속도를 제공
- 사용 가능한 레지스터의 크기에 따라 제약이 발생
- 유효 주소: 없음
- 여기서 주목해야 할 것은 CPU가 메모리에 접근하는 것은 일반적으로 시간 소모가 크며, 이에 비해 CPU 내부에 있는 레지스터에 접근하는 것은 빠르다는 것이다.
5. 레지스터 간접 주소 지정 방식
- 메모리에 접근하는 횟수가 한 번으로 줄어들어 간접 주소 지정 방식보다 빠른 처리가 가능
- 데이터를 메모리에 저장하고 주소를 저장한 레지스터를 참조해야 하므로 추가적인 레지스터 사용이 필요
- 유효 주소: 레지스터에 있는 주소
각 주소 지정 방식은 장단점을 갖고 있으며, 컴퓨터 아키텍처의 목적과 요구사항에 맞게 적절한 방식을 선택하여 사용해야 한다. 일반적으로 빠르고 메모리 효율성이 높은 순서로 나열하면 '레지스터 간접 > 레지스터 > 간접 > 직접 > 즉시 주소' 순이다. 물론 컴퓨터 아키텍처와 구현에 따라 결과가 달라질 수 있다.
요약
고급 언어
1. 정의: 사람이 이해하는 언어
2. 변환
a. 컴파일 언어: 컴파일러에 의해 소스 코드 전체가 저급 언어로 변환하여 목적 코드 생성
b. 인터프리터 언어: 인터프리터에 의해 소스 코드 한 줄씩 저급 언어로 변환
저급 언어
1. 정의: 컴퓨터가 이해하는 언어
2. 종류
a. 기계어: 0과 1로 이루어진 명령어 모음
b. 어셈블리어: 기계어를 읽기 편한 형태로 번역한 언어
명령어
1. 구조: 연산 코드 + 오퍼랜드
a. 연산 코드: 데이터 전송, 산술/논리 연산, 제어 흐름 변경, 입출력 제어
b. 오퍼랜드: 연산에 사용할 데이터 또는 데이터가 저장된 위치
2. 주소 지정 방식
- 직접, 즉시, 간접, 레지스터, 레지스터 간접
3. 일반적으로 레지스터 접근 속도가 메모리 접근 속도보다 빠름
'CS > 컴퓨터구조' 카테고리의 다른 글
[컴퓨터구조] CPU의 작동 원리 (2) (0) | 2023.06.11 |
---|---|
[컴퓨터구조] CPU의 작동 원리 (1) (0) | 2023.06.09 |
[컴퓨터구조] 데이터의 이해 (2) (0) | 2023.06.02 |
[컴퓨터구조] 데이터의 이해(1) (0) | 2023.06.01 |
[컴퓨터구조] 개요 (0) | 2023.05.26 |