봉황대 in CS

[Chapter 2. 명령어: 컴퓨터 언어] 명령어 집합과 MIPS(산술, 메모리, 상수 연산), 레지스터와 메모리의 역할 본문

Computer Science & Engineering/Computer Architecture

[Chapter 2. 명령어: 컴퓨터 언어] 명령어 집합과 MIPS(산술, 메모리, 상수 연산), 레지스터와 메모리의 역할

등 긁는 봉황대 2022. 8. 16. 23:11

* 본 글은 '컴퓨터 구조 및 설계: 하드웨어/소프트웨어 인터페이스(Computer Organization and Design: The Hardware/Software Interface) 5th edition'의 내용과 2021학년도 1학기에 수강한 '컴퓨터 구조' 과목 강의 내용을 함께 정리하여 작성하였습니다.

 

명령어 집합 (Instruction Set)


컴퓨터 언어에서 단어를 명령어(instruction)라 하고,

그 어휘(특정한 구조가 이해할 수 있는 명령들의 집합)를 명령어 집합이라고 한다.

 

기계어는 다양하지만 실제로는 모두 유사하기 때문에

서로 다른 언어라기보다는 같은 언어의 사투리 정도로 보는 것이 타당할 것이다.

 

MIPS 명령어 집합 (The MIPS Instruction Set)

초기 컴퓨터는 매우 단순한 명령어 집합을 가졌지만,

발전에 따라 한 명령어가 한 번에 많은 명령을 할 수 있는 복잡한 명령어 집합을 구성할 수 있게 되었다.

(Complex Instruction Set Computer, CISC)

 

 

그러나 CISC에서는 명령어가 복잡하기 때문에 다음의 문제점들이 존재한다.

1. 명령어를 해석하는 데 시간이 오래 걸리며, 명령어 해석에 필요한 회로도 복잡하다.

2. 프로그래밍을 돕기 위한 수많은 명령어와 주소 모드가 존재했는데,

    이 중 실제로 쓰이는 명령어는 몇 개 되지 않는다는 사실이 밝혀졌다.

 

 

따라서 현대의 대다수 컴퓨터들은 다시 적은 수의 명령어들로 명령어 집합을 구성한다.

(Reduced Instruction Set Computer, RISC)

 

 

  CISC RISC
구조 복잡한 구조 단순한 구조
구성 복잡, 많은 명령어 간단, 최소 명령어
명령어의 길이 다양 고정
레지스터 적음 많음
속도 느림 빠름
용도 개인용 컴퓨터 서버, 워크스테이션

 

 

MIPS 명령어 집합은 RISC 계열의 명령어 집합 체계이다.

이는 현대의 많은 명령어 집합 구조(Instruciton Set Architecture, ISA)의 공통점들을 갖고 있다.

 

 

본서에서는 MIPS 명령어 집합을 예제로 사용한다.

 

산술 연산 (Arithmetic Operations)


기본적으로 모든 컴퓨터는 산술 연산(Arithmetic)을 할 수 있어야 한다.

 

다음 MIPS 어셈블리 언어는 두 변수 b와 c를 더해서 그 합을 a에 넣으라고 컴퓨터에 지시하는 것이다.

add a, b, c  # a gets b + c

 

MIPS 산술 명령어는 반드시 한 종류의 연산만 지시하며, 항상 변수 3개를 갖는 형식을 엄격히 지킨다.

위에서 설명했다시피, MIPS 명령어 집합은 RISC 계열이며

모든 명령어가 피연산자를 반드시 세 개씩 갖도록 제한하는 것은 하드웨어를 단순하게 하자는 원칙과 부합한다.

 

 

이러한 규칙에서 하드웨어 설계의 3대 원칙 중 첫 번째를 도출할 수 있다.

 

설계 원칙 1 : 간단하게 하기 위해서는 규칙적인 것이 좋다.

정규화는 구현을 단순하게 하며, 단순화를 통해 적은 비용으로도 높은 성능을 만들어낼 수 있다.

즉, 정규적인 형태의 틀을 갖고 구현을 하는 것이 좋다는 것이다.

 

 

(예시)

다음의 C언어 코드가 있다.

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

 

이를 MIPS 어셈블리 언어로 바꿔보면 아래와 같을 것이다.

add t0, g, h	# temp t0 = g + h
add t1, i, j	# temp t1 = i + j
sub f, t0, t1	# f = t0 - t1

 

레지스터와 메모리의 역할


레지스터

