2.2 Operations of the Computer Hardware
-RISC-V Register 종류
-RISC-V assembly language
-Compiling Two C Assignment Statements into RISC-V
왼쪽은 어셈블리어, 주석은 c언어이고, 같은 의미이다.
ex1)
add a, b, c //a = b + c;
sub d, a, e //d = a - e;
ex2) 다음과 같은 c언어 수식은 어셈블리어로 어떻게 변환될까?
f = (g + h) - (i + j)
이렇게 변환된다.
add t0, g, h
add t1, i, j
sub f, t0, t1
실제로 g,h,i,j 같이 알파벳을 사용하진 않고, 그 값이 들어있는 레지스터를 이용해 연산한다. (보기 좋게 표현한 것.)
- C / JAVA / Assembly 중 가장 많은 코드 라인을 가지는 언어는 무엇일까?
Assembly -> C -> JAVA 순으로 많은 라인을 가진다.
높은 수준의 언어일수록 라인의 수가 적다. (추상화 수준에 따른 결과)
2.3 Operands of the Computer Hardware
- Compiling a C Assignment Using Registers
위에서 살펴본 f = (g + h) - (i + j)를 레지스터를 사용해 어셈블리어로 바꿔보자.
f -> x19
g -> x20
h -> x21
i -> x22
j -> x23
temporary register -> x5, x6
add x5, x20, x21 // x5 = g + h
add x6, x22, x23 // x6 = i + j
sub x19, x5, x6 // f = x5 - x6
- Compiling an Assignment When an Operand Is in Memory
만약 A가 크기 100의 배열이고 시작주소가 x22에 담겨있고,
g는 x20, h는 x21에 담겨있다면,
g = h + A[8];
는 어셈블리어로 어떻게 표현할 수 있을까?
답은 다음과 같다.
//A의 시작주소인 x22에서 8번쨰 값을 임시레지스터 x9에 넣는다.
lw x9, 8(x22)
add x20, x21, x9 //g = h + A[8];
배열의 값을 lw로 불러온 뒤 연산해주면 된다.
다음은 RISC-V 메모리구조이다.
메모리 주소는 대부분 바이트 단위로 지정되며,
대부분의 아키텍쳐는 8비트(바이트) 단위로 데이터를 관리한다.
위 그림과 같이 연속된 데이터는 주소가 4씩 차이난다. (word)
- Little Endian / Big Endian
컴퓨터는 바이트 주소를 처리하는 방식에 따라 두 종류로 나뉜다.
Little Endian : 주소로 가장 오른쪽의 바이트를 사용하는 방식
Big Endian : 주소로 가장 왼쪽의 바이트를 사용하는 방식
RISC-V 는 Little Endian 방식을 사용한다.
- Compiling Using Load and Store
h가 x21에 저장되어있고, A의 시작주소가 x22일 때 아래의 c코드는 어셈블리어로 어떻게 변환될까?
A[12] = h + A[8];
답
//임시레지스터 x9에 A[8]로드. 8*4=32
lw x9, 32(x22)
add x9, x21, x9 //x9 = x9 + A[8]
sw x9, 48(x22) //A[12]에 x9(h + A[8]) 저장
2.4 Signed and Unsigned Numbers
- MSB / LSB
MSB(Most Significant Bit)
RISC-V 워드에서 가장 왼쪽에 있는 비트를 의미, 일반적으로 비트 31번으로 표기된다.
LSB(Least Significant Bit)
RISC-V 워드에서 가장 오른쪽에 있는 비트를 의미, 일반적으로 비트 0번으로 표기된다.
-two’s complement binary representations
음수를 표현하기 위해 과거에 다양한 방법을 사용해봤지만, 단점이 많았다.
더 나은 대안으로 2의 보수 표현이 사용되었다.
가장 왼쪽의 비트가 1이면 음수, 0이면 양수로 판단하는 표현 방식이다.
가장 왼쪽의 비트만 확인하면 수가 양수인지 음수인지 판별할 수 있기 때문에 효과적이다.
아래는 이진수를 십진수로 변환하는 과정이다.
결과에서 알 수 있듯, MSB가 1이므로 음수이므로 위의 그림처럼 계산할 수도 있고,
2의 보수를 취한 뒤 1을 빼주는 방식으로도 계산할 수 있다.
만약 구하는 수가 양수라면 2의 보수를 취한 뒤 1을 더해주면 된다.
이래는 2의 보수를 이용한 방법의 옛
2.5 Representing Instructions in the Computer
Translating RISC-V Assembly Language into Machine Language
//c code
A[30] = h + A[30] + 1;
//assembly code
//x21->h
//base of the array A -> x10
lw x9, 120(x10)
add x9, x21, x9
addi x9, x9, 1
sw x9, 120(x10)
2.6 Logical Operations
-명령어들
slli x11, x19, 4 // 레지스터 x19를 4비트 왼쪽으로 시프트하고 결과를 x11에 저장
and x9, x10, x11 // 레지스터 x10과 x11의 비트를 AND 연산하여 결과를 x9에 저장
or x9, x10, x11 // 레지스터 x10과 x11의 비트를 OR 연산하여 결과를 x9에 저장
xor x9, x10, x12 // 레지스터 x10과 x12의 비트를 XOR 연산하여 결과를 x9에 저장
-Which operations can isolate a field in a wor?
1. AND : 특정 비트를 선택적으로 남기기 위해 사용하는 마스킹 기법
2. A shift left followed by a shift right : 불필요한 비트를 밀어낸 뒤 다시 오른쪽으로 쉬프트한다.
두 가지 방법 모두 워드 내에서 특정 필드를 추출하거나 고립시키는데 사용할 수 있다.
2.7 Instructions for Making Decisions
-Compilling if-then-else into Conditional Branches
//c code
if(i == j) f = g + h;
else f = g - h;
//assembly code
// f(x19), g(x20), h(x21), i(x22), j(x23)
bne x22, x23, Else //goto Else if x22!=x23
add x19, x20, x21 //f = g + h; x22=x23일 떄
beq x0, x0, Exit //end of the if statement
Else:sub x19, x20, x21 //else f=g-h;
Exit:
-Compilling a while Loop in C
//c code
while (save[i] == k)
i += 1;
//assembly code
//i(x22), k(x24), save(x25)
Loop slli x10, x22, 2 //임시레지스터 x10 = i*4
add x10, x10, x25 //x10 = save[i]주소
lw x9, 0(x10) //임시레지스터 x9 = save[i]
bne x9, x24, Exit //같지않으면 끝
addi x22, x22, 1 //같으면 i+=1 하고 루프
beq x0, x0, Loop
Exit:
-Question
1. C는 많은 명령어들을 가지고 있지만 RISC-V는 적다.
- 더 많은 명령어는 코드 읽는것과 이해를 쉽게 만든다 (ㅇ)
- 적은 명령어가 실행을 책임지는 하위 레이어의 일은 단순화한다 (ㅇ)
- 명령어가 많다는 것은 적은 코드 길이가 작다는 것을 의미한다 (ㅇ)
2. C에서는 AND, OR 가 제공되지만 RISC-V에는 없다. 왜?
- 논리 연산 AND와 OR은 &와 |를 구현하고, 조건 분기는 &&와 ||을 구현한다.
2.8 Supporting Procedures in Computer Hardware
프로그램은 아래 6가지 단계를 따른다.
1. 매개변수를 적절한 위치에 배치한다.
2. 프로그램의 흐름을 procedure로 전달.
3. 필요한 저장공간을 확보한다.
4. 작업을 수행.
5. 결과값을 호출 프로그램이 접근 가능한 곳(레지스터, 메모리 등) 에 배치.
6. 제어를 원래 위치로 반환한다.
-레지스터의 용도
x10~x17 : return value를 저장하는 레지스터
x1 : return address를 저장하는 레지스터
-jal ( jump-and-link instruction) 사용법
//ProcedureAddress로 점프하고 x1에 return address를 넣어둠
jal x1, ProcedureAddress
-jalr (jump-and-link register) 사용법
//x1레지스터에 담겨있는 주소로 점프한다.
//이때 x0는 반환 주소를 무시하도록 설정되어있다.
jalr x0, 0(x1)
-PC(Program Counter)
컴퓨터에서 현재 실행중인 명령어를 저장하는 레지스터
RISC-V에서는 다음에 실행할 명령어의 주소를 가리킨다.
-Compilling a C Precedure That Doesn't Call Another Procedure
//c code
int leaf_example (int g, int h, int i, int j){
int f;
f = (g + h) - (i + j);
return f;
}
//assembly code
//g(x10), h(x11), i(x12), j(x13), f(x20)
leaf_example:
addi sp, sp, -12 // 스택 포인터 조정하여 3개의 항목을 위한 공간 확보
sw x5, 8(sp) // 레지스터 x5를 스택에 저장
sw x6, 4(sp) // 레지스터 x6를 스택에 저장
sw x20, 0(sp) // 레지스터 x20을 스택에 저장
add x5, x10, x11 // 레지스터 x5에 g + h 저장
add x6, x12, x13 // 레지스터 x6에 i + j 저장
sub x20, x5, x6 // 레지스터 x20에 (g + h) - (i + j) 저장
addi x10, x20, 0 // 반환 값 f를 x10에 저장 (x10 = x20 + 0)
lw x20, 0(sp) // 레지스터 x20 복원
lw x6, 4(sp) // 레지스터 x6 복원
lw x5, 8(sp) // 레지스터 x5 복원
addi sp, sp, 12 // 스택 포인터를 조정하여 할당된 3개의 항목 삭제
jalr x0, 0(x1) // 호출 루틴으로 돌아가기 위해 x1에 저장된 주소로 분기
아래 그림은 위 어셈블리 코드 과정에서의 스택 상태를 보여준다.
스택 포인터가 스택의 상단을 가리키고 있다가
3칸을 할당받아 x5, x6, x20의 값을 저장하고
스택 포인터가 호출 전 위치로 돌아간다.
이후 x5, x6의 값을 보존할 필요가 없으니 L/S 과정을 생략해도 딱히 상관없다.
(임시 레지스터이기 때문)
맨 위의 레지스터 표를 보면 알 수 있다.
-Compilling a Recursive C Procedure, Showing Nested Procedure Linking
//c code
int fact (int n){
if(n<1) return (1);
else return (n * fact(n - 1));
}
//assembly code
fact:
addi sp, sp, -8 // 2개의 항목(8바이트)을 저장하기 위해 스택을 조정
sw x1, 4(sp) // 반환 주소를 스택에 저장
sw x10, 0(sp) // 매개변수 n을 스택에 저장
addi x5, x10, -1 // x5 = n - 1
bge x5, x0, L1 // (n - 1) >= 0이면 L1으로 이동
addi x10, x0, 1 // 반환 값 1을 x10에 저장
addi sp, sp, 8 // 스택에서 2개의 항목을 팝
jalr x0, 0(x1) // 호출자에게 반환
L1:
addi x10, x10, -1 // n >= 1: n을 n - 1로 감소
jal x1, fact // fact(n - 1) 호출
addi x6, x10, 0 // fact(n - 1)의 결과를 x6에 저장
lw x10, 0(sp) // 이전 매개변수 n 복원
lw x1, 4(sp) // 반환 주소 복원
addi sp, sp, 8 // 스택에서 2개의 항목을 팝
mul x10, x10, x6 // n * fact(n - 1)을 계산하여 x10에 저장
jalr x0, 0(x1) // 호출자에게 반환
- 프로시저 호출 시 보존되는 것과 보존되지 않는 것
- 스택 할당의 과정
만약 로컬변수가 스택에 존재하지 않는다면 컴파일러는 fp를 사용하지 않는다.
위의 예시에서도 프레임 포인터의 사용을 피했다.
- The RISC-V memory allocation for program and data
스택과 힙은 반대 방향으로 성장한다.
스택은 정해진 크기의 블럭이 순서대로 할당되고
힙은 프로그램의 요청에 따라 크기를 동적으로 확장하거나 축소한다.
장점
1. stack에서 사용하지 않는 공간을 heap에서 사용하는 등 유연한 사용이 가능하다.
2. stack pointer / heap pointer은 서로 반대방향을 향하므로
만약 두 포인터가 충돌한다면 메모리가 부족하다는 것을 알 수 있다.
C언어에서는 malloc을 통해 메모리를 할당하고 free를 통해 할당을 해지하는데
만약 free를 안해주게 되면 시스템 메모리가 점점 고갈되는 메모리 누수가 발생할 수 있고,
할당을 해지한 다음 접근하려 할때는 프로그램 충돌(Dangling pointer)가 발생할 수 있다.
아래 그림의 RISC-V레지스터의 용도에 맞게 잘 사용하도록 하자.
2.9 Communicating with People
- RISC-V 의 바이트 조작 명령어
lbu x12, 0(x10) // 소스에서 바이트를 읽어 x12에 저장
sb x12, 0(x11) // x12의 바이트를 목적지에 저장
- Compilling a String Copy Procedure, Showing How to Use C Strings
//c code
void strcpy (char x[], char y[])
{
size_t i;
i = 0;
while ((x[i] = y[i]) != ‘\0’) /* copy & test byte */
i += 1;
}
//assembly code
//x(x10), y(x11), i(x19)
addi sp, sp, -4 // 1개의 항목(4바이트) 저장을 위해 스택 조정
sw x19, 0(sp) // 레지스터 x19를 스택에 저장
add x19, x0, x0 // i = 0 + 0
L1:
add x5, x19, x11 // y[i]의 주소를 x5에 저장
lbu x6, 0(x5) // x6 = y[i]
add x7, x19, x10 // x[i]의 주소를 x7에 저장
sb x6, 0(x7) // y[i] 값을 x[i]에 저장
beq x6, x0, L2 // y[i]가 0이면 L2로 이동하여 종료
addi x19, x19, 1 // i = i + 1
jal x0, L1 // L1로 이동하여 루프 반복
L2: lw x19, 0(sp) // 이전 x19 복원
addi sp, sp, 4 // 스택에서 1개의 항목 팝
jalr x0, 0(x1) // 호출자로 복귀
2.10 RISC-V Addressing for Wide Immediates and Addresses
- Loading a 32-Bit Constant
//32비트 상수를 로드하기 위해 먼저 상위 20비트를 로드한다.
lui x19, 976 // 976 (10진수) => 0000 0000 0011 1101 0000
//x19에 들어있는 값
0000 0000 0011 1101 0000 0000 0000 0000
//이후 하위 12비트를 x19에 로드한다.
addi x19, x19, 1280 // 1280 (10진수) => 0101 0000 0000
//최종 x19에 들어있는 값
0000 0000 0011 1101 0000 0101 0000 0000
- Addressing in Branches
RISC-V 명령어는 12비트 immediate를 사용하여 브랜치 주소를 나타낸다.
따라서, 주소는 항상 짝수여야 한다.
SB type 명령어는
7bit opcode
3bit func3
5bit register (rs1, rs2)
12bit immediate
로 구성되어있다.
ex)
bne x10, x11, 2000
0011111 | 01011 | 01010 | 001 | 01000 | 1100111 |
imm[12:6] | rs2 | rs1 | funct3 | imm[5:1] | opcode |
ex)
jal x0, 2000
00000000001111101000 | 00000 | 1101111 |
imm[20:1] | rd | opcode |
-PC-relative addressing
PC의 값을 기준으로 분기할 주소를 계산하는 방식이다.
최대 2^32의 크기까지 확장될 수 있다는 장점이 있고,
이를 통해 조건부 분기에서 주소 크기 문제를 해결할 수 있다.
PC = Register + Branch offset
jal은 20비트 imm을 사용하기 때문에 상대적으로 넓은 범위로 이동할 수 있고
lui와 jalr을 같이 사용하면 더 멀리 점프할 수 있다.
분기 명령어는 2바이트 단위로 거리를 표현하고
이를 통해 더 많은 범위를 커버할 수 있다.
-Showing Branch Offset in Machine Language
Loop:slli x10, x22, 2 // Temp reg x10 = i * 4
add x10, x10, x25 // x10 = address of save[i]
lw x9, 0(x10) // Temp reg x9 = save[i]
bne x9, x24, Exit // go to Exit if save[i] != k
addi x22, x22, 1 // i = i + 1
beq x0, x0, Loop // go to Loop
Exit:
이때 각 instruction과 address는 이렇다. (명령어가 메모리 80000부터 시작하고 각 명령어는 4바이트씩 차지)
• 80000: 0000000 00010 10110 001 01010 0010011
• 80004: 0000000 11001 01010 000 01010 0110011
• 80008: 0000000 00000 01010 011 01001 0000011
• 80012: 0000000 11000 01001 001 01100 1100011
• 80016: 0000000 00001 10110 000 10110 0010011
• 80020: 1111111 00000 00000 000 01101 1100011
조건부 분기와 무조건 점프는 S,U 타입이지만,
이들은 실제로 SB, Uj 타입이라고 불린다.
이는 어셈블러 작성을 더 복잡하게 할 수 있지만,
하드웨어 설계를 좀 더 단순하게 해준다.
- Branching Far Away
//조건부 분기 명령어는 제한된 분기 범위를 가지고 있다.
//그래서 아래와 같이 두 개의 명령어를 같이 사용하면 더 먼거리로 분기할 수 있다.
bne x10, x0, L2
jal x0, L1
- four RISC-V Addressing Mode
1. Immediate addressing
상수값을 연산에 사용한다.
ex) addi
2. Register addressing
피연산자가 레지스터에 있는 경우
ex) add
3. Base addressing
피연산자가 메모리 위치에 있으며 이 위치는 레지스터 값과 즉시 값의 합으로 계산된다.
ex) lw
4. PC-relative addressing
분기할 주소는 PC와 immediate의 합으로 결정된다.
ex) beq
Question
1. What is the range of byte addresses for conditional branches in RISC-V?
12비트 주소는 -2^11 ~ 2^11-1 까지 나타낼 수 있으므로
현재 위치 기준으로 2KB전후이다.
2. What is the range of byte addresses for the jump-and-link instruction in RISC-V?
jal명령어는 20비트 immediate 를 가지므로 -2^19 ~ 2^19-1까지 나타낼 수 있다.
현재 위치 기준으로 512KB 전후이다.
Design Principle 1: Simplicity favors regularity.
Design Principle 2: Smaller is faster.
Design Principle 3: Good design demands good compromises.
'Book > COMPUTER ORGANIZATION AND DESIGN RISC-V' 카테고리의 다른 글
4. The Processor(4.1~4.5) (1) | 2024.10.10 |
---|---|
2. Instructions:Language of the Computer(2.11~2.14, 2.23, 2.25) (6) | 2024.10.06 |
Operations (1) | 2024.10.05 |
Computer Organization And Design RISC-V Chapter 1. Exercise (0) | 2024.09.20 |
1. Computer Abstactions and Technology (1.7 ~ 1.14) (2) | 2024.09.18 |