Chap3 명령어

생성 일시: 2023년 8월 15일 오후 5:25

  • 소스 코드와 명령어
  • 명령어의 구조

03 명령어

03-1 소스코드와 명령어

프로그래밍 언어가 어떻게 명령어가 되어 실행되는가?

고급 언어와 저급 언어

컴퓨터는 C, C++, Python, Java 같은 프로그래밍 언어를 이해할 수 있는가? 그렇지 않다.

우리가 사용하는 프로그래밍 언어는 컴퓨터가 이해하는 언어가 아니라, 사람이 이해하고 작성하기 쉽게 만들어진 언어이다.

이런 프로그래밍 언어들을 고급 언어(high-level programming language)라고 한다.

컴퓨터가 직접 이해하고 실행할 수 있는 언어를 저급 언어(low-level programming language)라고 한다. 고급 언어로 작성된 프로그래밍 언어가 실행되려면 반드시 저급 언어(명령어)로 변환되어야 한다.

저급 언어의 두 가지 종류: 기계어와 어셈블리어

기계어 machine code

0과 1의 명령어 비트로 이루어진 언어로, 이진수로 표현하기도, 십육진수로 표현하기도 함

컴퓨터만을 위해 만들어진 언어기 때문에 사람이 이해하기 어렵다.

어셈블리어 assembly language

0과 1로 표현된 명령어를 읽기 편한 형태로 번역한 언어

어셈블리어만으로 복잡한 프로그램을 만들기는 쉽지 않다. 따라서 가독성이 좋고 편리한 문법을 제공하는 고급 언어로 프로그램을 구현한다.

하드웨어와 관련된 개발자가 된다면, 어셈블리어를 많이 이용한다. 직접 작성할 뿐만 아니라, 관찰함으로써 컴퓨터가 프로그램을 실행하는 과정을 가장 기초부터 추적하고 관찰할 수 있기 때문이다.

컴파일 언어와 인터프리터 언어

고급 언어로 작성한 코드는 저급 언어로 변환되는데, 이 변환 과정은 어떻게 이루어질까?

고급 언어 → 저급 언어: 두 가지 방식

  1. 컴파일 언어: 컴파일 방식으로 작동
  2. 인터프리터 언어: 인터프리트 방식으로 작동

컴파일 언어

컴파일러에 의해 소스 코드 전체가 저급 언어로 변환되어 실행됨 (예: C)

컴파일러는 개발자가 작성한 소스 코드 전체를 훑어보며 저급 언어로 컴파일한다. 이때 오류가 하나라도 발생하면 컴파일에 실패한다.

컴파일러를 통해 저급 언어로 변환된 언어를 목적 코드 (object code) 라고 한다.

소스 코드 → 컴파일러 → 목적 코드

인터프리터 언어

인터프리터에 의해 소스 코드가 한 줄씩 실행됨 (예: Python)

소스 코드를 한 줄씩 차례로 실행하기 때문에 소스 코드 전체를 저급 언어로 변환하는 시간을 기다릴 필요 없음. 중간에 오류가 발생하더라도 그 직전까지는 올바르게 수행됨.

컴파일 언어가 인터프리터 언어보다 느리다고 생각할 수 있지만, 일반적으로 인터프리터 언어는 컴파일 언어보다 느리다. 컴파일의 결과물을 통해 나온 목적 언어는 컴퓨터가 이해할 수 있는 저급 언어이지만, 인터프리터 언어는 소스 코드 마지막까지 한 줄씩 저급 언어로 해석하며 실행해야 하기 때문이다.

!!모든 언어가 컴파일 방식/인터프리터 방식 둘 중 하나로 나눠지는 것은 아니다.

목적 파일 vs 실행 파일


목적 코드로 이루어진 파일을 목적 파일이라 하고, 실행 코드로 이루어진 파일을 실행 파일(.exe)이라고 한다.

목적 파일 == 실행 파일 ?

목적 코드가 실행 파일이 되기 위해서는 링킹이라는 작업을 거쳐야 함

링킹: 목적 파일에 없는 외부 기능들까지 연결하는 작업

03-2 명령어의 구조

  • 연산 코드
  • 오퍼랜드
  • 주소 지정 방식

연산 코드와 오퍼랜드

컴퓨터 명령어 구조 - “무엇을 대상으로, 어떤 작동을 수행하라”

연산 코드오퍼랜드

명령어 = 연산 코드 + 오퍼랜드

연산 코드 명령어가 수행할 연산 (연산자)

오퍼랜드 연산에 사용할 데이터/연산에 사용할 데이터가 저장된 위치 (피연산자)

연산 코드가 담기는 영역을 연산 코드 필드, 오퍼랜드가 담기는 영역을 오퍼랜드 필드라고 함

기계어와 어셈블리어 모두 명령어이므로 연산코드 + 오퍼랜드로 구성되어 있다.

오퍼랜드

