CPU 규격 제조사 명령어 세트 - CPU gyugyeog jejosa myeonglyeong-eo seteu

2. 명령어와 CPU 아키텍처 (Instructions and CPU Architectures)

  • 2020.10.12 16:17
  • Study Note/컴퓨터구조

명령어Instructions는 특정 마이크로프로세서가 인식하고, 기능을 수행할 수 있는 기계어 명령어의 집합을 말한다. 프로세서는 제조사, 목적 등에 따라 각기 다른 명령어 집합Instruction Set을 보유하고 있다. 우리가 사용하는 컴퓨터 프로그램은 각 프로세서에 대응하는 명령어의 집합(즉, 기계어)로 번역되어 실행되게 된다.

구식 컴퓨터뿐 아니라 현대의 컴퓨터들도 의외로 간결한 명령어 집합을 보유하고 있다.

명령어는 opcode와 operand로 구성되는데, opcode는 해당 명령어가 수행할 기능(store, load, add 등)을 나타내고, operand는 해당 명령을 수행하는데 필요한 데이터의 메모리 주소를 나타낸다.

명령어의 길이

메모리 반도체의 가격이 비쌌던 옛날에는, 코드 전체의 크기를 최소화하기 위해 명령어의 길이를 가변적Variable으로 정했다. 자주 사용되는 명령어는 짧은 길이를 할당하고, 자주 사용되지 않는 명령어에는 긴 길이를 할당하여, 코드의 전반적인 길이를 줄이는데 집중했다.

그러나, 메모리의 가격이 저렴해지고 실행 시간이 중요해짐에 따라 모든 명령어의 길이가 동일한 고정Fixed 명령어 길이를 사용하기 시작했다.

명령어 집합 구조의 작동 구조

명령어 집합으로 구성된 프로세서는 다음 과정의 반복을 통해 작동한다.

  1. Instruction Fetch
    1. 명령어를 메모리에서 가져온다.
    2. 가져온 명령어를 특수 register에 저장해 둔다.
  2. Instruction Decode
    1. 명령어가 어떤 기능을 수행할지 결정한다. = 명령어 내의 opcode 부분을 decode 한다.
  3. Operand Fetch
    1. 수행할 데이터를 메모리에서 가져온다.
    2. 가져온 데이터를 범용 register에 저장한다.
  4. Execute
    1. Decode된 명령 기능을 수행한다.
    2. 결과를 범용 register에 저장한다.
  5. Result Store(Write Back)
    1. 범용 register에 있는 결과를 메모리에 저장한다.
  6. Instruction Fetch (다음 명령어로 반복)

위 구조에서, 레지스터와 메모리간의 데이터 이동이 많은 것을 알 수 있다. 실제로 컴퓨터에서 실행되는 명령어의 30% 이상은 load 명령어와 store 명령어라고 한다. 때문에, 메모리와 프로세서간의 I/O 성능이 성능에 큰 영향을 미친다.

명령어 실행 파이프라인

짧은 시간에 많은 명령어를 처리하기 위해, 프로세서는 명령어 수행의 5단계를 파이프라인을 통해 동시에 수행한다.

즉, A 명령어의 Instruction Fetch 작업이 끝나면 A 명령어의 Instruction Decode 작업을 시작함과 동시에 B 명령어의 Instruction Fetch 작업을 시작한다. 이 과정이 끝나면 A 명령어는 Operand Fetch, B 명령어는 Instruction Decode 단계에 진입하며 또다시 바로 C 명령어의 Instruction Fetch를 시작한다.

이 방법을 통해, 한 명령어의 5단계가 끝나고 다음 명령어를 실행하는 것에 비해 이론상 5배 빠른 처리가 가능하다.

CPU 아키텍처의 발전

이렇듯 컴퓨터 구조는 실행 속도를 개선하는 방향으로 발전하였는데, 초창기에는 누산기 구조Accumulator Architectures라 부르는 방법이 적용되었다.

이후, 스택 구조가 도입되며 레지스터가 등장했고, 마침내 우리가 사용하는 고레벨 컴퓨터 구조, 범용 레지스터 구조General-Purpose Register가 등장하게 되었다.

CISC vs RISC

CISC와 RISC는 CPU 아키텍처의 일종으로, CISC는 복잡 명령어 집합 컴퓨터Complex Instruction Set Computer를 의미하고, RISC는 축소 명령어 집합 컴퓨터Reduced Instruction Set Computer를 의미한다.

CISC는 이름처럼 복잡한 명령어 집합을 갖는데, 덕분에 Load 명령어를 따로 실행하지 않고 한번에 데이터를 load하여 연산을 수행할 수 있다. (즉, a+b를 수행할 때, load와 add를 따로 수행할 필요없이, add만으로 해결가능하다.)

