[컴퓨터구조] 2-1 Instruction

strn18·2024년 1월 4일

컴퓨터구조

목록 보기
2/4

ISA(Instruction Set Architecture)

컴퓨터에서, 하드웨어는 소프트웨어의 playground와 같다. 이러한 하드웨어는 정의된 instruction만 이해할 수 있는데, 소프트웨어의 언어가 instruction set을 통해서 하드웨어가 이해할 수 있도록 바뀌게 된다.

우리는 RISC-V ISA를 사용할 것.

Stored program

Instruction은 바이너리 파일로 표현되며, 이는 마치 데이터처럼 메모리에 저장된다. 프로그램이 데이터처럼 취급되어 메모리에 저장되는 것. 즉, 메모리에는 1) instruction 2) data 가 저장된다. 이때, 어떠한 instruction을 메모리로부터 읽기 위해 그것의 주소가 필요하다. 메모리의 해당 주소를 읽어서 그 instruction을 실행할 수 있는 것.

32-bit 컴퓨터의 메모리 크기는?
=> 32비트로 표현될 수 있는 메모리 주소는 2322^{32} 가지이다(0x00000000 ~ 0xFFFFFFFF). 이때, 각 주소는 byte addressing으로, 각 주소 당 한 바이트의 데이터가 담긴다. 그러므로 메모리의 총 크기는 2322^{32} 바이트 = 4GB이다.

Program counter

Program counter(PC)는 컴퓨터가 실행할 instruction의 주소가 담기는 레지스터이다. 가령 PC 값이 0x10144라면, 메모리의 0x144라는 주소에 저장되어있는 instruction을 실행하게 되고, 그런 다음 PC를 업데이트하여 다음 instruction을 실행하게 된다. 이때 PC는 일반적으로 4씩 증가하게 된다. 왜냐? 32비트 체제에서 instruction은 하나 당 32비트 = 4바이트이고, 어떠한 주소에는 1바이트가 담긴다고 했으므로, 주솟값을 4씩 증가시켜야 다음 instruction을 실행할 수 있다. 0x10144, 0x10148, 0x1014C, ... 이렇게 증가하면서 instruction을 순차적으로 실행하게 된다. 이때, PC가 4씩 증가하지 않는 경우가 있는데, branch와 같이 조건 분기가 발생하면 instruction을 순차적으로 실행하지 않고 뒤로 되돌아가거나 건너뛰거나 하게 됨.

Instruction

add instruction은 다음과 같은 형태이다.

add a, b, c

add: 실행할 operation
a: destination operand
b, c: source operand

b와 c의 값을 더해 a에 할당한다. 즉 a = b + c 와 유사하다고 볼 수 있음.

대부분의 instruction은 이와 비슷한 형태이다. 이는 ISA 디자인 원칙에 의한 것으로,

  1. Simplicity favors regularity
  2. Make the common case fast
  3. Smaller is faster
  4. Good design demands good compromises

이 중에서 1번에 해당함. 다양한 instructions가 모두 비슷한 형식을 가지도록 하여 simplicity를 확보하고, simpler hardware를 사용하여 성능을 높일 수 있다.

Instruction의 operand(위의 예시에서 a, b, c)가 저장되는 위치는 3가지이다.

  • Registers
  • Memory
  • Constants(Immediates)

Registers

레지스터란? 데이터가 저장될 수 있는 hardware로, 빠르게 access할 수 있는 대신 size는 매우 작다. RISC-V에서는 32비트 레지스터가 32개 존재하고(32 * 32 register file), 각 레지스터를 x0 ~ x31이라는 register number로 지칭할 수도 있고, zero(항상 상수 0이 담김), ra(return address), sp(stack pointer), ... 라는 ABI name(레지스터의 usage에 맞게 이름을 붙인 것)으로 지칭할 수도 있다.

add x8, x9, x18

이 instruction은 x9와 x18 레지스터의 값을 더해서 x8 레지스터에 할당하라는 것을 의미한다.

Constants

a = 1
b = b + 2
c++

위의 연산을 할 때, a ~ c에 더해지는 1이나 2와 같은 데이터는 단순한 상수이다. 이때 해당 상수들을 다른 레지스터에 담고, 그것을 통해 add 연산을 하는 것은 비효율적이다. 그러므로, 이러한 small constant number를 instruction format에 저장해두고 사용할 수 있다. ISA 디자인 원칙 2번에 따라, 자주 사용되는 common case를 빠르게 실행할 수 있도록 하여 성능을 높인다.

addi x8, x9, 6

이 instruction은 x9 레지스터의 값과 상수 6을 더해서 x8 레지스터에 할당하라는 것을 의미한다. add instruction과 달리, source operand 중에서 하나는 register(x9)이고 하나는 constant(6)이다.

Memory

데이터를 32비트 레지스터 32개에만 저장할 수는 없기에, 메모리에 더 많은 데이터를 담는다. 메모리는 용량이 큰 대신 속도가 느리다. 그렇기에 자주 참조되는 데이터는 주로 레지스터에 담긴다.

이러한 메모리를 이용하려면 store/load 연산을 해야한다. Store는 데이터를 메모리에 저장하는 것이고, load는 메모리로부터 데이터를 불러오는 것.

이전에 언급했다시피, 메모리는 byte-addressed이기에 각각의 address는 8-bit(1-byte) data space를 가리킨다.

Little-endian / Big-endian

다음 32-bit data가 있다고 하자.

Data: 0x 0A 0B 0C 0D

이것은 4바이트이므로, 총 4개의 address에 걸쳐 담길 것이다. 해당 address가 다음과 같다고 하자. 각 address에 1바이트 데이터가 담긴다.

Address: a+0 a+1 a+2 a+3

이때? Little-endian 방식으로 데이터를 저장하면? 낮은 주소에 데이터의 낮은 바이트부터 저장한다.
a+0: 0D
a+1: 0C
a+2: 0B
a+3: 0A

Big-endian 방식으로 데이터를 저장하면? 낮은 주소에 데이터의 높은 바이트부터 저장한다.
a+0: 0A
a+1: 0B
a+2: 0C
a+3: 0D

사람 입장에서는 Big-endian 방식이 편해보인다. 데이터는 0A 0B 0C 0D 이고, 이것을 a ~ a+3이라는 address에 순서대로 저장하기 때문.
하지만 컴퓨터의 연산에 있어서는 Little-endian 방식이 유리하다. 덧셈을 한다고 하면, 낮은 주소에 저장된 바이트(낮은 바이트)부터 순서대로 자리 올림을 하면서 덧셈을 할 수 있기 때문.

Store/Load

sw x7, 48(x22)

이 instruction은 store 연산을 한다(store word). x22 레지스터의 값 + 48 이라는 메모리 주소에 x7 레지스터의 값을 저장하는 것이다. 즉, x22는 base address, 48은 offset이다.

lw x9, 32(x22)

이 instruction은 load 연산을 한다(load word). x22 레지스터의 값 + 32 이라는 메모리 주소의 데이터를 불러와서 x7 레지스터에 저장하는 것이다. 즉, x22는 base address, 32는 offset이다.

0개의 댓글