본문 바로가기
Study/컴퓨터 구조

컴퓨터 구조 - MIPS 구조

by Jamie Lim 2020. 6. 12.

1. MIPS 시스템

- 1989년대 스탠포드대학에서 John Hennessy가 그의 동료들과 함께 개발되었다

 

- Silicon Graphics, Nintendo, Cisco의 제품에서 사용되고 있다.

 

- 디자인 원리

  · 규칙적인 것이 간단성을 위해 좋다

  · 많이 발생되는 사항을 빨리 처리한다

  · 적을수록 빠르다

  · 좋은 설계는 좋은 절충안을 요구한다

 

2. 설계 원칙 1 - 규칙적인 것이 간단성을 위해 좋다

  - 일관성 있는 명령어의 형태

 

  - 같은 수의 피연산자 (두 개의 source와 한 개의 destination)

 

  - 하드웨어로 구현하기 쉽다

 

  - 명령어

   1) 덧셈 (Addition)

      ≫ High-level code  :  a = b + c;

       MIPS assembly code  :  add a, b, c

 

   2) 뺄셈 (Subtraction)

       High-level code  :  a = b – c;

       MIPS assembly code  :  sub a, b, c

 

3. 설계 원칙 2 - 많이 발생되는 사항을 빨리 처리한다

  - MIPS : 단순하고 많이 사용되는 명령어를 포함함

 

  - 명령어를 해석하고 실행하는 하드웨어는 단순하고 빠르다

 

  - 복잡한 명령어는 여러 개의 단순한 명령어로 수행된다

     High-level code  :  a = b + c – d;

     MIPS assembly code  :  add t, b, c    # t = b + c

                                                sub a, t, d    # a = t – d

 

  - 컴퓨터 구조 분류

    · RICS (Reduced Instruction Set Computer) : MIPS

    · CISC (Complex Set Instruction Set Computer) : InterIA-32

 

4. 설계 원칙 3 - 적을수록 빠르다

  - MIPS는 적은 수의 레지스터를 포함한다

 

  - 32개의 레지스터로부터 데이터를 획득하는 것이 1000개의 레지스터 또는 메모리로부터 데이터를 획득하는 것보다 빠르다

 

  1) MIPS 레지스터

    (1) 레지스터 세트

레지스터 이름 레지스터 번호 사용법
$0 0 상수값 0
$at 1 어셈블러 임시용
$v0 - $v1 2 – 3 프로시저 리턴 값
$a0 - $a3 4 – 7 프로시저 인자
$t0 - $t7 8 – 15 임시 변수
$s0 - $s1 16 – 23 저장 변수
$t8 - $t9 24 – 25 임시 변수
$k0 - $k1 26 – 27 운영체제 임시용
$gp 28 전역 포인터
$sp 29 스택 포인터
$fp 30 프레임 포인터
$ra 31 프로시저 반환 주소

 

    (2) 레지스터를 사용한 명령어 예시

       High-level code  :  a = b + c;

       MIPS assembly cod  :  add $s0, $s1, $s2   # $s0 = a, $s1 = b, $s2 = c

 

       High-level code  :  a = b + c – d;

       MIPS assembly code  :  sub $t0, $s2, $s3  #$s0 = a, $s1 = b, $s2 = c, $s3 = d

                                                 add $s0, $s1, $t0

 

    (3) 워드 주소 메모리

       load 명령어 (lw)

        - 메모리로부터 레지스터에 1워드를 전송

        - 형식 : lw dest offset(base)

        - lw $s3, 1($0)    # $0 주소에 1더한 곳(00000001)의 데이터를 $3에 넣기

 

      store 명령어 (sw)

        - 레지스터로부터 메모리에 1워드를 전송

        - 형식 : sw src, offset(base)

        - sw $t4, 0x3($0)   # 0x30x000003이므로 $0자리에 더하면 주소가 000003인 곳에 $t4의 값을 넣는다

     

    (4) 바이트 주소 메모리

       load 명령어 (lw)

        - 워드 주소 메모리와 같은 형식이지만 한 워드가 4바이트로 바뀐 것이다

        - 형식 : lw dest, offset(base)

        - lw $s3, 4($0)   # base$0주소에 4를 더해 주소가 00000004인 곳의 데이터를 $s3에 넣어준다

 

       store 명령어 (sw)

        - 워드 주소 메모리와 같은 형식이지만 한 워드가 4바이트로 바뀐 것이다

        - 형식 : sw src, offset(base)

        - sw $t7, 12($0)   # base$0주소에 12를 더해 주소가 0000000C인 곳에 $t7의 값을 넣는다

 

    (5) Big-Endian  VS  Little-Endian

      - Endina : 컴퓨터의 메모리와 같은 1차원 공간에 여러 개의 연속된 대상을 배열하는 방법

  

       Big-Endian

        - 큰 단위부터 들어가는 Endian

        - 장점 : 사람이 숫자를 읽고 쓰는 방식과 같아 디버그를 편하게 해준다

