RISC-V ISA
사람이 내린 명령어는 컴퓨터 내부에서 숫자의 연속으로 저장된다. 숫자들이 모여 명령어로 해석되며 RISC-V에서는 32bit 고정된 명령어 길이를 갖는다. 명령어 길이를 모두 동일하게 고정하고, 명령어 종류에 따라 형식은 다르게 설정하였다. 대략 6개 타입으로 분류할 수 있다.
R Type
Arithmetic
3개의 operand를 가지고 있다. 예를 들어 add a, b, c라는 명령어는 b와 c의 레지스터에 저장된 값을 더해서 a에 저장하라는 의미이다. RISC-V의 Arithmetic 명령어는 메모리에 있는 데이터를 직접 사용하지 않는다. 그 이유는 당연하게도, 레지스터에서 값을 가져오는 게 훨씬 빠르기 때문이다.
예를 들어, a = b + c + d - e;라는 C언어를 어셈블리어로 표현해보면 아래와 같다.
add x10, x1, x2
add x10, x10, x3
sub x10, x10, x4
Shift
워드 내 모든 비트를 왼쪽이나 오른쪽으로 이동시키는 명령어를 말한다.
- SLL, SRL : rs1을 rs2 만큼 shift하는 명령어, 이동 후 남은 자리는 0으로 채워준다.
- SRA : rs1을 rs2만큼 shift하는 명령어는 위와 같은데, sign-extended 상태로 이동한다. 즉, 부호 bit은 유지한채로 이동한다.
Compare
말 그대로 비교 연산자이다.
- SLT : rs1 < rs2이면 rd = 1, 아니면 rd = 0
Logical Bitwise
AND, OR, XOR이 있다.
I Type
만약에 상수 값을 사용하고 싶으면 어떻게 하면 될까? 위의 R Type와 거의 비슷하다. 만약에 아래와 같이 4를 더하고 싶다고 해보자.
var1: .dword 4
...
ld x9, var1(x3)
add x22, x22, x9
그러면, 아래처럼 간단하게 표현할 수 있다. 이 방법은 메모리 액세스를 추가로 하지 않아도 되기 때문에 훨씬 빠르다.
addi x22, x22, 4
I Type의 형식은 아래와 같다.
12비트 immediate에 상수를 표현한다. 이때, sign-extended이므로 -2048에서 +2047까지 표현할 수 있다. 예를 들어서, addi x15, x1, -50은 아래처럼 표현할 수 있다. sign-extended 된 Immediate에 주목해서 확인해야 한다.
위에서 risc-v에서 arithmetic 연산은 메모리에서 직접 값을 가져오지 않고 레지스터를 사용한다고 했다. 그러나, 레지스터에 저장할 수 있는 크기는 한정되어 있기 때문에, 필요할 때마다 메모리에 저장된 값을 레지스터에 올려야 한다. 이때 사용하는 명령을 load라고 한다.
S Type
load하는 명령어 종류를 I type이라고 했다면 반대로 레지스터 값을 메모리에 저장하는 명령어도 있을 것이다. 이를 Store라 하고 S type에 속한다.
SB Type
C언어에서 if-else문, for문이 이 타입에 속한다. 조건에 따라 이동하는 타입과 조건 없이 이동하는 타입으로 나눌 수 있다.
- conditional branch : beq, bne, blt, bge
- unconditional branch : jump
Conditional Branch
beq는 'branch if equal'를 의미하고 rs1과 rs2가 같으면 label에 해당하는 문장으로 가라는 뜻이다.
beq rs1, rs2, label
bne는 'branch if not equal'이라는 뜻으로, rs1과 rs2가 같지 않으면 label에 해당하는 문장으로 가라는 뜻이다.
bne rs1, rs2, label
label 값은 12비트 immediate로 표현된다. 부호를 표현해야 하기 때문에 -2^11 에서 +2^11-1까지 표현할 수 있다.
그렇다면, 조건에 맞춰서 label 값으로 이동한다고 하자. 어떻게 label에 해당하는 주소로 이동할 수 있을까? label이 immediate로 표현된다고 했는데, 이 필드를 PC의 offset 값으로 사용한다. Branch는 프로그램의 흐름을 바꾸는데 주로 사용하는데, 반복문처럼 작은 범위의 코드에서 많이 사용된다. 코드들은 메모리에서 같은 영역에 저장되기 때문에 흐름을 바꾸는 것도 그 주변 흐름으로 이동한다. 언급한 것처럼, 12bit immediate이기 때문에, -2^11 ~ 2^11-1 사이의 주소 값으로 이동할 수 있다. 즉, 주소 이동 자체를 byte 단위가 아닌 'word' 단위로 한다는 것이다. 명령어는 32bit 길이를 가지기 때문에 주소는 항상 4의 배수로 지정된다. 예를 들어서 분기하지 않으면 PC+4로 이동하고 분기하면 PC + (immediate * 4)값으로 이동한다.
아래 예시를 보면, immediate에 1bit가 추가된 것을 확인할 수 있다. bne x10, x11, 2000이라 하면 2000 * 2bytes로 계산하는 것이다. 2000 * 4bytes 해야하는 것 아닌가?라고 생각할 수 있다. RISC-V에서는 2 byte instruction을 설계하고 싶었기 때문에, 2의 배수를 2진수로 표현했을 때, 마지막에 항상 0이 오기 때문에 이런식으로 표현한 것이다.
만약에 코드 중 일부의 위치를 이동하면 immediate 값이 어떻게 될까? 당연히 바뀐다. 그러면 function 자체를 이동하면 immediate 값은 바뀌지 않는다. 왜냐하면 PC값에 의존하고 있기 때문이다.
U Type
위에서 프로그램의 흐름을 변경하려면 -2^11에서 +2^11-1 까지 이동할 수 있다고 언급했다. 그 이상 혹은 그 이하로 이동하고 싶으면 어떻게 해야 하지? 라는 생각이 들 수 있다. 그래서 RISC-V는 12번째부터 31번째 bit까지 20bit 상수값을 집어 넣는 lui(Load Upper Immediate)라는 명령어를 제공한다. 맨 오른쪽 12bit는 0으로 채워진다. 이 명령어를 이용하면 명령어 2개로 32bit 상수를 만들 수 있다.
예를 들어서 레지스터 x19(64bit)에 32bit를 채운다고 해보자. x19에는 아래와 같은 값이 저장되어 있다.
00000000 00000000 00000000 00000000 00000000 00111101 00000101 00000000
lui x19, 976을 하면 아래와 같이 레지스터 값이 바뀐다.
00000000 00000000 00000000 00000000 00000000 00111101 00000000 00000000
976을 이진수로 표현하면 0000 0000 0011 1101 0000이기 때문에 이를 12비트~31비트 자리에 채우고 나머지는 0으로 채워준다. 그 다음 addi x19, x19, 1280을 하면 아래처럼 바뀐다.
00000000 00000000 00000000 00000000 00000000 00111101 00000101 00000000
1280을 이진수로 표현하면 00000101 0000000이므로, 0~11비트까지 채워주면 된다.
UJ Type
jump & link 타입을 말하는데, 이는 조건 없이 다음 명령여의 주소를 x1 레지스터에 저장한다. 그래서 함수에서 값이 반환되면 x1 레지스터에 저장된 주소로 이동한다. jal 명령어가 호출되면 항상 x1 레지스터에 다음 명령어 주소 값을 저장해야 한다. jarl이라는 명령어를 사용해서 32bit 주소 이동을 하게 할 수 있다.
lui를 사용해서 12부터 31번째 비트 값을 임시 레지스터에 저장하고, jalr을 사용해서 아래 12bit 값을 레지스터에 저장해서 이동한다.
beq x10, x12, L1
lui x9, L1_U20
addi x9, x9, L1_L12
bne x10, x12, L2
jalr x0, 16(x9)
L2:
정리
Addressing Mode
- immediate addressing
- Register addressing
- Base addressing
- PC-relative addressing
PC-relative Addressing
branch, jump 명령어들은 모두 PC 값을 기준으로 위 아래로 일정한 크기만큼 이동할 수 있다는 것을 기억해야 한다.
'CS > 컴퓨터구조' 카테고리의 다른 글
[컴퓨터구조] 2-4. Linking (1) | 2024.12.18 |
---|---|
[컴퓨터구조] 2-3. Calling Convention (0) | 2024.12.18 |
[컴퓨터구조] 2-1. General Instruction Set Architecture (0) | 2024.10.23 |
[컴퓨터구조] 1. Computer Architecture (1) | 2024.10.22 |