앞의 글을 읽으시면 이해에 도움이 됩니다.
2022.09.24 - [Computer Science/컴퓨터 구조] - [컴퓨터 구조] Assembly Language (컴퓨터의 언어 - 어셈블리어)
1. Instruction Format
Instruction은 machine code라고 불리는 binary code로 encoded 됩니다.
모든 명령어는 디자인 규칙에 의하여 32비트로 제한되며, 이 32비트 안에 모든 것을 표현해야 합니다.
이때 명령어를 여러 타입으로 나누어서 표현하게 만들었는데, 이를 Instruction Format이라고 표현합니다.
Instruction Format은 대표적으로 3가지 타입으로 분류됩니다.
- R-Type(Register Type) : most arithmetic and logical instruction (except for "immediate")
- I-Type(Immediate Type) : data transfer (load), arithmetic with Immediate
- S-Type(Store Type) : data transfer (store)
세 타입 모두 인코딩 방식이 다르므로 하나하나 차례대로 알아보겠습니다.
2. R-Type
R-Type은 산술과 논리 연산에 사용되는 instruction format입니다.
32비트 안에 모든 것을 넣었으며, opcode, func3, func7을 통하여 어떤 명령을 수행할지 결정합니다.
rd는 destination register이며, 값을 넣고자 하는 레지스터가 됩니다.
rs1은 첫 번째 source가 되는 register입니다.
rs2은 두 번째 source가 되는 register입니다.
register에 해당하는 bit가 모두 5비트인 것은 레지스터의 개수가 32개이기 때문입니다.
따라서 opcode, func3, func7을 통하여 어떤 명령을 할지 결정하고,
해당 명령을 rs1, rs2에 적용하여 rd에 저장합니다.
예를 들어서
add x9, x20, x21이라는 어셈블리어가 있다면, 이는 곧 x9 = x20 + x21이 됩니다.
R-Type으로 표현하면
- func7 : 0
- func3 : 0
- opcode : 0110011
- rd : 01001
- rs1 : 10100
- rs2 : 10101
이 됩니다.
따라서 해당 명령어는
이렇게 표현됩니다.
3. I-Type
I-Type은 load 혹은 constant 연산을 위해 존재하는 instruction format입니다.
R-Type과는 다르게 rs1만 존재합니다.
immediate 비트는 총 12개이며, 여기에 상수 혹은 offset이 들어가게 됩니다.
만약 load로 명령어를 사용하게 된다면, rs1에 있는 base address에 imm 값(offset)을 더하여 rd에 값을 넣게 됩니다.
혹은 addi(add immediate)를 사용하게 된다면, rs1에 있는 source에 imm 값을 더하여 rd에 넣게 됩니다.
여기서 나오는 Design Principle 3이 있습니다.
Design Principle 3 : Good design demands good compromises
좋은 설계를 위하여 적절한 타협이 필요하다는 뜻입니다.
비록 다른 format이어도 32비트는 유지해야 하며, format을 가능한 한 비슷하게 만들어야 합니다.
그렇기 때문에 R-Type의 rs2와 func7이 합쳐져서 I-Type의 immediate가 된 것입니다.
근데 imm은 최대 12비트기 때문에 32비트의 숫자를 처음부터 덧셈을 하려면 어떻게 해야할까요?
addi를 여러 번 사용해야 할까요?
이를 위한 명령어는 향후 lui 글에서 적도록 하겠습니다.
2022.10.21 - [Computer Science/컴퓨터 구조] - [컴퓨터 구조] for Wide Immediate Operands : lui
4. S-Type
S-Type은 Store을 위한 Instruction Format입니다.
해당 format을 보면 R-Type, I-Type에 있던 rd 자리에 imm[4:0]이 들어간 것을 볼 수 있습니다.
이는 위의 design principle 3에 의한 내용입니다.
imm[11:5]와 imm[4:0]이 합쳐져서 하나의 offset을 만듭니다.
이는 rs1, rs2의 field를 동일하게 나두기 위함과, opcode, func3를 동일한 위치에 놓기 위해 쪼개 놓았습니다.
rs1은 저장 공간의 base address입니다.
rs2는 저장할 값이 있는 register입니다.
따라서 rs2에 있는 값을 rs1 + imm[11:5] + imm[4:0]에 넣는다고 보면 될 것 같습니다.
5. Logical Operations
위와 같은 산술 연산, data transfer operation을 제외하고 논리 연산을 위한 명령어가 존재합니다.
shift left에서 sll, slli로 나뉘어 있는데, sll은 R-Type으로 rs2에 얼마 정도 옮길지의 값이 저장되어 있습니다.
근데 보통은 slli로 사용한다고 하네요.
아무튼 slli를 보면 특이합니다.
기존의 I-Type과는 다른 형태를 가지고 있습니다.
I-Type은 imme를 위해 12비트를 할당했습니다.
하지만 저희는 32 bit가 word이기 때문에 사실 31번 이상 shift를 하는 것은 의미가 없습니다.
그렇기 때문에 imme 비트는 5개로 제한하고, 남은 비트를 func으로 재활용합니다.
그런데 보면 재활용된 비트를 보면 func7이 아닌 func6입니다.
이거는 제가 교수님한테 여쭤본 내용이긴 한데, 교수님도 헷갈리신다고 나중에 말씀드린다고 하셨어요.
근데 알아보니까 64 비트와 호환하기 위해서 imme bit를 6개로 두기 때문에, func6이 된다고 나와 있더라고요
사실 뒤에서 살펴보겠지만, multiplication 연산 같은 경우에는 32 bit를 기준으로 연산을 한다 하더라도, 곱셈의 결과는 최대 64 bit가 나오게 되고, 이때 64 bit shift가 일어나게 됩니다.
그렇기 때문에 호환을 위해 imme bit를 6비트로 두고, 남은 6개의 비트를 func6에 넣은 것 같습니다.
이건 자세한 내용을 들으면 아래에 다시 적도록 하겠습니다.
아무튼 위에 표를 보면 Shift right Arithmetic, Bit-by-bit NOT 연산만 네모가 쳐져있습니다.
sra, srai 연산은 오른쪽으로 shift 함과 동시에 Sign Extension이 일어납니다.
Sign extension은 비트가 확장되거나, shift 될 때, 최상위 비트로 왼쪽을 채워줍니다.
만약 뭔 소린지 모르겠으면 2의 보수를 검색하는 게 이해에 도움이 될 것 같습니다.
NOT 연산은 사실 RISC-V에서 공식적으로 지원하는 명령어가 아닙니다.
NOT 연산은 사실 XOR 연산을 통하여 연산을 수행합니다.
x9에 있는 비트를 NOT 하고 싶다면,
xor x9, x9, "111...1111"을 하면 NOT이 됩니다.
XOR은 비트가 같다면 0, 다르다면 1로 변환해주기 때문에, 모든 비트가 1인 값을 XOR 해준다면 x9의 값이 NOT이 되는 효과가 있습니다.
감사합니다.
다음 글에는 decision을 위한 instruction에 대해 알아보겠습니다.
2022.10.21 - [Computer Science/컴퓨터 구조] - [컴퓨터 구조] Decision Instruction
지적 환영합니다.
'Computer Science > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] Procedure call, jal, jalr (프로시저 콜을 위한 명령어들) (2) | 2022.10.21 |
---|---|
[컴퓨터 구조] Decision Instruction (4) | 2022.10.21 |
[컴퓨터 구조] RISC-V 명령어 작동 과정 (RISC-V Instruction Operation Process) (3) | 2022.10.01 |
[컴퓨터 구조] Assembly Language (컴퓨터의 언어 - 어셈블리어) (0) | 2022.09.24 |
[컴퓨터 구조] Introduction to Computer Architecture (컴퓨터 구조의 소개) (0) | 2022.09.23 |