반응형
Arithmetic Operation (산술 연산)
컴퓨터에서 덧셈 및 뺄셈을 할때? 피연산자 3개로 구성됩니다.
- Source 2개 및 destination 1개로 구성됩니다.
- 모든 산술 연산에는 아래 예시와 같은 형식이 있습니다
Design Principe 1. 정규성을 위한 단순성 (Simplicity favors regularity)
- 연산의 규칙성을 통해 구현이 더욱 간단해집니다.
- 단순성으로 더 낮은 비용으로 더 높은 성능을 제공한다는 특징이 있습니다.
Register Operands (피연산자 등록)
산술 명령어는 레지스터 피연산자를 사용합니다
- RISC-V (RV32I) has a 32 x 32-bit register files: x0 ~ x31
효율적인 Register의 사용은? → 연산 결과의 성능 상승으로 이어집니다.
- 자주 액세스하는 데이터에 사용됩니다.
- 그리고 32비트 데이터를 "word” 라고 부릅니다.
Design Principle 2. 더 작은 것이 더 빠름 (Smaller is faster)
EX. 메인 메모리: 수백만 개의 위치 (메모리 vs 레지스터)
- 위에 말이 무슨말이냐? 라고 설명을 드리면?
- Register 개수는 32개 고정이지만, Memory 용량은 ~ TB 단위까지 높아집니다.
- 또한 CPU와 가까울수록 빨라짐 & 규모가 줄어들면 탐색시간도 감소합니다.
Register Operands Example
산술논리연산: add [목적 Register, Source Register 1, Source Register 2] 으로 예시를 들어보겠습니다.
C: f = (g + h) - (i + j);
- RISC-V Code
- add x5, x20(g), x21(h) → x20(g) + x21(h) = x5에 저장 (x5는 아무데나 지정)
- add x6, x22(i), x23(j) → x22(i) + x23(j) = x6에 저장 (x6는 아무데나 지정)
- sub x19, x5, x6 → x5(x20(g) + x21(h)) - x6(x22(i) + x23(j)) = x19(f)
Registers vs. Memory
레지스터는 메모리보다 액세스 속도(접근 속도)가 빠릅니다.
- RISC-V 에서는 ALU(산술 논리 연산값) instruction 으로 메모리의 데이터를 직접 처리할 수 없습니다.
ALU(산술 논리 연산값) instruction 으로 Memory에 바로접근 불가
→ Memory 주소를 찾아서 Register로 load후 Register - Register간 연산 필요!
- 메모리 데이터에 대한 작업을 수행하려면 load(가져오기) 및 Store(쓰기)가 필요합니다
- 실행해야 할 Instruction이 더 많습니다.
- 또한 컴파일러는 가능한 한 변수에 대해 레지스터를 사용해야 합니다
- 덜 자주 사용되는 변수에 대해서만 메모리로 유출됩니다.
- 그래서 레지스터 최적화가 중요합니다!
Immediate Operand
여기서 질문을 드리면, 명령어에 지정된 일정한 데이터는? → 상수 연산을 처리하기 위해서 32bit 명령어중 얼마나 차지할까요?
- addi(즉시 연산 수행)형식: 목적지_레지스터, 소스_레지스터, 즉시값
addi x22, x22, 4 → x22 Register에 x22 주소에 있는 값 + 4 후 다시 Register x22에 저장합니다.
Register x22에 저장된 값을 4만큼 증가시키고, 그 결과를 다시 Register x22에 저장합니다.
- 공용 케이스를 빠르게 만듭니다
- 작은 상수가 일반적입니다(제한된 12비트)
- 피연산자를 즉시 지정하고 로드 명령을 피합니다 → 상수 연산을 시켜서 load instruction을 피합니다.
32-bit Constant
대부분의 상수는 작습니다. 그래서 12비트를 즉시 사용하는것으로도 충분합니다.
- 다만, 경우에 따라 32비트 상수를 사용합니다.
- 20비트 상수를 rd의 비트 [32:12]로 복사합니다.
- 그리고 rd ~ 0의 비트[11:0] 지워서 사용합니다.
ex) x19 ← 0x003D500 [0x003D / 500]
- lui x19, 0x003D0 (상위 20bit)
- addi x19, x19, 0x500
i type 명령어 (12비트만 표현 가능 - 상위 20비트, 하위 12비트로 자릅니다)
Logical Operation (논리 연산)
bitwise(비트 단위) 조작에 대한 instruction 내용을 설명해 보겠습니다.
Shift left (slli)
→ s (shift), l (left or right), l (logical(논리연산) or Arthimentic(산술연산)) + i (피연산자상수)
- Word 단위로 비트 그룹을 추출하고 삽입하는 데 유용합니다.
AND Operations
- Word 단위로 여러가지 마스크 비트를 사용합니다. → 일부 비트를 선택하고 나머지 비트를 0으로 지웁니다.
Example. and x9, x10, x11
- AND
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
AND: 둘다 1이면 1로 set, if문 보다 성능이 좋다는 특징이 있습니다. 또한 두 비트가 1인 경우만 색출에 유용합니다.
OR Operations
- 비트를 단어로 포함하는 데 유용합니다. → 그리고 일부 비트를 1로 설정하고 다른 비트는 변경하지 않습니다.
Example. or x9, x10, x11
- OR
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
OR: 둘중 하나만 1이면 1로 set으로 됩니다.
XOR Operation
- XOR Operation은 Differencing 작업이라는 개념이 들어갑니다.
- 비트가 같은 경우 지우기, 다른 경우 설정을 합니다.
- 같은 비트확인시, 다음비트 뭐인지 확인시에 유용하다는 특징이 있습니다.
xor x9, x10, x12
- XOR
0 | 0 | 1 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Shift Operations
Shift Operations 즉, → 이동 연산은 얼마나 큰 이동을 하는지 전달 및 방향 설정을 합니다.
- immed: 얼마나 많은 위치를 이동할 것인지를 의미합니다.
- Shift left logical
- 왼쪽으로 이동하고 0비트로 채웁니다
- slli by I bits는 2를 곱합니다!
- Shift right logical
- 오른쪽으로 이동하고 0비트로 채웁니다(논리)
- srli by I bits 2**i 로 나눕니다!(부호되지 않은 경우만 해당)
- C.f. Shift right Arithmetic → Logical(논리) or Athimetic(산술)
- 오른쪽으로 이동하고 MSB 비트로 채웁니다 (sra)
오른쪽으로 이동시 빈칸이 남는데 0채움 - logical, 부호비트(MSB) → Arithmetic
1칸씩 가면 / 2 효과
Arithmetic Opeations (산술 연산) 정리표
SignExt (imm12) → 빈공간을 부호비트(32bit)로 채웁니다.
또한 32bit 연산자로 계산이 가능합니다.
Logical Operation (논리 연산)
Example: Arithmetic Operation (산술 연산)
- add a5, a0, a1 : a0와 a1을 더한 결과를 a5에 저장합니다. 즉, x + y의 결과를 a5에 저장합니다. (t1)
- add a2, a5, a2 : a5와 a2를 더한 결과를 a2에 저장합니다. 이는 t1 + z의 결과를 a2에 저장합니다. (t2)
- addi a0, a0, 4 : a0에 4를 더한 결과를 a0에 저장합니다. 이는 x + 4의 결과를 a0에 저장합니다. (t3)
- slli a5, a1, 1 : a1을 왼쪽으로 1비트 시프트합니다. 이는 y * 2의 결과를 a5(t1)에 저장합니다. → a5 = 2y
- add a1, a5, a1 : a5(t1)와 a1을 더한 결과를 a1에 저장합니다. 이는 이전 단계에서 계산된 y2와 y를 더한 결과, 즉 y3을 a1에 저장합니다. → a1 = 3y
- slli a5, a1, 4 : a1을 왼쪽으로 4비트 시프트합니다. 이는 y3 * 16, 즉 y48의 결과를 a5에 저장합니다. (t4)
- add a0, a0, a5 : a0와 a5를 더한 결과를 a0에 저장합니다. 이는 t3 + t4의 결과를 a0에 저장합니다. (t5)
- sub a0, a2, a0 : a2에서 a0를 빼서 그 결과를 a0에 저장합니다. 이는 t2 - t5의 결과를 a0에 저장합니다. 이 최종 결과는 함수의 반환 값이 됩니다.
- ret : 함수의 실행을 종료하고 호출자에게 제어를 반환합니다.
nt t4 = y * 28 → 2**n x k = 48:
y = y x 2 + y = 3y (왼쪽 shift x2)
최대한 수를 2**n x k 형태로 이렇게 해야합니다.
Example: Logical Operation (산술 연산)
- xor a0, a0, a1 : 레지스터 a0와 a1의 값을 XOR 연산합니다.
- XOR 연산의 결과는 a0에 저장됩니다. 이 연산은 두 비트가 다를 때 1을 반환하고, 같을 때 0을 반환합니다.
- 이 단계에서의 결과 t1은 x ^ y입니다.
- srai a0, a0, 17 : a0에 저장된 값을 오른쪽으로 17비트 산술 시프트합니다.
- 산술 오른쪽 시프트는 가장 왼쪽 비트(부호 비트)를 유지하면서 오른쪽으로 이동시키며, 새로 생기는 비트는 부호 비트의 값으로 채워집니다.
- 이 단계에서의 결과 t2는 t1 >> 17입니다.
- andi a0, a0, 249 : a0에 저장된 값과 249(16진수로 0xF9)를 AND 연산합니다.
- AND 연산은 두 비트 모두 1일 때만 1을 반환하고, 그렇지 않으면 0을 반환합니다.
- 이 단계의 연산은 t2 & ((1<<8)-7)과 동일합니다.
- 여기서 ((1<<8)-7)은 256에서 7을 뺀 값, 즉 249(0xF9)와 같습니다.
- 이것은 8비트 값을 기준으로 하위 8비트 중에서 최상위 3비트를 제외한 나머지 비트를 유지하는 연산입니다.
- ret : 함수의 실행을 종료하고 호출자에게 제어를 반환합니다.
RISC-V의 부등식
조건이 참이면 결과를 1로 설정합니다. 그렇지 않으면 0으로 설정합니다.
- slt rd, rs1, rs2로 설정합니다
- if (rs1 < rs2) rd=1; else rd=0;
- slti rd, rs1, constant
- if (rs1 < constant) rd=1; else rd=0;
- 부호가 없는 비교: sltu, sltui
Example
- x8 = FFFFFFFF (if signed: -1)
- x9 = 00000001
- slt x10, x8, x9 #signed
- 1 < +1 → $t0 = 1
- slt x10, x8, x9 #unsigned
- 4,294,967,295 > +1 → $t0 = 0
- slt x10, x8, x9 #signed
Immediate Operands (즉시 피연산자)
Immediate Operands (즉시 피연산자)는 명령어에 지정된 일정한 데이터입니다.
Exampel: addi x3, x4,10 # Ccode: f = g + 10;
- 뺄셈은 즉시 명령이 없습니다. 단지 음의 상수만 사용합니다.
- x3, x4, -10 # C 코드: f = g - 10;
- 피연산자를 최소화할 수 있는 이점이 있습니다.
- 작은 상수가 일반적입니다
- 즉시 피연산자가 load instruction를 피합니다
- 상수 0
- RISC-V 레지스터 0(x0)은 상수 0입니다.
- 그리고 덮어쓸 수 없습니다. add x0, x3, x4는 아무것도 하지 않습니다
Hardware 자체에서 0을 의미 (blackhole) → 의미가 없어집니다.
- 공통 레지스터에 유용합니다
- Example: 레지스터 간 이동으로 예시를 들어보겠습니다.
- add x1, x2, x0 # C code: f = g → register 값 복사시
- add x3, x0, 0xff # C code: f – 0xff;
Sign Extension (부호 확장)
- SignedL w bit → w+k bits
- 주어진 w-비트 부호 정수 x
- 값이 같은 w+k 비트 정수로 변환합니다
- 부호 비트를 왼쪽으로 복제합니다(8비트에서 16비트)
- +2: 0000 0010 → 0000 0000 0000 0010
- -2: 1111 1110 → 1111 1111 1111 1110
- RISC-V 명령어 세트
- 1b: 부호 extend 로드 바이트.
- 1bu: 제로 extended 로드 바이트.
Memory Operands
Memory Operands → 메모리값 연산 & 저장시 사용합니다.
- 복합 데이터에 사용되는 메인 메모리
- 어레이, 구조, 동적 데이터
- 산술 연산을 적용하려면
- 메모리에서 레지스터로 값 로드
- 레지스터에서 메모리로 결과 저장
- 메모리가 바이트 주소로 지정됨: 각 주소는 8비트(바이트)
- RISC-V is Little Endian
- 단어의 최소 의미 바이트 주소
- RISC-V는 다른 ISA와 달리 메모리에 단어를 정렬할 필요가 없습니다. 이유는 무엇일까요?
굳이 aligned 안해도 메모리에 접근이 가능합니다, but, 성능을 위해서 4bit aligned을 해줘야 합니다.
lw → w: load word(단어 단위)
32(x22) → 연산이 의미하는 만큼 offset +
add x9, x21, x9 → 배열(memory)에 저장, at base address (12칸 떨어진 곳)
Byte/Halfword/Word Operations
- Loadbyte / halfword / word:
- 부호는 rd로 32비트로 확장됩니다 → 읽거나 쓰는 단위로 달라집니다.
- Loadbyte / halfword
- 0이 32비트 Ind로 확장됩니다 → memory의 빈 Register에 부호를 저장합니다 (u)
- Storebyte /. halfword / word
- 가장 오른쪽에 8/16/32비트를 저장합니다.
Data Transfer Operations
반응형
'⚙️ Computer Architecture' 카테고리의 다른 글
[Computer Architecture] RISC-V (0) | 2024.07.13 |
---|---|
[Computer_Architecture] Instruction Set (0) | 2024.07.11 |
[Computer_Architecture] Performance Part.2 (0) | 2024.06.24 |
[Computer_Architecture] Performance Part.1 (0) | 2024.06.15 |
[Computer Architecture] Processor, Computer System Organization (0) | 2024.04.18 |