명령어 집합(Instruction set)은 컴퓨터에서 사용하는 명령어들의 집합으로 서로 다른 컴퓨터는 다른 명령어 집합을 사용합니다. 하지만 대부분의 경우에 공통된 특징을 많이 가지고 있습니다. 이 책에서 선택한 명령어 집합은 MIPS이며 MIPS의 instruction set은 다른 명령어 집합에 비해서 간결하고 쉽게 배울 수 있습니다.
ISA는 Instruction Set Archtecture의 약자입니다. ISA는 lowest level software인 system software나 운영체제 간의 interface 역할을 해줍니다.(필요한 정보들을 instruction에 담아서 cpu에 주면 해당 instruction을 실행함) ISA는 같은 소프트웨어를 실행할 때 성능과 비용에 따라 다른 구현이 가능해집니다. ISA만 같다면 같은 소프트웨어를 여러 개의 cpu에서 실행할 수 있습니다.
application binary interface(ABI)는 ISA와 operation system의 합으로 두 개의 바이너리 프로그램 모듈 사이의 인터페이스를 의미합니다. 유저 관점에서 중요한 부분으로 어떤 프로그램이 특정한 컴퓨터에서 실행될 때 ABI가 같다는면 다른 컴퓨터에서도 그 프로그램을 실행될 수 있기 때문입니다. 집과 사무실 컴퓨터에서 ppt 실행이 가능한 것도 같은 ABI를 사용해서입니다.
다음으로는 MIPS에서 사용하는 instruction set에 대해서 알아보겠습니다.
Design Principle 1: simplicity favours regularity
첫 번째로 배우는 것은 arthmetic operation입니다. add instruction의 동작을 보면 b와 c를 더해서 a에 assign 합니다. 덧셈 연산과 같은 다른 연산들도 더해질 숫자 두 개와 결과를 기억할 장소 이렇게 operand 3개를 가집니다. 이런 경우 피연산자가 가변적인 것보다 주면 구현할 때 훨씬 수월한 것을 알 수 있습니다.
Design Principle 2: smaller is faster
arithmetic instruction는 레지스터를 사용해 연산을 합니다. MIPS는 0 ~ 31번까지 총 32bit 레지스터를 가지고 있습니다. 32bit 데이터는 word라는 단위로 부릅니다. 레지스터를 32개로 제한한 이유는 레지스터가 많으면 전기 신호가 더 먼 곳까지 전달되어야 하므로 클럭 사이클 시간이 길어지기 때문입니다. 메인 메모리는 용량이 크지만 액세스 시간이 레지스터에 비해서 거의 천 배 이상 소요됩니다.
Design Principle 3: Make the common case fast
컴퓨터에서 가장 기본이 되는 단위는 bit이며 8bit가 1byte입니다. 대부분의 컴퓨터에서는 메모리를 바이트 단위로 저장합니다. 32bit 프로세서에서는 메모리 단위를 word로 맞춥니다. Endian은 이 데이터를 word에 어떤 방식으로 저장할지를 결정합니다. Big Endian은 큰 값을 왼쪽 끝에 두고 Little Endian은 작은 값을 왼쪽 끝에 둡니다. 빅 엔디언은 데이터를 뒤집어서 저장하고 리틀 엔디언은 그대로 저장합니다.
메인 메모리에 대해서 알아보겠습니다. 메인 메모리는 어떤 데이터를 저장하는 공간으로 사용됩니다. 산술 연산은 레지스터에서만 진행되므로 메모리에서 레지스터로 데이터를 이동해야 합니다. 이 과정에서 사용되는 명령어가 data transfer instruction이라고 합니다. 메모리에 기억된 데이터 워드에 접근하려면 메모리 주소를 지정해야 합니다. MIPS 프로세서는 연산을 하고 싶을 때 레지스터로 load 한 다음 연산을 하고 메모리에 그 결과를 store 합니다. 이것을 load - store architecture라고 합니다. (컴파일러 같은 경우 메모리 액세스 횟수를 줄여야 하므로 이렇게 동작하지 못합니다.)
- Load/Store만을 통해서 메모리에 접근할 수 있습니다. (load/store architecture)
- intel의 경우 arthmetic operation에서도 메모리에 접근할 수 있습니다.
MIPS 레지스터 종류입니다. $zero 레지스터의 경우 0을 저장하고 있으며 다른 값을 write하지 못합니다. 이 레지스터는 특정 레지스터의 값을 복사하고 싶을 때 많이 사용합니다. 자주 사용하지 않는 variable은 메모리로 가져다 두고 최대한 사용할 것들만 드는 방향으로 최적화를 한다면 성능을 높일 수 있을 것입니다. (메모리 접근을 줄임)
- add $t2, $s1, $zero
- $s1에 0을 더해서 $t2에 넣는 방식으로 값을 복사합니다.
- 레지스터는 메모리보다 훨씬 빠릅니다.
- 레지스터를 늘리면 레지스터의 속도가 줄어들 수 있습니다.
Immediate operands에 대해서 알아보겠습니다. 이전 산술 연산에서는 3개의 operands가 모두 레지스터였지만 여기서는 마지막에 어떤 상수 값을 가집니다. addi $s3, $s3, 4는 $s3 + 4를 한 것이라고 생각하시면 됩니다. 뺄셈은 지원하지 않습니다. 작은 값의 상수를 Immediate operand로 사용하는데 이런 경우 메모리에서 load를 안 해도 되기 때문에 더 빠릅니다. (자주 사용하는 걸 빠르게 만든 것)
- 실제로 작은 상수값을 자주 사용하기 때문에 성능향상을 가져옵니다.
레지스터의 0번에는 항상 0이 저장되어 있으며, 읽기는 가능하지만 쓰기 명령을 불가능합니다. 이 레지스터를 통해서 move 기능을 구현할 수 있습니다. $s1에다 0을 더해 $t2에 넣으면 $t2로 $s1값을 옮긴 효과를 볼 수 있습니다. 이렇게 move 기능을 지원함으로써 move라는 명령어를 만들어주지 않아도 됩니다.
컴퓨터에서는 숫자를 2진수로 표현합니다. 부호가 있는 integer를 표현할 때는 2s-complement를 사용하며 범위는 항상 음수의 최대값이 양수의 최댓값보다 1 큽니다. (complement = sign bit를 사용), 범위가 확장되더라도 부호는 유지가 되어야 합니다.
컴퓨터에서 사용되는 모든 명령들은 바이너리로 표현되며 이것을 machine code라고 부릅니다. MIPS는 instruction을 32bit로 표현하고 operation code가 적어 간단하며 높은 성능을 얻을 수 있습니다.
위 사진은 MIPS R-format의 구조입니다. 제일 왼쪽부터 opcode, source register, target register, destination register, shift amount, 마지막으로 실제 operation인 function code가 적재되어 있습니다.
다음과 같이 assembly operation를 기계어로 표현할 수 있습니다.
Design Principle 4: Good design demands good
I-format에 들어가는 연산은 imediate arithmetric 이나 load/store입니다. 그래서 target register는 source register나 output register가 될 수 있습니다. load나 store를 진행할 때 16bit address에 offset값이 들어가며 이 값이 source register에 더해져 메모리 상에서 필요한 부분을 읽어 들입니다.
- load/store나 imediate arithmetic은 별개의 명령어지만 같은 format를 사용합니다.
- 이를 통해서 디코딩을 진행할 때 더 빠르게 진행할 수 있습니다.
- format을 많이 만들면 느려지는 문제가 존재 = MIPS는 2개의 format만을 사용
그 외에도 shit operation이 존재하는데 left로 i만큼 옮기면 2의 i 승을 곱한 값이 나오게 됩니다. right로 옮기면 2의 i승으로 나눈 값이 나오게 됩니다. right의 경우 unsigned type에만 적용이 됩니다.
and operation은 bit wise 연산을 통해서 두 레지스터에 들어 있는 값에서 겹치는 부분만 출력합니다. 이를 통해서 masking이나 특정 값을 제외한 나머지를 0으로 만들 수 있습니다. MIPS에서는 not operation을 지원하지 않기 때문에 nor를 통해서 구현해야 합니다.
- a NOR b == NOT(a OR b)와 같다는 점을 이용하여 구현합니다.
그다음은 conditional operation으로 branch 명령어 입니다. 조건에 맞는 경우 branch를 실행하고 그렇지 않을 경우에는 그 다음 명령어를 실행합니다. 이를 통해서 기존 sequential 한 동작을 벗어나게 됩니다. 실행 시 소프트웨어 인터럽트가 발생하고 가지고 있던 PCB 정보들을 스택에 대피시킵니다.
branch 명령어에서 사용할 수 있는 조건은 =와!=입니다. >, < 와 같은 기능을 지원하면 좋겠지만 이 기능은 equal, not equal에 비해서 구현하기 어려우면 구현하더라도 속도가 느립니다. 같거나 다른 것을 알기 위해서는 그냥 빼서 나머지가 0인지 아닌지를 확인하면 되지만 비교 연산은 복잡해서 하드웨어가 이 기능을 지원하면 clock이 느려집니다.
- 모든 명령어들은 clock에 동기화되어 있어서 마찬가지로 전부 느려지게 됩니다.
- 간단한 명령어를 만들어서 여러 번에 걸쳐 처리하는 것이 복잡한 명령어 하나를 처리하는 것보다 성능이 좋습니다.
'CS > Computer Architecture' 카테고리의 다른 글
6. Arithmetic for Computer (0) | 2024.02.19 |
---|---|
5. Instructions (0) | 2024.02.18 |
4. Instructions (0) | 2024.02.13 |
2. The Power wall (0) | 2024.02.06 |
1. Performance (2) | 2024.02.05 |