Exemplo 4 - Chamada de procedimentos e armazenamento de dados na pilha

 

Objetivo: Implementar um procedimento para o cálculo do fatorial de n. Tal procedimento deverá ser feito de tal maneira a chamar um segundo procedimento.
$v0 = retorna o resultado ao programa principal
$v0 = 0 se n < 1
$v0 = 1 se n = 1
$v0 = n! se n > 1
n! = n.(n-1).(n-2)... .1

 

.text
.globl main
main: # Programa Principal
li $a0, 5 # Parametro = 5
jal Fatorial # Chama a função fatorial,
# armazenando o endereco da proxima instrucao em $ra
move $s0, $v0 # Registrador $s0 recebe o valor resultado
li $v0, 10 # Serviço do sistema no. 10 : Exit
syscall # Chamada de serviço do sistema
# Obs. Isto é necessário para encerrar aqui o programa
Fatorial: # Função Fatorial. Retorna o fatorial de n ($a0)
sub $sp,$sp,4 # Abre espaço para armazenar 1 item na pilha
sw $ra, 0($sp) # Armazena o conteúdo do registrador $ra
# Obs: Caso os registradores $s0 - $s9 fossem alterados, seria necessário guardá-los na pilha também, e restaurá-los ao fim do procedimento. Por convenção, os registradores temporários $t* não precisam ser guardados.
li $t1, 1 # $t1 = 1
slti $t0, $a0, 2 # Seta $t0 se $a0 < 2
beq $t0, $zero, Calcula # Se $t0 não setado, $a0 > 1, portanto Calcula
add $v0, $zero, $zero # Se não, $v0 = 0
beq $a0, $zero, Sai # Se $a0 = 0, Sai
add $v0, $t1, $zero # Se não, $v0 = 1
Sai:
lw $ra, 0($sp) # Carrega o registrador $ra da pilha
add $sp, $sp, 4 # Elimina 1 item da pilha
jr $ra # Retorna ao programa principal
Calcula:
add $a1, $a0, $zero # $a1 = $a0
Loop:
sub $a1, $a1, $t1 # $a1 = $a1 - 1
jal Multiplica # Multiplica $a0 por $a1
add $a0, $v0, $zero # $a0 = resultado da multiplicação
bne $a1, $t1, Loop # Enquanto $a1 for diferente de 1, Loop
j Sai
Multiplica:
mult $a0, $a1 # Multiplica $a0 por $a1
mflo $v0 # resultado em $v0
# Obs:. O resultado da instrução mult fica armazenado nos registradores # $hi e $lo. Para buscar os seus valores, utiliza-se mflo e mfhi. Para # podermos trabalhar com valores maiores em nosso programa bastaria retornar o $lo em $v0 e o $hi em $v1.
jr $ra # Retorna

 

Salve o arquivo com o nome de "exercicio4.s" e abra-o no SPIM. Antes de executá-lo, abra as janelas de Text Segment e a de Data Segment e redimensione-as de modo que as duas fiquem visíveis na tela. Vamos executar o programa passo a passo, através do Single Step (F10). As primeiras 8 linhas de código no Text Segment foram geradas automaticamente pelo SPIM para controlar o fluxo do programa. Continue executando linha por linha até chegar ao nosso código, que começa com [ 5: li $a0, 5 ]. A próxima linha muda o fluxo do programa, chamando a função fatorial. Continue executando. Observe que dentro da função fatorial armazenamos o conteúdo de $ra na pilha, e isto pode ser confirmado na janela do segmento de dados. Agora abra a janela de Registradores e continue fazendo o passo a passo, acompanhando a evolução do resultado do fatorial em $a0. Ao final do laço, retornamos ao programa principal que coloca o resultado em $s0.

Outra maneira interessante de se resolver este exercício é através de procedimentos recursivos, ou seja, uma função fatorial que chama a si mesma com um parâmetro (que seria o resultado intermediário) até chegar a um resultado final.