본문 바로가기
Computer Architecture/ISA

[RISC-V] 컴퓨터구조 - Instructions 개요

by FastBench 2024. 3. 9.

2.1 Introduction

컴퓨터에 명령을 하기위해서, 'instruction (명령어)' 라고 불리는 컴퓨터 언어를 사용해야 한다.

해당 명령어들의 집합을 instruction set 이라고 한다.

 

Instruction Set Architecture (ISA) 란 instruction set 이 해당 하드웨어에 적용될 수 있도록 구조와 인터페이스를 설계한 것을 의미한다. 또한 하드웨어의 레지스터 구조, 명령어의 실행방식등도 정의한다.

따라서 컴파일러나 어셈블러가 이 ISA 를 토대로 설계되어

사람이 작성한 고수준언어(C, C++)가 하드웨어에 효율적으로 매핑될 수 있도록 한다. 

 

정리하면, 컴파일러는 사람이 작성한 C나 C++ 같은 코드를 어셈블리어로 변환하는데, 이 어셈블리어가 아래의 표와 같은 Instruction 의 형태로 작성된다.

이번 챕터에서 다룰 명령어(어셈블리어). 실제로는 훨씬 많은 수의 명령어가 존재한다.

어셈블러는 어셈블리어를 ISA 에 정의된 방식으로 0과 1로 이루어진 이진수로 변환한다.

이를 machine code라고 하고, CPU는 이 machine code 를 읽으면서 프로그램을 실행시킨다.

 

2.2 Operations of the Computer Hardware

 

각 RISC-V arithmetic 명령어는 오직 한가지 작업만 수행하고, 정확히 세개의 변수를 가져야만 한다.

아래는 b,c,d,e 의 합을 a에 저장하는 예시이다.

  • a = b+c+d+e
add a, b, c
add a, a, d
add a, a, e

즉, 네개의 변수 합을 구하려면 세개의 명령어가 사용된다.

 

앞으로 확인하겠지만, 덧셈과 같은 연산에 RISC-V 는 정확히 세개의 operands(피연산자)를 요구하는데, 이는 하드웨어 설계를 단순하게 해준다. (피연산자의 갯수가 정해져있지 않고 가변적이면 하드웨어 설계가 매우 복잡해 진다.)

 

  • f=(g+h)-(i+j) 
add t0, g, h
add t1, i, j
sub f, t0, t1

 

2.3 Operands of the Computer Hardware

high level language 와 다르게, 산술 명령어의 피연산자는 반드시 하드웨어에 직접적으로 내장된 레지스터 라는 곳에서 와야만 한다.

 

RISC-V 아키텍처의 레지스터 갯수는 32개로 정해져있지만, 시스템의 타입에 따라 레지스터 사이즈 달라진다.

32비트 시스템이면 레지스터 사이즈도 32비트이다. 64비트 시스템이면 레지스터 사이즈도 64비트이다.

흔히 word 라는 단위는 32비트, 즉 4바이트를 의미하고. double word 는 64비트, 즉 8바이트를 의미한다.

 

앞으로는 명령어를 작성할 때 레지스터 넘버링을 이용하여 단순하게 작성한다. 위에서 본것과는 다르게, 어셈블리 명령어의 피연산자에 변수명은 들어가지 않는다.

 

위 레지스터의 usage 에 대해서는 차차 언급하도록 하고,

  • f=(g+h)-(i+j) 

를 다시 정의해보자.  f,g,h,i,j 가 각각 x19-x23 에 저장되어있다고 가정한다.

add x5, x20, x21 // register x5 contains g + h
add x6, x22, x23 // register x6 contains i + j
sub x19, x5, x6 // f gets x5 – x6, which is (g + h) − (i + j)

 

컴파일러의 역할이지만, 임시적으로 만들어야 하는 변수는 temporaries 레지스터인 x5,x6 에 저장되고

실제 변수들은 saved register 인 x19-x23 에 저장됨을 기대할 수 있다.

 

Memory Operands

프로그램을 하다보면 위와 같은 단일 데이터 요소말고, 배열이나 구조체 같은 자료구조를 사용할 떄도 있다.

당연히 레지스터 갯수는 제한되므로, 메모리를 사용해야 한다.

RISC-V 는 메모리와 레지스터 사이에 데이터를 전달하는 명령어를 가지고 있다. (data transfer instructions)

 

load 라고 불리는 명령어는 '상수' 부분과 두번째 레지스터 값의 합이 메모리 주소를 형성한다.

store 라고 불리는 명령어도 load 와 같은 방식으로 메모리 주소를 형성한다.

 

RISC-V 에서는 각각 lw (load word), sw (store word) 를 명령어 이름으로 사용한다.

  • 명시된 메모리 주소로 부터 32비트(word) 데이터를 레지스터에 로드한다.
  • 명시된 메모리 주소에 32비트(word) 데이터를 레지스터로 부터 저장한다. 

위 예시에서 상수부분은 'offset' 이라고 하고,  메모리 주소를 형성하기 위한  레지스터 (x22)  부분은 base register 라고 한다.

 

하드웨어 측면에서, 메모리에 접근하는 것은 레지스터에 접근하는 것보다 훨씬 오래걸리고 에너지도 많이 소모하므로 컴파일러는 최대한 빈번하게 사용되는 변수들을 레지스터에 유지하기 위해 노력한다.

 

Constant or Immediate Operands

많은 프로그램에서 매우 빈번하게 피연산자로 '상수'를 가지는 경우가 많다.

상수를 메모리에서 가져오는 것보다 명령어에 포함시키는 편이 훨씬 빠르고 에너지를 적게 소모하기 때문에 상수피연산자 명령어는 자주 사용될 수록 좋다.

 

RISC-V 도 상수 명령어를 아래와 같은 방식으로 정의한다.

addi (add immediate) 

addi x22, x22, 4 // 4와 x22의 값을 더하고 x22에 써라

 

또한 RISC-V 의 경우 x0 레지스터를 0으로 hard-wired 시켜놓아서, 다양한 방식으로 응용한다. 0은 프로그램에서 매우 자주 사용되기 때문에 큰 효과를 볼 수 있다.

 

2.4 Signed and Unsigned Numbers

2's complement (2의 보수)를 통해 이진수의 음과 양을 표현할 수 있다.

하드웨어는 오직 MSB 만을 확인함으로써 해당 수가 양인지 음인지 확인할 수 있다. (MSB 는 sign bit 이라고 불린다.)

-2의 31승에 주목하자.

 

메모리로부터 8바이트 데이터를 레지스터로 로드하는 경우를 생각해보자.

  • lb 명령어 : 해당 데이터가 signed 데이터타입으로 지정되어있을 경우, 32비트로 늘릴때 sign bit 로 패딩한다.
  • lbu 명령어 : 만약 unsigned라면 단순히 0으로 패딩한다.

 


Reference

  • Computer Organization and Design - The Hardware Software Interface [RISC-V Edition] 2nd Edition

댓글