우리가 C, Java 등의 상위 수준 언어로 코딩을 했을 때에는 변수를 만들어서 그 변수에 값을 저장하면 끝이었지만,

산술 명령어의 피연산자에는 제약이 존재한다.

 

이들은 레지스터(register)라고 하는 하드웨어로 직접 구현된 특수 위치 몇 곳에 있는 것만을 사용할 수 있다는 것이다.

 

레지스터는 하드웨어 설계의 기본 요소인 동시에 프로그래머에게도 보이는 부분이므로,

컴퓨터를 구성하는 벽돌과 같다고 할 수 있다.

 

 

MIPS 구조에서는 레지스터의 크기는 32비트이다.

MIPS에서 32비트가 한 덩어리로 처리되는 일이 매우 빈번하므로 이것을 워드(word)라고 부른다.

(1 word = 32 bit = 4 byte)

 

 

프로그래밍 언어에서 사용하는 변수와 하드웨어 레지스터의 큰 차이점 하나는 레지스터는 개수가 한정되어 있다는 점이다.

 

레지스터의 개수는 제한되어있기 때문에

변수의 개수가 레지스터의 제한을 넘을 경우 컴파일러의 레지스터 최적화는 필수적이다.

 

현대 컴퓨터에서는 MIPS에서 처럼 32개의 레지스터를 갖는다.

즉, MIPS는 32비트의 레지스터를 32개 갖고 있다.

 

* 레지스터를 나타내기 위해 MIPS 관례는 달러 기호 뒤에 두 글자가 따라 나오는 이름을 사용한다.

1. C나 Java의 변수에 해당하는 레지스터를 위해선 $s0, $s1 등을 사용

2. MIPS 명령어로 컴파일하기 위해 필요한 임시 레지스터를 위해서는 $t0, $t1 등을 사용

 

 

(예시)

위에서 보인 C 코드 예시이다.

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

 

이를 레지스터를 사용해서 바꿔보면 아래와 같을 것이다.

add $t0, $s1, $s2	# register $t0 contains g + h
add $t1, $s3, $s4	# register $t1 contains i + j
sub $s0, $t0, $t1	# f gets $t0 - $t1, which is (g + h) - (i + j)

 

그런데 레지스터의 개수는 왜 32개로 제한했을까?

 

그 이유는 하드웨어 설계의 3대 원칙 중 두 번째 원칙에서 찾을 수 있다.

 

설계 원칙 2 : 작은 것이 더 빠르다.

레지스터가 아주 많아지면 전기 신호가 더 멀리까지 전달되어야 하므로 클럭 사이클 시간이 길어진다.

 

32개 이상의 레지스터를 사용하지 않는 또 다른 이유 하나는 명령어 형식에서 레지스터가 사용하는 비트 수와 관련이 있다.

(2.5절에 나올 예정)

 

메모리

프로그래밍 언어를 쓸 때 값 하나만 기억하는 단순한 변수 외에도 배열이나 구조체 같은 복잡한 자료구조들이 있다.

 

이러한 복잡한 자료구조 하나에는 레지스터 개수보다 훨씬 많은 데이터 원소가 있을 수 있는데,

이들은 컴퓨터에서 어떻게 표현되고 사용될까?

 

 

우리는 배열이나 구조체 같은 큰 자료구조는 메모리에 저장한다.

 

 

대부분의 컴퓨터는 byte 단위로 주소를 지정한다. (byte address, 1 byte = 8 bit)

 

워드(word) 주소를 사용할 경우 4 byte의 크기를 차지한다. (1 word = 32 bit = 4 byte)

즉, MIPS에서 word의 시작 주소는 항상 4의 배수여야 하며, 이러한 요구사항을 정렬 제약이라고 한다.

 

* 정렬 제약(alignment restriction) : 메모리 내에서 데이터는 자연스러운 경계를 지켜서 정렬되어야 한다는 요구 조건

 

 

word 주소를 사용하는 방법에는 2가지가 존재한다.

 

1. 최상위(big end) 바이트 주소를 워드 주소로 사용 : Big-Endian

    MSB(Most Significant Byte)부터 메모리에 저장하는 것이다.

 

2. 최하위(litte end) 바이트 주소를 워드 주소로 사용 : Little-Endian

    LSB(Least Significant Byte)부터 메모리에 저장하는 것이다.

 

 

MIPS는 Big-Endian 계열에 속한다.

 

 

(예제 문제)

데이터는 주소 0번지부터 저장된다고 가정할 경우,

