• 프로그래밍 언어의 두가지 분류
High-level Languages
컴파일러를 지원하기 때문에 하드웨어 독립적이다.
하나의 문장이 여러 명령어를 포함한다.
ex) C, C++, Java, Python
Low-level Languages
특정 아키텍처에서 볼 수 있기 때문에 하드웨어 종속적이다.
하나의 문장이 기계어 하나로 대응되는 경우가 많다.
ex) Assembly languages for x86, ARM, RISC-Ⅴ
• Assembly Language vs Machine Language
Assembly Language
기계어에 대한 표현이다.
하나의 문장이 하나의 기계어에 대응한다.
High-level 프로그램과 기계어 코드 사이의 Abstraction layer이다.
Machine Language
컴퓨터의 Native 언어이다.
하드웨어(CPU)에 의해 실행되는 이진(binary) 형식의 표현을 가지고 있다.
• CPU의 기본적인 4가지 컴포넌트
- PC(Program Counter)
CPU가 다음에 실행할 명령어의 주소를 가리키는 역할을 한다. - Register file
데이터를 저장하는 Register의 집합이다.
가장 빠르고 가장 작은 크기의 메모리이다. - ALU(Arithmetic & Logic Unit)
산술 연산과 논리 연산을 수행한다. - Control logic
명령어 Fetch, Decode, Execute를 제어하는 로직이다.
명령어를 해석하고 실행하는 데 필요한 모든 제어 신호를 생성하고 관리한다.
PC값을 기반으로 계속해서 명령어를 순차적으로 처리하면서 수행된다.
• Instruction Set(명령어의 집합)
컴퓨터 명령어의 레퍼토리(모음)이다.
컴퓨터마다 명령어 세트가 다를 수 있다.(RISC vs CISC)
초기 컴퓨터는 명령어 세트가 단순했다.
• ISA(Instruction Set Architecture)
하드웨어와 소프트웨어 사이를 구성하는 인터페이스 역할을 한다.
소프트웨어가 요구/제약사항을 만족하면서도, 고성능 & 저전력 하드웨어를 구현하는 것이 ISA의 목적이다.
• ISA의 구성요소
- Instruction set = operation (명령어 = 동작)
- Processor register (레지스터)
- Memory addressing modes (메모리 주소지정방식)
- Data types and representations (데이터타입 표현)
- Byte ordering (바이트 오더링)
• RISC-Ⅴ
학계/산업계에서 무료로 이용가능하다.
RISC 기반 ISA는 임베디드 시장에서 큰 점유율을 차지한다.
3개의 기본 Integer ISA(32/64/128-bit)가 존재한다.
RV32I(RISC-Ⅴ 32bit Integer)는 47개의 instructions를 가지고 있다.
(굉장히 적은 숫자)
RISC-Ⅴ 표준 ISA 확장
목적에 맞게 최적화해서 사용할 수 있다.
• RISC-Ⅴ: Registers
Register 32개 + Program counter로 구성되어 있다.
컴파일러가 레지스터 번호마다 사용 목적을 명시해두고 있다.
몇몇 레지스터들을 살펴보자.
x0 : 언제나 0인 상태를 유지한다.
x1 : 돌아올 주소를 저장해두는 용도로 사용한다.
x2 : 함수에서 데이터를 쓸때 스택 몇 번째 포인터를 저장하고 있는지를 알아보는 용도로 사용한다.
x5 : 임시변수로 사용한다.
x12 ~ x17 : 6~8개가 Fuction arguments로 사용된다.
컴퓨터 아키텍처에서 제공하는 Fuction arguments가 제한적이기 때문에 함수 인자를 많이 늘리면 성능이 떨어질 수 있다.
• Memory
Byte addressable array(바이트 단위 주소이다.)
address의 가장 하위 비트를 증가시키면 byte 단위로 증가한다.
따라서 메모리 단위가 byte로 되어있기 때문에 bit 단위로 읽을 수 없다.
(char : 1byte)
• Registers vs Memory
레지스터는 프로세서에서 가장 작고 빠른 메모리이기 때문에 메모리보다 빠르다.
RISC-Ⅴ에서 메모리의 데이터는 직접 접근할 수 없고 Load 후 연산이 가능하다.
#1의 RISC vs CISC를 보면 RISC가 더 많은 명령어 수행을 필요로 함을 알 수 있다.
• RISC-Ⅴ: Operations
레지스터에 저장된 데이터를 기반으로 산술/논리 연산을 수행한다.
Register에 저장되어 있는 값만 사용 가능하고, Memory는 접근할 수 없다.
(x86에서는 가능)
Load 명령어 (레지스터 ← 메모리)
Store 명령어 (레지스터 → 메모리)
Transfer control : 분기, 반복, 함수 호출 및 리턴에 사용된다.
• RISC-Ⅴ: Addressing(주소 지정 방식)
데이터는 어떻게 정의될까?
4가지 방식이 존재한다.
1. Immediate(constant) value : 곧바로 내재하는 방식
2. Value in a register : Register에 있는 것을 가지고 오는 방식
3. Value in memory : Register에 없고 Memory에 있는 경우 Load나 Store 명령어를 이용해 메모리에 접근한다.
4. Adress : go to문이나 분기문을 이용해서 접근한다.
• Data Representation
• RISC-Ⅴ: Arithmetic & Logical Operations(산술/논리 연산)
• Arithmetic Operation(산술 연산)
Register Operand
산술 명령어는 레지스터 피연산자를 사용한다.
자주 접근하는 데이터를 위해 사용한다.
임시변수가 사용된다는 것을 알수 있다.
Immediate Operand
이제 하나가 immidiate 값인 명령어에 대해 알아보자.
작은 크기의 상수는 일반적으로 많이 사용된다.
이러한 경우에는 64-bit 레지스터를 쓸 필요가 없고, Load 명령어를 피할 수 있다.
실제로 이러한 과정은 컴파일러가 대신해준다.
• Arithmetic Operations (산술 연산 명령어 정리)
밑에 있는 두 Instruction은 12bit 즉시값으로는 표현할 수 없는 큰 상수값을 레지스터에 로드할 때 사용한다.
다음은 lui와 addi 명령어의 사용 예시이다.
lui 명령어는 상위 20비트를 설정하고, addi 명령어는 하위 12비트를 추가하여 값을 완성한다.
• Logical Operation(논리 연산)
AND Operation : bit를 masking 하는데 사용
둘 중 하나라도 1이 아니면 0을 저장한다.
OR Operation : 포함여부를 체크하는데 사용
둘 중 하나라도 1이면 1을 저장한다.
XOR Operation : 비트의 차이를 확인하는데 사용
비트 값이 동일하면 0, 다르면 1을 저장한다.
• Logical Operations (논리 연산 명령어 정리)
• RISC-Ⅴ: Data Transfer Operations
메모리는 바이트단위 주소를 사용한다.
즉, 바이트보다 작은 단위를 지정할 수 없다.
Data transfer instructions
데이터를 메모리에서 레지스터로 로드하거나, 레지스터의 데이터를 메모리로 스토어하는 명령어이다.
로드 명령어
데이터의 크기에 따라 명령어가 다르게 사용된다.
lw : 32bit
ld : 64bit
스토어 명령어
sw : 32bit
sd : 64bit
• Byte Ordering
빅 엔디언과 리틀 엔디언 방식이 있다.
빅 엔디언 : 큰 값이 끝의 주소에 래핑된다.
리틀 엔디언 : 작은 값이 끝의 주소에 래핑된다.
• Alignment Restrictions
align가 되어 있지 않은 데이터는 성능저하가 필연적으로 발생할 수밖에 없기 때문에(로드 명령어를 두번 사용하는 등) 대부분의 아키텍처에서는 align를 맞추는 것을 가급적 권장하고 있다!
'CS > 컴퓨터구조' 카테고리의 다른 글
[컴퓨터구조] #7 ISA(3) (0) | 2024.04.23 |
---|---|
[컴퓨터구조] #6 ISA(2) (0) | 2024.04.23 |
[컴퓨터구조] #4 부동소수점 (0) | 2024.04.19 |
[컴퓨터구조] #3 정수표현법 (0) | 2024.04.15 |
[컴퓨터구조] #2 성능 (0) | 2024.04.10 |