명령어 집합

 

'''Instruction Set Architecture, ISA'''

1. 개요
2. 상세
2.1. 명령어의 구성
2.2. 주소 지정 방식 (addressing mode)
3. 관련 문서


1. 개요


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

2. 상세


컴퓨터의 상태를 저장하는 요소가 메모리이니, 컴퓨터의 상태는 현재 메모리에 무엇이 저장되어 있는지라고 해도 될 것이다. 이 가운데는 CPU 내부에서 빠르게 이용할 수 있는 메모리인 레지스터가 있다. 이 레지스터는 프로그램을 어디까지 실행했는지에 대한 정보를 담고 있는 프로그램 카운터(PC), 계산중에 만들어지는 값과 같은 데이터를 저장할 수 있는 데이터 레지스터 등 여러 종류가 있다. '''명령어'''(instruction)는 이진수 코드의 조합으로, 프로세서가 명령어를 실행하면 레지스터에 저장된 정보와 같은 시스템의 상태가 바뀐다. ISA는 효과적인 프로그램 실행을 위해 다양한 종류의 명령어를 보유한다.
  • 산술 논리 명령어 : 산술논리장치(ALU)를 이용하여 사칙연산이나 논리 연산 등을 수행한다. add, sub 등이 있다.
  • 데이터 전송 명령어 : 메모리 간에 데이터를 전송한다. load/store라고 하며, 특히 레지스터 간에 데이터를 전송하는 것은 보통 move 명령어라 한다.
  • 실행 흐름 제어 명령어 : 조건에 따라 서로 다른 실행 흐름으로 분기하는 branch 계열의 명령어, 서브루틴을 실행하는 call 명령어, 운영체제에게 흐름을 전달하는 trap 명령어 등이 있다.
  • 부동소수점 연산 명령어 : 부동소수점 실수의 연산을 하는 명령어들이다.

2.1. 명령어의 구성


명령어는 보통 다음 두 부분으로 구성된다. 각 부분들이 이진수로 표현되고 조합되어 하나의 명령어를 구성한다.
  • opcode : ADD, SUB와 같이 명령의 종류를 나타낸다.
  • operand : opcode, 어떤 대상에 대해 그 명령을 수행할 것인지에 대한 operand로 구성된다. 명령의 종류에 따라 함께 오는 operand의 구성은 다양하다. operand가 아예 없는 명령어도 있고, 하나, 둘, 심지어 셋 이상일 수도 있다. 흔히 오는 operand의 종류로는 레지스터, 메모리 주소, 상수 값 등이 있다.
예컨대, RISC-V ISA에 있는 ADDI 명령어는 지정한 레지스터에 들어 있는 정수 값에 특정한 정수 상수를 더하여 그 결과를 레지스터에 저장하는 명령어이다. 그러므로 이 명령어는 레지스터 둘과 상수 하나를 operand로 한다고 할 수 있다. 이 명령어의 길이는 4바이트(32비트)로, 비트 0-6과 12-14는 명령어의 종류(ADDI)를 나타내는 값이, 비트 7-11에는 결과를 담을 레지스터의 번호[1]가, 비트 15-19는 어느 레지스터에 상수를 더할지를 나타내는 레지스터 번호가, 비트 20-31에는 부호 확장되는 12비트의 상수 값이 들어간다. 1번 레지스터에 저장되어 있는 값에 5를 더한 값을 2번 레지스터로 저장하는 명령어를 이진수로 표현한다고 하자. RISC-V는 기본적으로 리틀 엔디안을 사용하므로, 다음과 같이 조립된다.
31                    20 19     15 14 12 11      7 6           0
+-----------------------+---------+-----+---------+-------------+
|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. 주소 지정 방식 (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. 관련 문서



[1] RISC-V의 기본 레지스터는 총 32개로, 5비트면 번호를 표현하는 데 충분하다.