오퍼랜드 필드에는 숫자나 문자 등을 직접 나타내는 데이터 또는 메모리나 레지스터 주소가 모두 올 수 있지만, 일반적으로 연산에 사용할 데이터가 저장된 위치 (메모리 주소, 레지스터 이름) 가 담긴다.

따라서 오퍼랜드 필드를 주소 필드라고 부르기도 한다.

오퍼랜드 같은 경우 한 명령어 안에 하나도 없을 수 있고, 하나일 수도, 두 개일 수도… 여러 개일 수도 있음

오퍼랜드 개수에 따라

  • 0-주소 명령어
  • 1-주소 명령어
  • 2-주소 명령어
  • 3-주소 명령어

연산 코드

대표적인 연산 코드 유형

  1. 데이터 전송
  2. 산술/논리 연산
  3. 제어 흐름 변경
  4. 입출력 제어

명령어의 종류와 생김새는 CPU마다 다르다. 따라서 대표적인 연산 코드의 종류만!

데이터 전송

  • MOVE 데이터 옮기기
  • STORE 데이터를 메모리에 저장하기
  • LOAD (FETCH) 메모리에서 CPU로 데이터 가져오기
  • PUSH 스택에 데이터 저장하기
  • POP 스택의 최상단 데이터 가져오기

산술/논리 연산

  • ADD SUBSTRACT MULTIPLY DIVIDE 덧셈, 뺄셈, 곱셈, 나눗셈
  • INCREMENT DECREMENT 오퍼랜드에 1 더하기, 오퍼랜드에 1 빼기 (증감 연산자?)
  • AND OR NOT AND, OR, NOT 연산 수행
  • COMPARE 두 개의 숫자 또는 TRUE FALSE 비교

제어 흐름 변경

  • JUMP 특정 주소로 실행 순서 옮기기
  • CONDITIONAL JUMP 조건에 부합할 때 특정 주소로 실행 순서 옮기기
  • HALT 프로그램의 실행 멈추기
  • CALL 되돌아올 주소를 지정하고 특정 주소로 실행 순서 옮기기
  • RETURN CALL을 호출할 때 저장했던 주소로 돌아가기 → CALL, RETURN: 함수를 호출하고 리턴하는 명령어

입출력 제어

  • READ(INPUT) 특정 입출력 장치로부터 데이터 읽기
  • WRITE(OUTPUT) 특정 입출력 장치로부터 데이터 쓰기
  • START IO 입출력 장치 시작
  • TEST IO 입출력 장치의 상태 확인

주소 지정 방식

왜 오퍼랜드 필드에는 데이터를 직접 담지 않고 메모리나 레지스터의 주소를 담을까?

→ 명령어 길이는 한정적이기 때문이다.

만약 데이터를 직접 저장한다면, 데이터의 크기가 작으면 상관없지만 커지면 데이터 하나도 제대로 담지 못하는 상황이 됨. 하지만, 메모리의 주소값을 준다면 오퍼랜드 하나에는 메모리에 담을 수 있는 정보의 크기만큼 담을 수 있다. 레지스터의 경우도 마찬가지다.

명령어에서 연산의 대상이 되는 데이터가 저장된 위치를 유효 주소라고 한다. 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때, 연산에 사용할 데이터 위치를 찾는 방법을 주소 지정 방식 (addressing mode) 라고 한다.

즉시 주소 지정 방식 immediate addressing mode

| 연산 코드 | 연산에 사용할 데이터 | | ——— | ——————– |

연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식, 가장 간단한 형태!

표현할 수 있는 데이터의 크기가 작아지지만, 연산에 사용할 데이터를 메모리나 레지스터로부터 찾아내는 과정이 없기 때문에 다른 방식들보다 상대적으로 연산이 빠르다.

직접 주소 지정 방식 direct addressing mode

연산 코드유효 주소

오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식, 주소에 담을 수 있는 값만큼의 데이터를 다룰 수 있지만, 여전히 연산 코드로 인해 명령어의 공간이 줄었다.

간접 주소 지정 방식 indirect addressing mode

연산 코드유효 주소의 주소

유효 주소의 주소 → 유효 주소 → 연산에 사용할 데이터

표현할 수 있는 유효 주소의 범위가 넓어졌지만, 두 번의 메모리 접근이 필요하기 때문에 다른 방식들보다 느린 방식

레지스터 주소 지정 방식 register addressing mode

직접 주소 지정 방식과 비슷! 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시

CPU 외부 메모리에 접근하는 것보다 CPU 내부 레지스터에 접근하는 것이 빠르기 때문에 직접 주소 지정 방식보다 빠르게 데이터에 접근할 수 있다. 하지만 여기서도 표현할 수 있는 레지스터 크기에 제한이 생길 수 있다는 단점이 있음

레지스터 간접 주소 지정 방식 register indirect addressing mode

연산에 사용할 데이터를 메모리에 저장하고, 그 주소를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법

간접 주소 지정 방식과 비슷하지만, 메모리에 접근하는 횟수가 한 번으로 줄어 상대적으로 수행 시간이 짧음