mir.pe (일반/어두운 화면)
최근 수정 시각 : 2024-07-13 15:37:46

명령어 집합


명령어 집합
CISC AMD64 x86 · M68K · 68xx · Z80 · 8080 · MOS 65xx · VAX
RISC AArch64 ARM · RISC-V · MIPS · DEC Alpha · POWER PowerPC · CELL-BE
LoongArch · OpenRISC · PA-RISC · SPARC · Blackfin · SuperH · AVR32 AVR
VLIW
EPIC
E2K · IA-64 · Crusoe

1. 개요2. 상세
2.1. 명령어의 구성2.2. 명령어의 형식2.3. 주소 지정 방식 (addressing mode)
3. 목록
3.1. CISC3.2. RISC3.3. VLIW
4. 관련 문서

1. 개요

명령어 집합(Instruction Set Architecture(ISA), Instruction Set)은 소프트웨어 하드웨어, 특히 CPU와의 사이의 약속이다. ISA는 여러 명령어들을 정의하며 또한 현재 시스템의 상태가 어떻게 구성되어 있고 명령어를 실행할 때 그 상태가 어떻게 바뀌는지에 대해서 정의한다. 그래서 소프트웨어를 구현하는 프로그래머 입장에서는 ISA를 통해 작성한 프로그램이 컴퓨터에서 어떻게 실행될 것인지 알 수 있고, 하드웨어를 구현하는 설계자 입장에서 ISA는 어떤 명령이 수행되었을 때 어떻게 수행되도록 설계해야 하는지의 명세서가 된다. 이렇게 ISA를 정의함으로써 프로그래머 입장에서의 인터페이스와 하드웨어 설계자 입장에서의 구현을 분리할 수 있다.

2. 상세

컴퓨터의 상태를 저장하는 요소가 메모리이니, 컴퓨터의 상태는 현재 메모리에 무엇이 저장되어 있는지라고 해도 될 것이다. 이 가운데는 CPU 내부에서 빠르게 이용할 수 있는 메모리인 레지스터가 있다. 이 레지스터는 프로그램을 어디까지 실행했는지에 대한 정보를 담고 있는 프로그램 카운터(PC), 계산중에 만들어지는 값과 같은 데이터를 저장할 수 있는 데이터 레지스터 등 여러 종류가 있다. 명령어(instruction)는 이진수 코드의 조합으로, 프로세서가 명령어를 실행하면 레지스터에 저장된 정보와 같은 시스템의 상태가 바뀐다. ISA는 효과적인 프로그램 실행을 위해 다양한 종류의 명령어를 보유한다.
일반 사용자 입장에서는 응용 소프트웨어가 정상적으로 돌아가느냐를 가르는 두번째 장벽[1]이다. Windows on ARM이 탑재된 기기가 영 신통치 않은 판매량을 보이는 것도 이 이유이다.

2.1. 명령어의 구성

명령어는 보통 다음 두 부분으로 구성된다. 각 부분들이 이진수로 표현되고 조합되어 하나의 명령어를 구성한다. 예컨대, RISC-V ISA에 있는 ADDI 명령어는 지정한 레지스터에 들어 있는 정수 값에 특정한 정수 상수를 더하여 그 결과를 레지스터에 저장하는 명령어이다. 그러므로 이 명령어는 레지스터 둘과 상수 하나를 operand로 한다고 할 수 있다. 이 명령어의 길이는 4바이트(32비트)로, 비트 0-6과 12-14는 명령어의 종류(ADDI)를 나타내는 값이, 비트 7-11에는 결과를 담을 레지스터의 번호[2]가, 비트 15-19는 어느 레지스터에 상수를 더할지를 나타내는 레지스터 번호가, 비트 20-31에는 부호 확장되는 12비트의 상수 값이 들어간다. 1번 레지스터에 저장되어 있는 값에 5를 더한 값을 2번 레지스터로 저장하는 명령어를 이진수로 표현한다고 하자. RISC-V는 기본적으로 리틀 엔디안을 사용하므로, 다음과 같이 조립된다. (블록 윗줄은 비트의 넘버를 말하는데 10 이상의 경우, 윗숫자가 10의자리, 아랫숫자가 1의자리를 의미한다.)
 3                     2 1       1 1   1 1       7 6           0
 1                     0 9       5 4   2 1