이러한 장점이 있지만, CISC는 가변 명령어 길이로 인해 각 명령어의 실행 속도가 상이하여, 파이프라인을 통한 병렬처리에 약하다는 큰 단점이 있다.

반면, RISC는 단순한 고정 길이 명령어들로 구성되어 파이프라인 처리에 용이하다는 장점이 있으며, 복잡한 연산을 단순한 연산의 조합으로 처리하므로 CISC에서 처리 가능한 연산을 모두 수행할 수 있다.

RISC는 메모리 접근을 Load/Store의 두 명령어로 제한하여, 다른 연산에서 불필요한 메모리 접근으로 인한 속도 저하를 막았다는 특징도 있다.

결과적으로, 현대에 들어 CPU 아키텍처는 대부분 RISC 구조를 채택하게 되었다.

C언어에서 명령어로

아래의 C 코드를 실행하는 경우를 가정해보자.

sum = a + b;

먼저, C언어 코드는 다음과 같은 어셈블리어로 컴파일된다.

lw $1, 100($5) # $5(메모리)이 100번째 주소에 있는 값을 레지스터 $1로 이동
lw $2, 104($5) # 메모리의 104번째 주소에 있는 값을 레지스터 $2로 이동
add $3, $1, $2 # $1, $2를 더한 값을 $3에 저장
sw $3, 108($5) # $3의 값을 메모리 108번 주소에 저장

이 코드는 최종적으로 기계어 명령어로 변환된다. 아래 명령어 집합에서 1번은 load, 2번은 add, 3번은 store에 대응된다고 보면 된다.

# 1번 명령어 , 1번 주소, 5번 주소 + 100
0001 0001 0101 0110 0100
# 1번 명령어 , 2번 주소, 5번 주소 + 104
0001 0010 0101 0110 0110
# 2번 명령어, 1번 주소, 2번 주소, 3번 주소
0010 0001 0010 0011
# 3번 명령어, 3번 주소, 5번 주소 + 108
0011 0011 0101 0110 1000

1. 명령어 세트(Instruction Set) -> CPU 기능을 위해서 정의된 명령어들의 집합

  • CPU의 기능은 이들에 의해 결정된다.
  • 이들의 수와 종류는 CPU에 따라 많이 다르다.(아키텍처가 다르기 때문  ex. x86, amd64)

2. 명령어 세트 정의를 위해 결정되어야 할 항목

       operand : 컴퓨터에서, 연산에 필요하거나 연산으로 나타나는 수치를 통틀어 이르는 말(출처 : 네이버 백과사전)

    A. 오퍼랜드(operand)

        ① 오퍼랜드의 크기와 형태

        ② 정의 방법

    B. 오퍼랜드의 CPU 기억장소

        ① 스택(Stack)

        ② 범용 레지스터(GPR)

        ③ 누산기(Accumulator)

    C. 연산 명령어

        : CPU 명령어가 수행할 연산들의 수와 종류

    D. 오퍼랜드/명령어

        : 일반적인 명령어가 처리 가능한 오퍼랜드의 수

    E. 오퍼랜드의 위치

        ① CPU의 외부 혹은 내부

        ② Reg-to-Reg, Mem-to-Reg, Mem-to-Mem(-> 데이터를 주고 받는 경로를 의미함)

    2-1. 부연 설명

          여기서, operand의 CPU 기억장소와 명령어의 종류 및 형식, 명령어의 주소지정 방식에 대해서는 좀 더 설명할 것이 있다.

          A. operand의 CPU 기억장소

              1) stack architecture(CPU 초기 버전에 쓰임)

                  간단한 명령어로 직관적으로 짤 수 있다는 장점이 있으나, 그러기엔 많은 코드를 써야는 단점이 존재한다.

              2) accumulator architecture

위와 마찬가지로 간단한 명령어로 직관적으로 짤 수 있고 내부 구조를 최소화 할 수 있는 장점이 있으나, 메모리 사용량이 높아지는 단점이 있다.

              3) General-Purpose Register architecture(GPR)

가장 보편적인 모델이라는 장점이 있지만, 명렁어의 길이가 길어지는 단점이 있다.

          B. 명령어의 종류

             1) 데이터 전송명령

                 : Reg-Reg, Reg-Mem, Mem-Mem 간에 데이터를 이동시키는 명령

             2) 산술 연산명령

                 : 2의 보수 및 부동소수점 수에 관한 덧셈, 뺄셈, 곱셈 및 나눗셈과 같은 기본적인 산술 연산 명령

             3) 논리 연산명령

                 : 데이터의 각 비트들 간에 대한 논리 연산 명령

             4) I/O(입출력) 명렁

                 : CPU와 External I/O 장치들 간의 데이터를 이동시키는 명령

             5) 프로그램 제어명령

                 : 각 명령어의 실행 순서를 변경하는 Branch 명령과 Subroutine call 및 return 명령


          C. 명령어의 형식

             ① 명령어는 CPU가 한 번에 처리할 수 있는 비트 수의 크기(word / cpu마다 다름)로 정의된다.

             ② 명령어를 구성하는 비트는 용도에 따라 몇개의 Field로 나누어진다.

             ③ 기본적으로는 op-code field와 operand field로 구성된다.

             ④ operand field는 컴퓨터의 처리 능력에 따라 여러 개의 operand field로 구성된다.

