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

[6] MIPS 시스템

by 투말치 2020. 6. 9.

목차

    반응형

    1-1. MIPS 시스템이란?

    - 밉스 테크놀로지에서 개발한 RISC 기반 ISA이다. ISA는 Instruction Set Architecture의 약자로 명령어 집합 구조라는 뜻이고 마이크로프로세서가 인식해서 기능을 이해하고 실행할 수 있는 기계어 명령어를 말한다. 더 알고 싶으면 아래 링크에 잘 설명되어 있다.

    https://velog.io/@shinychan95/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0-2%EA%B0%95-%EC%A0%95%EB%A6%AC-feat.-ISA

     

    컴퓨터 구조 2강 정리 (feat. ISA)

    모든 내용을 정리하는 것이 아니라, 주 맥락이나 파헤치며 배우고 깨닫게 된 부분에 대해서 정리합니다.

    velog.io

    - MIPS는 4가지의 디자인 원리를 가지고 설계되었다.

    1. 규칙적인 것이 간단성을 위해 좋음

    2. 많이 발생되는 사항을 빨리 처리함

    3. 적을수록 빠름

    4. 좋은 설계는 좋은 절충안을 요구함

     

     

    1-2. 설계 원칙 1

    - 규칙적인 것이 간단성을 웨해 좋음

    => 이 원리를 실현하기 위해 아래의 특징을 가진다.

    ①일관성있는 명령어 형태

    ②같은 수의 피연산자

    ③하드웨어로 구현하기 쉬움

     

    -덧셈

    High-level code

    MIPS assembly code

    a=b+c;

    add a, b, c

    -뺄셈

    High-level code

    MIPS assembly code

    a=b-c;

    sub a, b, c

     

    1-3. 설계 원칙 2

    - 많이 발생되는 사항을 빨리 처리함

    - 복잡한 명령어는 여러 개의 단순한 명령어로 수행한다. 따라서 명령어를 해석하고 실행하는 하드웨어가 단순하고 빠르다.

    => MIPS가 RISC(Reduced Instruction Set Computer) 기반이라서 명령어 개수가 적다.

     

    *RISC와 CISC 비교

    - RISC : Reduced Instruction Set Computer의 약자로 명령어 세트가 축소되었다는 뜻으로 명령어 개수가 많지 않고 적다. 따라서 단순하고 빠르다.

    - CISC : Complex Set Instruction Set Computer의 약자로 복잡한 명령어들을 많이 가진다. 따라서 프로세서 내부 구조가 복잡하다.

     

    1-4. 설계 원칙 3

    - 적을수록 빠름

    - MIPS는 적은 수의 레지스터를 가진다.

    - MIPS는 32개의 레지스터를 가진다(32비트 or 64비트)

     

    *MIPS 레지스터 세트

    레지스터 이름

    레지스터 번호

    사용법

    $0

    0

    상수값 0

    $at

    1

    어셈블러 임시용

    $v0-$v1

    2-3

    프로시저 리턴 값

    $a0-$a3

    4-7

    프로시저 인자

    $t0-$t7

    8-15

    임시 변수

    $s0-$s7

    16-23

    저장 변수

    $t8-$t9

    24-25

    임시 변수

    $k0-$k1

    26-27

    운영체제 임시용

    $gp

    28

    전역 포인터

    $sp

    29

    스택 포인터

    $fp

    30

    프레임 포인터

    $ra

    31

    프로시저 반환(return) 주소

     

    - 레지스터를 사용해서 명령어를 표현해보자

    High-level code

    MIPS assembly code

    a=b+c;

    $s0=a, $s1=b, $s2=c

    add $s0, $s1, $s2

    a=b+c-d;

    $s0=a, $s1=b, $s2=c, $s3=d
    sub $t0, $s2, $s3

    add $s0, $s1, $s2

     

    *워드 주소 메모리

    - 워드 단위로 주소를 읽어오는 것 (1워드 = 4byte or 8byte     => 1워드는 cpu에 따라 다름)

     

    *바이트 주소 메모리

    - 바이트 단위로 주소를 읽어오는 것

     

     

     

    *Big-Endian과 Little-Endian

    - 컴퓨터가 데이터를 읽어서 저장할 때 데이터를 상위데이터부터 읽어오면 Big-Endian 방식이고 하위데이터부터 읽어오면 Little-Endian 방식이다.

    EX) 만약 $t0의 값이 0x01234567 일 때,

    sw $t0, 0($0)

    lb $s0, 1($0)을 수행하면 다음과 같이 저장된다.

    Big-Endian

    $s0=0x00000023

    Little-Endian

    $s0=0x00000045

     

    1-5. 설계 원칙 4

    - 좋은 설계는 좋은 절충안을 요구함

    - 다중 명령어 형태는 융통성을 제공한다. (설계 원칙 1을 보면 같은 수의 피연산자를 사용한다고 했는데 명령어에 따라 융통성있게 사용한다.)

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

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

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

     

     

    2. 기계어

    - 기계어는 2진 수로 이루어진다. (0 또는 1)

    - MIPS는 명령어가 32비트로 구성되어 있다.

    - 명령어 형태로는 R-Type, I-Type, J-Type으로 3가지가 있다.

     

    2-1. 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

    - 예시 : add $s0, $s1, $s2를 표현하면 다음과 같다.

    - 일단 필드값은 보기 편하게 10진수로 표현했다.

    - R-type 명령어라서 op값은 0이다.

    - 17, 18, 16은 레지스터의 번호를 의미하고 funct값은 더하기를 의미해서 32값을 가진다.

     

     

    2-2. I-Type

    - 즉시값(Immediate) 타입

    - 3개의 오퍼랜드를 가짐

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

    => imm : 16비트 즉시값 (상수값을 넣기 위한 필드)

    - 다른 필드

    => op : operation 코드   - I-type 명령어는 R-type 명령어와 다르게 개별적인 op코드 값을 가진다.

    - addi rt, rs, imm   => op 코드 값 : 8, rs+imm을 해서 rt에 저장하라는 뜻

    - lw rt, imm(rs) => op 코드 값 : 35, imm+rs의 주소값을 불러와서 rt에 저장하라는 뜻

    - sw rt, imm(rs) => op 코드 값 : 43, imm+rs의 주소값에 rt값을 워드 단위로 저장하라는 뜻

    - 예시 : addi $s0, $s1, 5를 표현하면 다음과 같다.

     

    2-3. J-Type

    - Jump 타입

    - 1개의 오퍼랜드를 가짐

    => addr : 주소 피연산자

    - 다른 필드

    => op : operation 코드

     

    3-1. 조건부 분기 (beq)

    - 조건부 분기 명령어 중 beq 명령어를 코드로 살펴보자

    addi $s0, $0, 4   # $s0 = 0 + 4 = 4
    
    addi $s1, $0, 1	  # $s1 = 0 + 1 = 1
    
    sll  $s1, $s1, 2    #왼쪽 시프트 연산을 2번 수행하라는 뜻
    
    beq $s0, $s1, target   #s0과 s1이 같으면 target 레이블로 이동하라는 뜻 
    
    addi $s1, $s1, 1
    
    sub $s1, $s1, $s0
    
    target :
    
     add $s1, $s1, $s0  # $s1 = 4 + 4 = 8

    - $s1의 값과 $s2의 값이 같으므로 target 레이블로 이동해서 해당 명령어를 수행한다.

     

     

    3-2. 조건부 분기 (bne)

    addi $s0, $0, 4   # $s0 = 0 + 4 = 4
    
    addi $s1, $0, 1	  # $s1 = 0 + 1 = 1
    
    sll  $s1, $s1, 2    #왼쪽 시프트 연산을 2번 수행하라는 뜻
    
    bne $s0, $s1, target   #s0과 s1이 같지 않으면 target 레이블로 이동하라는 뜻 
    
    addi $s1, $s1, 1
    
    sub $s1, $s1, $s0
    
    target :
    
     add $s1, $s1, $s0 

    - $s1의 값과 $s2의 값이 같으므로 target 레이블로 이동하지 않고 순차적으로 명령어를 수행한다.

     

     

    3-3. 무조건 분기 (j)

    addi $s0, $0, 4   # $s0 = 0 + 4 = 4
    
    addi $s1, $0, 1	  # $s1 = 0 + 1 = 1
    
    j  target    #무조건 target으로 jump하라는 뜻
    
    ra $s1, $s1, 2   
    
    addi $s1, $s1, 1
    
    sub $s1, $s1, $s0
    
    target :
    
     add $s1, $s1, $s0 

    - 무조건 분기해야하기 때문에 target 레이블로 분기해 해당 명령어를 수행한다.

     

    3-4. 무조건 분기(jr)

    addi $s0, $0, 0x2010   
    
    jr   $s0
    
    sra $s1, $s1, 2   
    
    lw $s3, 44($s1)
    

    - 해당 명령어는 레지스터가 가진 값을 주소로 판단하고 해당 주소로 무조건 분기하라는 뜻이다.

     

     

    4-1. if 문

    - if 문을 어셈블리어로 표현해보자

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

    - 이 코드를 어셈블리어로 표현하면

     

    # $s0 = f, $s1 = g, $s2 = h
    # $s3 = i, $s4 = j
    
    bne $s3, $s4, L1 
    add $s0, $s1, $s2 
    
    
    L1 : sub $s0, $s0, $s3
    
    

    - If 문과 다르게 조건을 만족하면 덧셈 연산을 수행하는 것이 아니라 같지 않은 경우 분기하는 방식으로 if 문을 표현한다.

     

    4-2. if/else

    - if/else 문을 표현해보자

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

    - 이 코드를 어셈블리어로 표현하면

    # $s0 = f, $s1 = g, $s2 = h
    # $s3 = i, $s4 = j
    
    bne $s3, $s4, L1 
    add $s0, $s1, $s2 
    j done
    
    L1 : sub $s0, $s0, $s3
    done :

    - else 문이 있으면 if 가 끝난 다음에 done으로 가라는 코드가 있다.

     

     

    4-3. while문

    - while 문을 표현해보자

    int pow = 1;
    int x = 0;
    
    while (pow != 128) {
     pow = pow * 2;
     x = x + 1;
     }

    - 이 코드를 어셈블리어로 표현하면

    # $s0 = pow, $s1 = x
    
    addi $s0, 0, 1
    add $s1, $0, $0
    addi $t0, $0, 128
    
    while: beq $s0, $t0, done
           sll $s0, $s0, 1
           addi $s1, $s1, 1
           j while
    
    done :

    - $s0와 $t0(=128)가 같으면 done으로 이동해 while 문을 탈출한다.

    - while문은 계속 while 레이블로 분기하면서 반복한다.

     

    4-4. for문

    - for문을 표현해보자

    int sum = 0;
    int i;
    
    for (i=0; i!=10; i=i+1) {
     sum = sum + i;
     }

    - 이 코드를 어셈블리어로 표현하면

    # $s0 = i, $s1 = sum
    
    addi $s1, $0, 0
    add $s0, $0, $0
    addi $t0, $0, 10
    
    for: beq $s0, $t0, done
         add $s1, $s1, $s0
         addi $s0, $s0, 1
         j for
    
    done :

    - $s0과 $t0(=10)이 같으면 반복을 그만하고 done 레이블로 이동한다.

    - for 레이블의 명령어들은 $s0가 10이 되기전까지 반복된다.

     

     

    4-5. Less Than 비교

    - for문의 조건식을 less than으로 비교하는 코드를 표현해보자.

    int sum = 0;
    int i;
    
    for (i=1; i < 101; i=i*2) {
     sum = sum + i;
     }

    - 이 코드를 어셈블리어로 표현하면

    # $s0 = i, $s1 = sum
    
    addi $s1, $0, 0
    addi $s0, $0, 1
    addi $t0, $0, 101
    
    loop: slt $t1, $s0, $t0
          beq $t1, $0, done
          add $s1, $s1, $s0
          sll $s0, $s0, 1
          j   loop
    
    done :

    - slt 명령어의 뜻 : $s0의 값과 $t0의 값을 비교해서 만약 $s0 > $t0 이면 $t1이 0 값을 가진다.

    반대로 $s0 < $t0 값이 더 크면 $t1은 1값을 가진다.

    - 따라서 $t1이 slt 명령어를 수행해서 0 값을 가지면 앞의 코드에서 i<101의 조건이 아니라 i>101이 라는 의미이므로 반복문을 벗어나 done 으로 이동해야한다.

     

     

     

     

     

     

     

    더보기

    문제

    1. 0x98765432 를 Little-Endian 방식을 사용하는 시스템에 저장할 때 다음 표를 채우세요.

     

    하위주소         상위주소

     

    2. 다음 중 R-Type 명령어에 대한 설명으로 옳지 않은 것은?

    ㄱ. op 코드 값이 항상 1이다.

    ㄴ. 명령어의 길이가 32비트다.

    ㄷ. 레지스터 오퍼랜드가 3개다.

    ㄹ. 명령어에 funct 필드가 있다.

     

    3. 다음은 아래의 for문을 MIPS 어셈블리어로 표현한 것이다. 괄호를 알맞게 채우세요.

    int sum = 0;
    int i;
    
    for (i=0; i!=15; i=i+1) {
     sum = sum + i;
     }

     

    # $s0 = i, $s1 = sum
    
    (  1  ) $s1, $0, 0 
    add $s0, $0, $0
    addi $t0, $0, (   2   )
    
    for: beq $s0, $t0, (   3   )
         add $s1, (   4   )
         addi $s0, $s0, 1
         j    (    5   )
    
    done :

     

     4. 다음은 I-type 명령어의 필드들을 나타낸 것이다. 빈칸을 알맞게 채우시오.

     

    op rs rt  

     

     5. 다음은 아래의 if문을 MIPS 어셈블리어로 표현한 것이다. 괄호를 알맞게 채우세요.

    if (i==j)
     f = g - h;
    
    f = f + i;
    # $s0 = f, $s1 = g, $s2 = h
    # $s3 = i, $s4 = j
    
    (     ) $s3, $s4, L1 
    (     ) $s0, $s1, $s2 
    
    
    L1 : (     ) $s0, $s0, $s3
    
    

     

     6. 음은 아래의 less than 조건식을 사용한 for문을 MIPS 어셈블리어로 표현한 것이다. 괄호를 알맞게 채우세요.

    int sum = 0;
    int i;
    
    for (i=1; i < 20; i=i+2) {
     sum = sum + i;
     }

     

    # $s0 = i, $s1 = sum
    
    addi $s1, $0, 0
    addi $s0, $0, 1
    addi $t0, $0, (     )
    
    loop: (     ) $t1, $s0, $t0
          (     ) $t1, $0, (    )
          add $s1, $s1, $s0
          add $s0, $s0, (    )
          j   (     )
    
    done :

     

    7. jr명령어는 레지스터가 가진 값을 주소로 판단하고 그곳으로 분기하라는 명령어다. (O/X)

     

     

     

     

    더보기

    정답/해설

     

    1.

    하위주소 32 54 76 98 상위주소

    - 리틀 인디안 방식은 데이터를 하위비트부터 읽기 때문에 하위 비트부터 차례대로 저장된다.

    만약 빅인디안 방식을 사용했다면 98 76 54 32 이렇게 저장된다.

     

     

    2. ㄱ

    ㄱ. R-Type 명령어의 op 코드 값은 항상 1이 아니라 항상 0이다.

    ㄴ. 명령어의 길이는 32비트다.

    ㄷ. 레지스터 오퍼랜드가 3개다.

    - rs, rt, rd로 총 3개다.

    ㄹ. 명령어에 funct 필드가 있다.

    - 계산을 구별하는 funct 필드가 있다.

     

    3. 

    # $s0 = i, $s1 = sum

    addi  ) $s1, $0, 0 
    add $s0, $0, $0
    addi $t0, $0, (   15   )

    for: beq $s0, $t0, (   done   )
         add $s1, (   $s1, $s0   )
         addi $s0, $s0, 1
         j    (    for   )

    done :

     

    - addi : 상수값과 레지스터를 더하기 때문에 addi 명령어를 사용한다.

    - 15 : $t0 값이 15가 아닌 동안 for문을 반복해야 하기 때문에 $t0에 15를 저장한다.

    - done : $s0와 $t0가 같아지면 for문을 나가기 위해 done 레이블로 이동한다.

    - $s1, $s0 : $s1과 $s0을 더하는 것이 sum=sum+i;를 의미한다.

    - for : 반복문을 만들기 위해 명령어를 다 수행하면 다시 for 레이블로 점프한다.

     

     

    4. imm

    - imm필드는 16비트로 상수 값을 넣기 위한 필드이다.

     

    5.

    # $s0 = f, $s1 = g, $s2 = h
    # $s3 = i, $s4 = j

    bne   ) $s3, $s4, L1 
    sub   ) $s0, $s1, $s2 


    L1 : (  add    ) $s0, $s0, $s3

    - if문을 어셈블리어로 표현할 때, 조건이 i와 j가 같을 때이므로 같지 않을 때 L1으로 분기해 if 문을 나가고 만약 같으면 if문을 실행하는 방식으로 표현한다.

     

     

    6.  

    # $s0 = i, $s1 = sum

    addi $s1, $0, 0
    addi $s0, $0, 1
    addi $t0, $0, (   20   )

    loop: (  slt   ) $t1, $s0, $t0
          (  beq   ) $t1, $0, (  done    )
          add $s1, $s1, $s0
          add $s0, $s0, (   2    )
          j   (  loop   )

    done :

     

    - 20 : $t0는 for문의 조건식을 표현하기 때문에 i<20 조건을 확인하기 위해 20을 저장한다.

    - slt : slt 명령어를 통해 i<20을 판단할 수 있다. $s0와 $t0의 값을 비교해서 $s0 < $t0이면 $t1은 1이고 $s0 > $t0이면 $t1은 0이다.

    - beq, done : $t1과 $0이 같은지 즉, $s0 > $t0이 된다면 i < 20을 만족하지 못한다는 의미라서 loop를 탈출하기 위해 done 레이블로 분기한다.

    - 2 : i=i+2를 표현하는 코드다.

    - loop : 반복을 계속하기 위해 반복문 조건을 비교하고 코드를 다 실행하면 다시 loop레이블로 돌아간다.

     

     

    7. O

    - jr명령어는 레지스터가 가진 값을 주소로 판단하고 그곳으로 분기하라는 명령어다.

     

     

     

     

     

     

     

     

     

     

     

     

    반응형