Oi galera! No artigo anterior ensinei vocês a testarem alguns dos códigos que fiz em um simulador bem simples, chamado MARS. No artigo de hoje darei continuidade aos testes dos exemplos, de forma que você tenha um material referencial na hora de fazer o seu próprio.
Exemplo 4: Array
Utilizarei agora o exemplo do quarto artigo desta série:
a = b + c[10];
LW $t0, 10 ( $s2 ) ADD $s0, $s1, $t0
LW $8, 10 ( $18 ) ADD $16, $17, $8
Esse exemplo será um pouco mais trabalhoso do que os outros pois estou falando de um array, de obter o valor de uma posição específica desse array, e depois somar esses valores. Não esqueça de que é preciso fazer o cálculo correto do endereço também. Antes de mais nada, veja como é o código completo em C:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main(){
setlocale(LC_ALL,"Portuguese");
int c[15] = {3, 0, 1, 2, -6, -2, 4, 10, 3, 7, 8, -9, -15, -20, -87, 0};
int a = 0, b = 30;
a = b + c[10];
printf("\n o valor de a é: %d \n", a);
}
Bom, para o nosso teste, eu vou descartar algumas coisas, ok? Como o FOR, por exemplo, visto que ainda não passei os detalhes para vocês sobre LOOP. Porém, ter o programa de alto nível como referência, para conseguirmos entender um pouco melhor a compilação aqui no MARS, é muito útil.
Primeira coisa: notem que a variável b foi declarada como um tipo inteiro e a ela foi atribuído o valor 30.
Segunda coisa: um array do tipo inteiro chamado c foi declarado com o tamanho de 15 posições, e já inicializado com os respectivos valores.
Terceira: também é declarada uma variável do tipo inteiro chamada “a”, que não é inicializada.
Quarta: a soma é executada.
Quinta coisa: impressão do resultado, a qual não mostrarei neste artigo.
Farei algo bem semelhante no MARS para testar o exemplo do artigo 4. Vou declarar e inicializar um array no MARS, conforme demonstra a linha abaixo:
.data c: .word 3, 0, 1, 2, -6, -2, 4, 10, 3, 7, 8, -9, -15, -20, -87, 0
A diretiva “.data” indica que as instruções a seguir contêm dados. A diretiva “.word” armazena n quantidades de 32 bits em palavras de memórias sucessivas. Assim, determino que “c” é um label (ou rótulo) que contém os valores designados da word. Essas diretivas permitem usar o segmento de dados para armazenar e manipular dados. Assim, pode-se dizer que a linha de código abaixo, em linguagem C…
int c[15] = {3, 0, 1, 2, -6, -2, 4, 10, 3, 7, 8, -9, -15, -20, -87, 0};
…pode ser traduzida como abaixo, no MIPS:
.data c: .word 3, 0, 1, 2, -6, -2, 4, 10, 3, 7, 8, -9, -15, -20, -87, 0
Porém, há outras formas de trabalhar com Arrays na compilação para o MIPS. Por hora, para não confundir muito, deixarei assim para que você consiga testar os exercícios depois. Além de definir e inicializar o array “c”, é necessário também definir o índice e o endereço, isto é, serão atribuídos a registradores temporários o índice específico (no caso 10) e o endereço do array. Para atribuir o endereço do array a um registrador, é preciso usar uma instrução chamada la, que significa load address, em português “carga de endereço”. Determinado o array, agora basta determinar b = 30, que ficará da seguinte forma:
li $s1, 30 # (30)10 = (1E)16, portanto $s1 = 0 x 0000 001E
O valor imediato, 30, é carregado para $s1, que é o registrador de b, lembrando que li é a instrução de load immediate. Após, é preciso carregar o endereço do array em um registrador, como a seguir:
la $s2, c # c está em 0 x 0000 1001
Suponha que o endereço do array “c” seja (1001)2 ou (4097)10. Neste momento, na hora da execução do código Assembly no MARS, vocês vão notar que o registrador $at será utilizado para ajustar o endereço, de forma que ele passa de 0x00001001 para 0x10010000. O registrador $at é reservado para o montador, para uso exclusivo dele. A instrução la carrega o endereço do array c para o registrador $s2. Agora, é preciso especificar o índice para outro registrador, no caso do nosso exemplo, é a posição 10:
li $t2, 10 # (10)10 = (A)16
Novamente uso li, para a carga do número inteiro 10, que é um imediato, para o registrador $t2. Agora que o endereço do array já está guardado em um registrador temporário, e o índice 10 também, é preciso calcular o endereço da forma correta, conforme já expliquei em artigos anteriores.
add $t2, $t2, $t2 # 10 + 10 = 20 => (14)16 add $t2, $t2, $t2 # 20 + 20 = 40 => (28)16 add $t1, $t2, $s2 # (28)16 + (1001)16
Na terceira linha o cálculo é feito como uma soma dos dois registradores:
|
$t2 |
1001 0000 |
|
$s2 |
0000 0028 |
|
$t1 |
1001 0028 |
Portanto, o endereço resultante armazenado em $t1 é 0x10010028. Depois de calculado o endereço, já é possível carregar o valor contido em c[10] para o registrador $t0:
lw $t0, 0 ( $t1 )
Na posição c[10] está armazenado o valor 8, que em hexadecimal é 00000008. Reforço também que a contagem no array começa em zero e não em um! Cuidado com este pequeno grande detalhe, ok? Bom, todo esse trabalho apenas para carregar o valor correto e então usá-lo em uma soma, que você já conhece bem:
add $s0, $s1, $t0 # 30 + 8 = (38)10, ou então, 001E + 0008 = (26)16
O código completo fica conforme a seguir. Teste o mesmo no MARS e verifique os valores, endereços e estados dos registradores.
.data c: .word 3, 0, 1, 2, -6, -2, 4, 10, 3, 7, 8, -9, -15, -20, -87, 0 .text li $s1, 30 # determinando o valor para $s1 la $s2, c # colocando o endereço do array em $s2 li $t2, 10 # colocando o índice do array em $t2 add $t2, $t2, $t2 # “2i” add $t2, $t2, $t2 # “4i” add $t1, $t2, $s2 # combinando os dois componentes do endereço lw $t0, 0 ( $t1 ) # obtendo o valor da célula do array add $s0, $s1, $t0 # executando a soma
Conclusão
Ufa! Terminou! Quanto trabalho não! Dá pra entender porque muitas pessoas preferem programar em alto ou médio nível. Mas não desista! Apesar das dificuldades, linguagens de baixo nível em geral, são um grande aprendizado, pois te desafiam a sair da zona de conforto e a pensar um pouco diferente do que está acostumado. Sem contar que, nunca sabemos quando é que vamos precisar usar algo como isto em algum projeto, portanto, nenhum conhecimento é desperdiçado. Continuem me acompanhando, tem muito mais pela frente.








Estou começando a estudar Assembly antes de ir para C, e esses exemplos incrementam d+ nos estudos! Obrigado pelas boas postagens gerando um bom entendimento do assunto.
opa!! que bom =) fico muito feliz em ajudar
Boa tarde, Elaine.
Eu não entendi um detalhe abordado:
é na linha 10: lw $t0, 0 ($t1)
não entendi o porquê do uso desse zero. Poderia me tirar esta dúvida?
Sophia, é que o cálculo foi feito usando $t1, então o valor 10, que é o índice, já foi usado para ajudar no cálculo do endereço e armazendo no registrador $t1. Assim, ali no lw fica 0 pois não precisamos mais do 10.
Desculpe a demora para responder.
Parabéns pelo conteúdo gerado, estava meio perdido na disciplina de AOC1 na minha universidade ajudou e muito!!! Obrigado!!!
Que bom!!!! Fico muito feliz em poder ajudar =)
Cecilia, fazemos parte das lideres de comunidade da CPBR e não sabia que também eras magnifica nos artigos.
Parabéns!
Este material ajudou muito. Sucesso sempre!
Patricia Silva
Comunidade Manguebyte
opa!!! que bom =) obrigada gente