본문 바로가기
소프트웨어/컴퓨터 구조(MIPS)

[MIPS] MIPS programming 과제 - 정수의 나눗셈

by Ruas 2021. 10. 27.
728x90

 

오늘은 MIPS를 사용한 정수의 나눗셈을 설명드리겠습니다.

 

해당 포스트를 진행하기에 앞서 기본적인 opcode 학습이 필요합니다.

 

 

[MIPS] MIPS programming 기본

 

[MIPS] MIPS programming 기본

opcode Artithmetic Instructions opcode 사용 방법 의미 add add $s1, $t0, $t1 $s1 = $t0 + $t1 sub sub $s1, $t0, $t1 $s1 = $t0 - $t1 mul mul $s1, $t0, $t1 $s1 = $t0 * $t1 mult mult $t0, $t1 Lo, Hi..

ruas-coding.tistory.com

 

 

2. 사용자로부터 변수 a, c에 입력을 받아 저장하고, 입력받은 두 수의 몫과 나머지를 출력하는 프로그램을 작성하시오.

 

이번 문제에서는 사용자로부터 변수를 입력받아야 합니다.

기본적인 구성 자체는 다른 언어와 크게 다르지 않습니다.

 

C++을 예로 설명 드리자면,

 

int a = 0;

int main(void){
	cin >> a;
    return 0;
}

 

변수 a를 선언한 다음에 main 함수에서 변수 값을 입력 받는 방식으로 할 수 있습니다.

 

어셈블리어에서도 구조 자체는 동일합니다. 

 

    .data
a: .word 0
c: .word 0
    .text

 

먼저 입력받을 변수 a와 c를 0으로 초기화한 상태로 생성합니다.

 

main:
    li $v0, 5
    syscall
    sw $v0, a

    li $v0, 5
    syscall
    sw $v0, c

 

변수의 값은 main에서 입력 받습니다.

정수의 나눗셈을 구현하니 정수의 타입은 int가 되야겠죠?

int 입력을 담당하는 syscall 5를 사용합니다.

 

li $v0, 5 가 이 역할을 수행합니다.사용자로 부터 int 타입의 값을 입력 받아 $v0 레지스터에 저장합니다.

 

현재 사용자의 입력값을 받아 레지스터에 저장한 단계에 있습니다.레지스터에 저장을 했다는 것은 변수에 값을 저장했다는 뜻이 아닙니다.때문에 레지스터에 저장되어 있는 값을 위에서 선언한 변수에 이동시키는 과정이 필요합니다.

 

해당 기능을 수행하는 코드가 바로 sw 입니다.sw $v0, a 는 $vo에 있는 값을 변수 a에 저장하겠다는 의미입니다.이 코드까지 수행하면 변수 a에 사용자가 입력한 값이 정상적으로 저장됩니다.

 

문제에서는 정수의 나눗셈을 위한 두개의 정수를 입력받으라고 하였기 때문에,같은 과정을 한번 더 수행하여 변수 c에 사용자 입력값을 저장합니다.

 

    lw $t1, a
    lw $t2, c

    div $s0, $t1, $t2

 

다음은 나눗셈을 합니다.

다만, 나눗셈을 진행하기 이전에 변수 a, c에 저장되어 있던 값을 임시 레지스터로 이동시킵니다.

 

lw의 경우 값을 이동시킨다는 개념보다 load 하는 개념으로 이해하셔야 합니다.

lw $t1, a 는 변수 a에 저장되어 있는 값을 레지스터 $t1에 Load 하겠다는 의미입니다.

 

두개의 변수를 모두 Load 하고,

나눗셈을 수행하는 명령어 div를 사용합니다.

 

div 역시 다른 연산 명령어와 동일한 구조를 가지고 있습니다.

맨 앞의 $s0는 연산 결과를 저장할 레지스터 이며, $t1 / $t2 연산을 수행합니다.

 

div 까지 완료하면 나눗셈 연산 자체는 완료 됩니다.

하지만, 문제를 보면 나눗셈의 몫과 나머지를 '모두' 출력해야 합니다.

 

div 연산 이후 $s0를 출력하게 되면 해당 연산의 '몫'만 출력됩니다.

때문에, 별도의 코드를 작성해서 나머지까지 출력할 수 있도록 해야합니다.

여기서 필요한 것이 바로 mflo와 mfhi 입니다.

 

    li $v0, 1
    mflo $s1
    mfhi $s2

 

mflo 의 경우 나눗셈의 몫을 다루고,

mfhi 의 경우 나눗셈의 나머지를 다룹니다.

 

몫과 나머지를 모두 출력해야하기 때문에 각각 별도의 레지스터에 저장합니다.

mflo $s1은 $s1 레지스터에 나눗셈의 몫을,

mfhi $s2는 $s2 레지스터에 나눗셈의 나머지를 저장합니다.

 

    move $a0, $s1
    li $v0, 1
    syscall

    move $a0, $s2
    li $v0, 1
    syscall

    li $v0, 10
    syscall

 

이후 출력하는 방법은 이전 포스트에서 설명드렸던 바와 같습니다.

int를 출력하는 syscall 1을 사용하며, $s1과 $s2에 있던 값을 $a0로 이동하여 순차적으로 출력합니다.

 

출력이 완료되면 exit를 담당하는 syscall 10을 사용하여 프로그램을 종료합니다.

 

 

 

 

아래는 전체 코드 입니다.

 

    .data
a: .word 0
c: .word 0
    .text

main:
    li $v0, 5
    syscall
    sw $v0, a

    li $v0, 5
    syscall
    sw $v0, c

    lw $t1, a
    lw $t2, c

    div $s0, $t1, $t2
    
    li $v0, 1
    mflo $s1
    mfhi $s2

    move $a0, $s1
    li $v0, 1
    syscall

    move $a0, $s2
    li $v0, 1
    syscall

    li $v0, 10
    syscall

 

이상입니다.

728x90

댓글