+-----------------------+---------+-----+---------+-------------+
|0 0 0 0 0 0 0 0 0 1 0 1|0 0 0 0 1|0 0 0|0 0 0 1 0|0 0 1 0 0 1 1|
+-----------------------+---------+-----+---------+-------------+

이렇게 조립된 00000000010100001000000100010011이 명령의 이진수 표현이 되고, 이것을 실행하는 프로세서는 1번 레지스터의 값과 상수 5를 더해 2번 레지스터에 저장하는 동작을 한다. 이런 식으로 명령어를 표현한 것이 기계어인데, 사람이 읽기 편하게 하기 위해 다음과 같이 기계어에 대응하는 어셈블리어를 사용하여 표현할 수도 있다.
addi x2, x1, 0

2.2. 명령어의 형식

명령어는 피연산자를 지정하는 방식에 따라 다음과 같은 형식으로 나눌 수 있다:
명령어 형식 명령어의 예시 예시의 의미 설명 사용될 수 있는 예
0-operand add Stack[0] ← Stack[0] + Stack[1] 스택의 맨 위에서부터 피연산자를 읽어온다. 스택 구조 (예: x87)
1-operand add r1 ACC ← ACC + Regs[r1] 누산기를 암시적으로 사용하고, 추가 피연산자를 지정한다. 누산기 구조 (예: 인텔 4004)
2-operand add r1, r2 Regs[r1] ← Regs[r1] + Regs[r2] 하나의 레지스터는 값을 읽고 쓰는 데 사용하고 하나의 레지스터는 값을 읽는 데 사용한다. 레지스터 구조, 주로 CISC (예: x86)
3-operand add r1, r2, r3 Regs[r1] ← Regs[r2] + Regs[r3] 값을 읽을 레지스터들 및 쓸 레지스터를 각각 지정한다. 레지스터 구조, 주로 RISC (예: ARM, MIPS, RISC-V)

2.3. 주소 지정 방식 (addressing mode)

명령어가 어디에 있는 값을 읽고 써야 하는지 지정하는 방식을 주소 지정 방식이라 한다. 가능한 주소 지정 방식은 ISA마다, 명령어마다 다양하다. 아래에 다양한 주소 지정 방식을 설명하였다. Regs[r]는 레지스터 r에, Mem[x]는 메모리 주소 x에 있는 값을 의미한다.
주소 지정 방식 명령어의 예시 예시의 의미 설명 사용될 수 있는 예
레지스터(register) add r1, r2 Regs[r1] ← Regs[r1] + Regs[r2] 레지스터에 저장된 값을 접근할 때 지정한다. 연산 중간 결과의 저장
상수 / 즉치(immediate) add r1, 3 Regs[r1]←Regs[r1] + 3 명령어 자체에서 상수 값을 읽어올 때 지정한다. 상수 값과의 연산
직접 지정(direct) add r1, (1000) Regs[r1]←Regs[r1] + Mem[1000] 고정된 주소의 메모리를 접근할 때 지정한다. 전역 변수 접근
레지스터로 간접 지정(register indirect) add r1, (r2) Regs[r1]←Regs[r1] + Mem[Regs[r2]] 레지스터에 있는 주소의 메모리를 접근할 때 사용한다. 포인터 접근
거리로 지정(displacement) add r1, 4(r2) Regs[r1]←Regs[r1] + Mem[4 + Regs[r2]] 레지스터에 있는 주소에 일정 거리를 더한 주소의 메모리를 접근할 때 사용한다. 지역 변수 접근
레지스터로 거리 지정(index) add r1, (r2+r3) Regs[r1]←Regs[r1] + Mem[Regs[r2] + Regs[r3]] 레지스터에 있는 주소에 다른 레지스터 값에 해당하는 거리를 더한 주소의 메모리를 접근할 때 사용한다. 배열 접근

3. 목록

3.1. CISC

3.2. RISC

3.3. VLIW

4. 관련 문서


[1] 첫번째는 단연 운영체제고, 세번째는 하드웨어의 제원이다. 하드웨어가 세번째인 이유는 운영체제와 명령어 집합이 안 맞으면 '그 앱이 에러만 나고 실행 자체가 안 된다'라는 점이고, 하드웨어 제원이 안 좋으면 '그 앱이 실행까진 되지만 버벅거리고 느리다'라는 점이기 때문. [2] RISC-V의 기본 레지스터는 총 32개로, 5비트면 번호를 표현하는 데 충분하다.