오퍼레이션 코드(op-code) : CPU에서 실행될 연산(load, store, add 등)을 지정

/

오퍼랜드(operand) : 연산을 실행하는 데 필요한 데이터 혹은 주소 값을 포함한다.

             1) op-code field의 비트 수

                CPU에서 수행될 연산 종류의 수에 따라 비트의 수가 결정된다. ex) 연산의 종류가 8가지 -> 8=2^3 이므로 3비트 필요

                ② 비트 수가 증가할수록 많은 연산의 정의가 가능하나, operand field 비트 수가 감소(-> 32bit cpu보다 64bit cpu가 더 좋은 이유)

             2) operand field의 비트 수

                operand의 종류에 따라 결정됨

                ② immediate value : 표현 가능한 수의 범위 결정

                ③ memory address : CPU가 직접 주소를 지정할 경우 기억장치 영역의 범위가 결정됨(ex. 10bit면 0~1023)

                ④ register no. : GPR의 수를 결정한다.

             3) 명령어 형식의 예

                A) 1-address instruction

                B) 2-address instruction(operand가 모두 레지스터인 경우)

@는 address, #은 immediate value를 의미함

                B-2) 2-address instruction(오퍼랜드 한 개만 레지스터인 경우)

※교수님께 여쭤보니 명령어의 경우 아키텍처별로 상이하기 때문에 LOAD R1, #100 같은 경우 상황에 따라 R1 <- M[R+100]도 맞고, R1 <- 100 도 맞다다고 하심. 그렇지만 대다수의 엔지니어들은 뒤의 표현이 맞다고 함

                C) 3-address instruction(모든 operand가 레지스터인 경우)

                C-1) 3-address instruction(operand 두 개는 레지스터인 경우)

          D. 명령어의 형식에 따른 실행 예제

             1) 1-address instruction

             2) 2-address instruction

             3) 3-address instruction

          E. 명령어 addressing mode 방식

              * 사용목적

                A) 정해진 명령어의 비트들은 그 수에 있어 매우 제한적

                B) 그 안에 오퍼랜드들만으로 메모리를 지정하는 것 또한 매우 제한적

                C) 더 큰 용량의 메모리에 접근하기 위해서는 직접/간접으로 다양한 방법이 요구됨

                D) 이러한 방법은 아키텍쳐마다 다름

CPU 규격 제조사 명령어 세트 - CPU gyugyeog jejosa myeonglyeong-eo seteu

Instruction-addressing mode-address-data  ->  간접

Instruction-addressing mode-data  ->  직접

              1) 즉치(immediate addressing mode)

operand에 immediate 값이 들어있으므로 인출할 필요가 없다.

              2) 묵시적(implied addressing mode)

오퍼랜드가 없는 명령어나, 오퍼랜드가 1개인 명령어에 이용된다.

              3) 직접(direct addressing mode)

'데이터에 할당된 메모리가 커지면 제한적'이라는 단점을 가지고 있다. 이를 보완한 것이 뒤에 나올 간접 지정모드이다.

              4) 간접(indirect addressing mode)

              5) 레지스터(register addressing mode)

제일 좋아보이는데 안 쓰는 이유? 레지스터가 비싸기 때문...

              6) 레지스터 간접(register indirect addressing mode)

              7) 변위(displacement addressing mode)

                  A) relative addressing

                      레지스터에는 PC가, 다음 명령어의 주소는 주소 필드에(위의 imm), 유효 주소(위 memory의 data)에는 (다음 명령어 주소-PC)값이 저장됨.                       주소 비트를 절약할 수 있는 장점이 있다. 주로 branch 명령어에 사용됨(ex. jump)

                  B) indexed addressing

                     유효주소 data는 인덱스 레지스터의 내용 + 변위 값을, 레지스터는 인덱스 레지스터를, 주소 필드는 배열의 첫번째 값의 번지를 갖는다.

                     배열을 쓸 때 유용하다.

                  C) base-register addressing

                      베이스 레지스터의 내용과 변위를 더하여 유효 주소를 결정하는 방식(어디에 쓰이나 찾아보려고 했으나 찾기 어렵다)