Big-Endian

        - 저장 예시

          ≫ $t0의 값이 0x23456789일 때, Big-Endian 시스템에서 수행한 후 $s0의 값은?

 

      Little-Endian

        - 작은 단위가 먼저 들어가는 Endian

        - 산술 연산이 메모리의 주소가 낮은 쪽에서부터 높은 쪽으로 가면서 처리되는 것과 같음

        - 장점 : 첫 바이트만 확인하면 되기 때문에 짝수, 홀수 검사를 할 때 처리 속도가 빠름

Little-Edian

        - 저장 예시

          ≫ $t0의 값이 0x23456789일 때, Little-Endian 시스템에서 수행한 후 $s0의 값은?

 

5. 설계 원칙 4 – 좋은 설계는 좋은 절충안을 요구한다

  - 다중 명령어 형태는 융통성을 제공한다

    · add, sub : 3개의 레지스터 피연산자 사용

    · lw, sw : 2개의 레지스터 피연산자와 상수 사용

 

  - 적은 수의 명령어 형태를 유지한다

 

  1) 기계어

    - 명령어들의 이진 표현 (0 또는 1로 표현)

    - 32비트 명령어

   - 명령어 형태

      · R-Type

      · I-Type

      · J-Type

 

  2) R-Type

 

    -  레지스터 타입

 

    - 3개의 레지스터 피연산자(오파랜드)

      · rs, rt : source 레지스터

      · rd : destination 레지스터

 

    - 다른 필드

      · op : operation 코드 (모든 R-Type 명령어의 op 코드는 0이다)

      · funct : function (더하기, 빼기 등의 계산을 구별해줌)

      · shamt : shift 명령어에서 사용되는 shift의 양

 

      - 사용 예시

       add rd, rs, rt   /   sub rd, rs, rt

Field Values
Machine Code

 

  3) I-Type

    - 즉시 값(상수 값) 타입 (Immediate)

 

    - 3개의 피연산자 (오퍼랜드)

      · rs, rt : 레지스터 피연산자

      · mm : 16비트 즉시 값(immediate)

 

    - 다른 필드

      · ip : operation 코드

      · 각각의 I-Type 명령어는 개별적인 op코드 값을 갖는다

 

    - 사용 예시

       Addi rt, rs, imm  /  lw rt, imm(rs)  /  sw rt, imm(rs)

 

Field Values
Machine Code

 

  4) J-Type

    - Jump 타입

 

    - 분기 명령어 형식

 

    - 1개의 피연산자 (오퍼랜드)

      · addr : 주소 피연산자

 

    - 다른 필드

      · op : operation 코드

 

6. 기계어 코드 해석

  - opcode0이면 R-type 명령어이므로 func 비트를 통해 명령어 기능 분석

 

  - opcode0이 아니라면 I-Type 또는 J-Type 명령어다

 

 

  1) 조건부 분기 (beq, branch if equal)

    - 형식 : beq register1, register2, L1

    - 만약 register1register2의 값이 같으면 L1에 해당하는 곳을 분기하라는 의미

    - 사용 예시

branch if equal

    - 현재 $s00 + 4이므로 4가 값으로 들어 있다. 그리고 $s10 + 11이 값으로 들어있는데 shift2번하므로 1 * 2 * 2가 되어 4를 갖고 있다. 그렇기 때문에 $s0$s1은 같은 값을 가져 target으로 분기하게 된다. (분기하였기 때문에 beq 아래 코드 2줄은 실행 X)

 

2) 조건부 분기 (bne, branch if not equal)

    - 형식 : bne register1, register2, L1

    - 만약 register1register2의 값이 다르다면 L1으로 분기하라는 의미

    - 사용 예시

branch if not equal

    - bqe의 예시와 똑같이 현재 #s04라는 값을 갖고 있고 $s1역시 4라는 값을 같고 있다. 하지만 bne는 서로 다른 경우에 분기하므로 target으로 분기하지 않고 아래 코드를 계속 진행한다.

 

  3) 무조건 분기 (j, jump)

    - 형식 : j L1

    - 이 명령어를 만나면 무조건 L1으로 분기한다

    - 사용 예시

jump

    - 다른 명령들과 상관없이 j target을 만나면 무조건 target 레이블로 분기한다.

 

  4) 무조건 분기 (jr, jump register)

    - 형식 : jr register

    - 이 명령어를 만나면 register의 값을 주소로 생각하고 해당 주소로 분기

    - 사용 예시

jump register

    - 현재 $s0은 0x2010이라는 값을 갖고 있다. 그러므로 jr $s0을 만나면 $s0의 값인 0x2010 을 주소로 하여 해당 주소로 이동한다.

 

5) if

  - if (i == j)에 대한 명령을 ij가 같지 않으면 분기해 실행하지 않도록 작성한다

