Compilando While no MIPS

mips

Oi pessoal! Nos artigos anteriores eu mostrei a vocês como compilar operações lógicas, números com e sem sinal, como testar algumas instruções no MARS e, também, alguns comandos de controle, como o IF. Bem, hoje vou mostrar a vocês como compilar o comando de controle WHILE para Assembly MIPS. Vamos começar!

 

 

O comando while

 

A palavra while significa “enquanto” e, em programação significa algo como “enquanto não alcançar o critério de parada, continue executando”. Isso caracteriza o que chamamos de LOOP pois, aquele bloco de código dentro dele continuará executando repetidamente até que algo o faça parar. Entramos em LOOP infinito quando o bloco de código nunca para de executar, sendo isto causado, muitas vezes, por um erro na codificação ou lógica da resolução do problema. Bom, para mais informações sobre os comandos de controle, sugiro ler o meu artigo sobre eles clicando aqui!

 

 

Exemplo de compilação

 

Vou mostrar agora como é feita a compilação de um comando while, na linguagem C, para o MIPS. Considere o seguinte exemplo:

 

São apenas duas linhas de instruções em linguagem C, parece simples, e de fato é, porém, a compilação é trabalhosa! Analisando a instrução verificamos que existe um array chamado save o qual é usado como condição de parada do while, “enquanto save[i] == k faça”, isto é, continue executando, significando que o bloco de código só parara quando save[i] for diferente de k. Esse array save deve ser carregado antes para que possa ser utilizado no while, somente depois compilaremos a comparação “==” e o restante do código.

 

Suponha então que i seja o registrador $s3, k o registrador $s5 e save o registrador $s6, vamos compilar o código Assembly MIPS correspondente a esse segmento em C. Como já aprendemos em artigos anteriores, quando temos um índice variável, precisamos calcular o seu endereço multiplicando i por 4, pela questão do endereçamento em bytes. Mostrei como fazer isso de forma um pouco bruta, somando várias vezes, e depois usando a instrução de deslocamento lógico à esquerda, que vou usar aqui:

 

LOOP:            sll $t1, $s3, 2              # $t1 = 4 * i

 

Fácil não?! O rótulo (label) LOOP precisa ser inserido no início desta instrução para identificar que ali começa um LOOP. Feito o cálculo do endereço do índice variável, agora precisamos do endereço de save[i], conforme segue:

 

add $t1, $t1, $s6

 

Bem, agora que já temos o endereço completo de save[i] podemos fazer a leitura do array, conforme já visto em outros artigos.

 

lw $t0, 0 ($t1)                        # $t0 = save[i]

 

Tranquilo né?! Bem, já calculamos o endereço de i, o endereço de save[i], carregamos o array, agora temos de fazer a comparação, o teste de igualdade, o qual também já aprendemos em um artigo anterior:

 

bne $t0, $s5, EXIT                 # vá para EXIT se save[i] diferente de k

 

EXIT é um label que indica o final desse bloco de código e o mesmo também já foi apresentado em um artigo anterior. Vejam só que legal, estamos usando praticamente tudo o que já aprendemos até agora para compilar o while, assim, essa linha diz que se o array save na posição i for diferente de k, então o compilador deve “pular” para o label EXIT que é o fim deste bloco de código, caso contrário, entra no bloco de código e executa as linhas que estão ali dentro. A instrução em C seguinte é a soma de i com 1, ou seja, um contador, que fica da seguinte forma:

 

add $s3, $s3, 1                       # $s3 = $s3 + 1           (ou i = i + 1)

 

Bem, assim terminamos a compilação das instruções, mas ainda precisamos fazer uma coisa. While é um LOOP, correto, e lembram-se que na primeira linha criamos um label chamado LOOP?! Então, esse LOOP precisa ser chamado de volta ao final do bloco de código pois, enquanto save[i] for igual a k ele deve repetir o bloco. Em C o início e o fim dos blocos são representados por chaves { }, mas em Assembly MIPS não existe essa representação, ainda assim precisamos dizer quando e onde o bloco de repetição começa e termina. Dessa forma utilizaremos uma instrução de salto para fazer esse papel junto com o label EXIT ao final:

 

j LOOP                       # volta para o LOOP

EXIT:

 

Essas duas últimas linhas então finalizam a compilação, onde j Loop volta para o label LoopEXIT sai da execução da repetição. Abaixo código completo:

 

A compilação está pronta, agora vamos encontrar o restante!

 

a) Linguagem de Máquina

 

 

b) Representação da Linguagem de Máquina

 

Endereço de Memória

OPCODE

RS

RT

RD

SHAMT

FUNCT

0x 0040 0010

0

0

19

9

4

0

0x 0040 0014

0

9

22

9

0

32

0x 0040 0018

35

8

9

0

0x 0040 001c

4

8

21

0x 0040 0028

0x 0040 0020

8

19

19

1

0x 0040 0024

2

0x 0040 0010

0x 0040 0028

EXIT

 

 

c) Código de Máquina

 

Endereço de Memória

Instrução

0x 0040 0010

000000 00000 10011 01001 00100 000000

0x 0040 0014

000000 01001 10110 01001 00000 100000

0x 0040 0018

100011 01000 01001 00000 00000 000000

0x 0040 001c

000100 01000 10101 01000 00000 101000

0x 0040 0020

001000 10011 10011 00000 00000 000001

0x 0040 0024

000010 00000 00000 01000 00000 010000

0x 0040 0028

 

 

Onde:

  • 0040 = 0100 0000
  • 0010 = 0001 0000
  • 0028 = 0010 1000

 

d) Código no MARS

 

Para testar o código passo a passo e verificar o comportamento, mude os valores de $s5 e de save. Neste exemplo eu coloquei os valores das cinco primeiras posições de save como zero e k também como zero, assim, enquanto 0 = 0, ele continuará, até chegar em 1, quando finalmente para.

 

 

 

Conclusão

 

Bom pessoal, e assim terminamos mais um artigo da série MIPS. Apenas a título de curiosidade, tentem mudar de BNE para BEQ e vejam o que acontece no MARS. Notem que o conhecimento é cumulativo, isto é, tudo o que você aprende artigo a artigo é necessário para desenvolver uma solução MIPS completa. Espero que estejam gostando e, como sempre, se houver dúvidas, deixem aqui nos comentários que eu responderei assim que for notificada, ok! Muito Obrigada pessoal e até o próximo artigo.

 

 

Saiba mais

 

Comando de Controle IF

Comando de Controle While

Comando de Controle For

Outros artigos da série

<< Compilando instruções com ou sem Sinal, Overflow e Imediato no MIPSCompilando Switch/Case no MIPS >>

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Elaine Cecília Gatto
Bacharel em Engenharia de Computação. Mestre em Ciência da Computação. Co-fundarora e Líder das #GarotasCPBr. Pesquisadora Convidada no Grupo de Pesquisa de "Artes em Tecnologias Emergentes" do Programa de Pós Graduação em Design na UNESP Campus Bauru. Cantora, Docente no Magistério Superior, Geek, Nerd, Otaku e Gamer. Apaixonada por Michael Jackson, Macross, Séries e Filmes de Super Heróis, Cervejas e Vinhos. Mais informações sobre mim você encontra em: http://lattes.cnpq.br/8559022477811603.

Deixe um comentário

Seja o Primeiro a Comentar!

avatar
 
  Notificações  
Notificar