값 0xabcdef12는 little-endian machine과 big-endian machine 각각에 어떻게 저장되는가?

 

 

메모리 연산 (Memory Operands)


MIPS의 산술 연산은 레지스터에서만 실행되기 때문에 메모리와 레지스터 간에 데이터를 주고받는 명령어가 필요하다.

 

이때 사용되는 것이 바로 메모리 연산자이다.

 

lw (load word)

메모리에서 레지스터로 데이터를 복사해 오는 데이터 전송 명령을 적재(load)라고 한다.

MIPS에서 이 명령어의 실제 이름은 lw(load word)이다.

 

 

아래의 C 코드가 있다.

g = h + A[8];

g는 레지스터 $s1, h는 레지스터 $s2,

A의 시작 주소는 레지스터 $s3에 저장되어 있다고 하자. (base 레지스터 : $s3)

 

위의 코드를 MIPS 어셈블리 언어로 바꾸면 다음과 같다.

lw $t0, 32($s3)  # load word
add $s1, $s2, $t0

 

A[8]은 A의 시작 주소에서 8*4(bit)=32번째 bit에 저장되어 있는 data임을 지시한다.

 

즉, 현재 4byte 크기의 word를 저장하고 있기 때문에 

A의 시작 주소에 32가 더해져야 A[8]의 메모리 주소 상 위치로 접근할 수 있어, 32가 offset으로 곱해지는 것이다.

 

sw (store word)

적재와 반대로,

레지스터에서 메모리로 데이터를 보내는 명령을 저장(store)라고 한다.

MIPS에서 이 명령어의 실제 이름은 sw(store word)이다.

 

 

아래의 C 코드가 있다.

A[12] = h + A[8];

h는 레지스터 $s2, A의 시작 주소는 레지스터 $s3에 저장되어 있다고 하자.

 

위의 코드를 MIPS 어셈블리 언어로 바꾸면 다음과 같다.

lw $t0, 32($s3)  # load word
add $t0, $s2, $t0
sw $t0, 48($s3)  # store word

 

상수 연산자 (Immediate Operands)


프로그램에서 상수를 사용하는 경우는 많이 있는데, 이들은 어디에 저장하여 사용하는 것일까?

 

 

이제까지 배운 명령어만으로 상수를 사용하려면 메모리에서 상수를 읽어 와야 한다.

(상수는 프로그램이 적재될 때 메모리에 넣어짐)

 

예를 들어 레지스터 $s3에 상수 4를 더하는 MIPS 어셈블리 언어는 아래와 같다.

lw $t0, AddrConstant4($s1)  # $t0 = constant 4
add $s3, $s3, $t0  # $s3 = $s3 + $t0 ($t0 == 4)

* $s1 + AddrConstant4는 상수 4가 저장되어 있는 메모리 주소라고 가정

 

 

하지만 상수는 쓰이는 빈도가 굉장히 높은데,

그때마다 적재 명령어를 사용한다면 성능이 굉장히 좋지 않을 것이다.

 

 

따라서 하드웨어 설계의 3대 원칙 중 세 번째 원칙에 따라

피연산자 중 하나가 상수인 산술 연산 명령어를 제공하는 방법을 사용한다.

 

설계 원칙 3 : 자주 생기는 일을 빠르게 하라.

 

이 상수는 수치(immediate) 피연산자라고 하며, 수치 피연산자를 갖는 덧셈 명령어는 addi이다.

 

위의 예시, 레지스터 $s3에 상수 4를 더하는 MIPS 어셈블리 언어는 아래와 같다.

addi $s3, $s3, 4  # $s3 = $s3 + 4

 

상수 피연산자는 자주 사용되므로, 상수 필드를 갖는 산술 명령어를 사용하면

매번 메모리에서 상수를 가져오는 것보다 연산이 훨씬 빨라지고 에너지를 덜 소모하게 된다.

 


상수 0의 경우, $zero라는 레지스터에 따로 저장해 두고 사용한다.

상수 0은 여러 변형을 제공함으로써 단순한 명령어 집합을 가능케하기 때문이다.

 

 

예를 들어, 복사(move) 연산은 피연산자 중 하나가 0인 add 명령어이다.

 

따라서 레지스터 $zero를 값 0으로 묶어둔다면

따로 새로운 명령어를 만드는 것이 아닌, 기존 add 명령어를 사용하여 복사 연산을 구현할 수 있게 된다.

add $t2, $s1, $zero  # move operation

 

 

반응형
Comments