if 문

 

  6) if / else

    - if (i == j)에 대한 명령을 ij가 같지 않으면 분기하도록 작성한다. 이때, 분기하지 않아 if문을 실행하게 되면 else문에 대한 명령은 실행하면 안되므로 else 명령 다름으로 분기할 수 있도록 if문 명령을 모두 실행하면 j done 명령을 실행하게 한다.

if / else 문

 

  7) whiel loop

    - 조건에 맞기 전까지는 while이라는 레이블에 while문에 해당하는 명령어를 넣어 while 레이블로 계속 분기한다. 만약 조건에 맞을 경우 done을 통해 done을 분기하여 while을 끝낸다.

while 문

 

  8) for loop

     - 조건에 맞지 않을 때가지 for이라는 레이블에 for문에 해당하는 명령어를 넣어 for 레이블로 계속 분기한다. 만약 조건에 맞을 경우 done을 통해 done을 분기하여 for을 끝낸다.

for loop

 

9) Less Than 비교

  - slt (set on less than) : slt $t1, $s0, $t0일 때, $t0보다 $s1이 작다면 $t1 = 1, 아니라면 $t0 = 0이 된다.

Less Then

 


< 퀴즈 >

Q1) MIPS 디자인(설계) 원칙으로 옳지 않은 것은?   (      )

  (1) 규칙적인 것이 간단성을 위해 좋다

  (2) 많이 발생되는 사항을 빨리 처리한다

  (3) 적을수록 빠르다

  (4) 좋은 설계는 절충안을 요구하지 않는다

 

 

Q2) 고급 언어에서 a = b + c라는 코드가 있을 때, 다음 중 이 코드와 같은 의미MIPS 어셈블리 코드를 고르시오.  (      )

 * 레지스터 $s0 = a, $s1 = b, $s2 = c 이다)

  (1) add $s1, $s0, $s2

  (2) add $s0, $s1, $s2

  (3) addi $s0, $s1, $s2

  (4) addi $s1, $s0, $s2

 

 

Q3) 레지스터 이름과 사용법이 잘 매치 되어 있지 않는 것을 고르시오.  (       )

  (1) $0 – 상수값 0

  (2) $t0 – 임시 변수

  (3) $gp – 전역 변수

  (4) $sp – 스택 포인터

 

 

Q4) $t0의 값은 0x98765432이다. 이때, Little-Endian 시스템으로 다음 코드를 수행했을 때 $s0의 값은?  (                     )

 sw $t0, 0($0)
 lb $s0, 1($0)

 

 

Q5) 다음 형식에 맞는 명령어 타입을 짝지으시오.

                       a. R-Type                                b. I-Type                                c. J-Type

  (1)   (             )

  (2)   (             )

  (3)   (             )

 

 

 

Q6) 다음 코드에서 색이 칠해진 코드가 실행되면 경우에 따라 어떻게 동작하는지 간단하게 쓰시오.

      addi $s1, $0, 0
      addi $s1, $0, 0

      addi $t0, $0, 12
for : beq $s0, $t0, done
      add $s1, $s1, $s0
      addi $s0, $s0, 1
      j for
done:

 

 

Q7) 아래 high-level 코드를 보고 MIPS assembly 코드에 뭐가 들어가야 할지 쓰시오.

Hight-level code MIPS assembly code
int num = 0;
int i;
 
for ( i = 10; i > 0; i = i - 1){
   num = num + i;
}
# $s0 = i, $s1 = num
        addi $s1, $0, 0
        addi $s0, $0, 10
        addi $t0, $0, 0
loop: (       1         )
        (        2        )
      add $s1, $s1, $s0
      sub $s0, $s0, 1
       j loop
done:

 

< 정답 >

더보기

A1) (4)

   좋은 설계는 절충안을 요구하지 않는 것이 아니라 좋은 절충안을 요구한다이다.

 

A2) (2)

   우선 add addi add가 맞다. 왜냐하면 addi는 정수 가산 명령으로 레지스터에 정수를 더해 저장하는 명령이다. 하지만 위 명령에서는 레지스터와 레지스터를 더하므로 add가 아닌 addi. 그리고 순서는 add dst, src1, src2이기 때문에 저장될 위치인 $s0이 가장 앞에 와야 한다. (add 명령은 operand로 레지스터만 가질 수 있다)

 

A3) (3)

   $gp는 전역 변수가 아니라 전역 포인터다.

 

A4) 0x00000054

 

A5) (1) b. I-Type

     (2) c. J-Type

     (3) a. R-Type

 

A6) $s0 for문을 돌면 12가 되기 전까지는 $t0과 같지 않으므로 그냥 다음 코드로 넘어가고 만약 $s0 12라면 $t0과 같으므로 조건에 성립에 done으로 분기한다.

 

A7) (1) slt $t1, $s0, $t0

     (2) bnq $t1, $0, done

 

 

< 참고 자료 >
https://madplay.github.io/post/big-endian-little-endian

댓글