5.1. Memory 구조
- Reserved : 시스템에서 지정된 영역으로, 유저가 접근할 수 없다.
- Text: 프로그램 코드가 저장되는 영역이다.
- Static data: 프로그램의 전역변수나 const array 또는 string 이 저장되는 영역이다.
- Dynamic data: Heap을 의미한다. 시스템이 메모리를 할당할 때 아래에서 위 방향으로 저장한다.
- Stack: Function call 등 컴파일러가 위에서 아래로 데이터를 쌓으며 저장한다. 따라서 공간을 확보할 때는 stack pointer
SP
를 감산하면서 확보해야 한다.
5.2. Byte ordering
작은 주소가 큰 의미를 갖게 할 것인지, 큰 주소가 큰 의미를 갖게 할 것인지를 결정.
- Big endian = 작은 byte일 수록 큰 주소를 의미함.
- Little endian = 큰 byte일 수록 큰 주소를 의미함.
4-byte 상수 0x01234567
을 저장할 때,
- Big endian 이라면
0x100: 01
, 0x101: 23
, 0x102: 45
, 0x103: 67
이렇게 저장된다.
- Little endian 이라면,
0x100: 67
, 0x101: 45
, 0x102: 23
, 0x103: 01
이렇게 저장된다.
5.3. Common Addressing Modes
이 부분은 아주 중요한 내용이므로 주의깊게 보자.
- Immediate addressing
- 주어진 instruction에 operand에 address가 아니라 바로 상수 operand가 있는 경우다.
- Operand 부분에 직접 상수가 저장돼있기 때문에 memory access가 불필요하다.
- 가장 빠르다. (i.e.
LOAD #3
= 상수 3을 load함)
- Direct addressing
- 주어진 instruction의 operand에 가지고 올 operand의 주소가 있는 가장 일반적인 경우다.
- 주어진 address에 operand가 저장돼있으므로 memory access가 필요하다.
- Indirect addressing
- 주어진 instruction의 operand에 가지고 올 operand의 주소의 주소가 있는 경우다.
- Instruction에 기재된 address를 타고 가면, 또 다른 주소가 있다. 그 주소를 타고 가야만 우리가 원하는 operand가 있다.
- Register direct addressing
- Load-store architecture에서 사용하는 mode로, instruction에는 register의 index가 기재돼있다.
- Register에 저장된 값을 operand로 가지고 온다.
- Register indirect addressing
- Register에 operand가 저장돼있던 direct addressing과 달리, 이번에는 주소가 저장돼있다.
- Memory 상의 그 주소에 접근해야만 원하는 operand를 구할 수 있다. (Memory access 필요)
- Displacement (Based or Indexed) addressing
- Register indirect addressing 기반이기는 하지만, register의 저장된 주소가 operand를 저장하고 있는 주소가 아니라, base로 사용할 주소다.
- Instruction에 기재된 상수값을 이 base 주소에 더한 새로운 주소가 operand가 저장된 주소다.
- Relative addressing
- 현재 PC에 저장된 메모리에 임의의 상수를 더해서 operand의 주소를 가리키는 방법이다.
이것들 이외에도 정말 많은 addressing mode가 있다.
우리는 지난 시간에 instruction을 종류에 따라 ⓐ Data movement, ⓑ ALU, ⓒ Branch 3가지로 분류했다.
ISR에 따라 지원하는 instruction의 length가 다르다
- 고정길이: 다음에 몇 bit를 읽어오면 명령어를 형성할 수 있을지 이미 알고있기 때문에 복잡도가 낮고 시간이 짧다. 하지만, 경우에 따라 instruction의 bit가 낭비되기도 한다.
- 가변길이: 명령어에 따라 필요한 length만 사용하므로 stroage에 낭비가 없다. 하지만, 다음에 올 instruction의 length를 알 수 없기 때문에 word-aligned 해야만 한다. 고정길이 instruction 보다 비교적 decode가 복잡하다.
CISC
- CISC에서는 최대한 많고 복잡한 addressing mode와 instruction을 지원하며 가변길이 instruction이다.
- 도구가 많기 때문에 복잡한 연산을 최대한 적은 cycle에 수행할 수 있도록 최적화할 수 있다.
- 하지만, 그런 최적화가 언제나 쉽게 가능한 것은 아니다.
RISC
- RISC는 적고 단순한 addressing mode와 instruction을 지원하며 고정길이 instruction이다.
- 일반적으로 하나의 instruction은 1 WORD 길이를 사용한다.
- 1 Cycle에 1 instruction을 수행하는 것을 원칙으로 한다. (예외인 경우도 있다.)
- CISC는 최적화로 간단히 할 수 있던 복잡한 작업에 몇몇 cycle을 더 사용해야 하기도 한다.
- Memory access instruction을
LDA
와 STA
로 한정짓는다. (Load-Store architecture가 기본임.)
- 컴파일러에 의존하는 ISA이므로 컴파일러의 성능에 영향을 크게 받는다.
- RISC-V는 RISC의 5번째 버전으로 임베디드 마켓을 타겟으로 새롭게 재정의 된 ISA를 의미한다.
MIPS
- RISC-V의 전신(predecessor) 격인 ISA다. RISC의 기본적인 제한이 모두 녹아들어있다.
- Instruction length는 32-bit (1 WORD)로 제한되있다.
- 32개의 gereral purpose register가 있다.
- Memory access instruction을
LDA
와 STA
로 한정짓는다.
- Branch 관련된 명령어를 조금 더 세부적으로 다양하게 지원한다.
5.5. RISC-V Operations
- RISC-V의 설계 규범 ⓐ: 단순한 구조는 곧 일반화된 구조를 말한다.
- RISC-V의 설계 규범 ⓑ: 작을 수록 더 빠르다.
Arithmetic operations
-
모든 arithmetic operations는 OP dest op1 op2
형식을 따른다.
-
C언어로 f = (a + b) - (c + d)
라고 작성했을 때, RISC-V ISA로 컴파일 된 코드는 다음과 같다.
-
add t0, a, b ;;; temp t0 = a + b
add t1, c, d ;;; temp t1 = c + d
sub f, t0, t1 ;;; f = t0 - t1
Register operations
-
RISC-V는 32개의 64-bit (2 WORD) register를 가지고 있다.
-
0번 register는 항상 0
으로 고정돼있다. (0
이라는 상수를 만드는 데에 비효율적인 과정을 거쳐야 하기 때문이라고 함.)
-
RISC-V 역시 Load-store architecture이므로 register를 적극 활용해서 빠른 연산을 수행하는 데 집중한다.
-
RISC-V의 register들은 사용자가 custom하게 사용할 수도 있지만, n번째 register를 특정 용도로 사용하자는 규약이 있다. 예를 들면 아래 그림과 같다.
Memory Operands
- RISC-V는 Little endian을 사용한다.
- Memory access를 최대한 줄이기 위해 register를 많이 활용해야 효율적이고 빠른 연산이 가능하다.
- C언어로
A[12] = h + A[8];
이라는 코드가 있을 때, RISC-V로 컴파일하면 다음과 같다.
;;; h는 x21, A는 x22에 저장돼있다고 가정함.
ld x9, 64(x22) ;;; displacement indirect addressing
add x9, x21, x9 ;;; x9 = x21 + x9 = h + A[8]
sd x9, 96(x22) ;;; x9 -> A[12]
A = A[0] = x22
register에 저장되있으므로 8번 인덱스는 x22
register로부터 8 * 8 = 64-bit 떨어져있다는 것을 displacement addressing으로 나타냄.
- A[8] 값을
x9
register에 load함.
- h가 저장된
x21
값과 A[8]이 저장된 x9
를 더한 뒤 다시 x9
에 덮어씌움.
x9
값을 x22
로부터 8 * 12 = 96-bit 떨어진 A[12]가 있는 address에 저장함.
- 상수값에 대한 연산을 수행할 때는 immediate addressing을 사용해서 instruction을 수행한다.
- Immediate operand는 memory access가 불필요하므로 load operation이 필요없어서 빠르다.
addi x22, x22, 10
이런 식으로 표현한다.