Assembly no processador MIPS!
Assuério Batista
você irá aprender sobre:
A história do MIPS.
Conceitos básicos de programação assembly no processador MIPS.
Conceitos de endereçamento de memória.
requisitos:
Ter raciocínio lógico.
Gostar de solucionar problemas.
introdução
O Microprocessador sem estágios intertravados de pipeline (MIPS - Microprocessor Without Interlocked Pipeline Stages) foi desenvolvido na década de 1980, pela empresa MIPS Technologies, formada por pesquisadores da Universidade de Stanford. Utiliza a linguagem assembly, de baixo nível (linguagem de baixo nível trata-se de uma linguagem de programação que segue as características da arquitetura do computador, utiliza somente instruções que serão executadas pelo processador. Em contrapartida as linguagens de alto nível que utilizam instruções abstratas, geralmente escritas em inglês, são mais facilmente compreendidas por humanos, mas posteriormente transformadas em assembly pelo compilador, sem que possamos perceber).
Conceito
Assembly é uma linguagem de montagem. Ou seja, diferente da maioria das outras linguagens, que são compiladas e/ou interpretadas, programar em Assembly é escrever um código que é diretamente entendido pelo hardware. Assembly é a linguagem que usamos para falar com os mais diversos tipos de hardwares, como os microprocessadores e microcontroladores.
Além disso, Assembly é uma linguagem de baixo nível, ou seja, que trabalha diretamente com os registradores do processador, manipulando dados. Nesse sentido, as linguagens de baixo nível estão diretamente relacionadas com a arquitetura do computador.
Portanto, para aprender a linguagem Assembly, é preciso entender como seu computador funciona, como sua memória está organizada, os registradores que possui, as instruções disponíveis, dentre outros detalhes.
os registradores
Os registradores podem ser representados por $s0, $s1, $t1, $v0... entre outros, depende da arquitetura (64 - bits, 32 - bits, etc) e do tipo de operação necessária (registradores temporários, chamada de funções, etc.). São responsáveis por armazenar o dado e realizar o que foi solicitado pelo programa. Exemplo: ele pode pegar um valor e calculá-lo na ULA, gravá-lo na memória, entre outros.
Interação dos registradores:
operações aritméticas
Fazemos cálculos com registradores através de uma ligação entre Registrador e ULA, e para calcular usamos as seguintes operações:
Adição - ADD
Subtração - SUB
Multiplicação - MUL
Divisão - DIV
Ex: $s1 = 4, $s2 = 2
Onde o valor será calculado e gravado no primeiro registrador, que neste caso é o $s0:
ADD $s0, $s1, $s2 //$s0 = 6
SUB $s0, $s1, $s2 //$s0 = 2
MUL $s0, $s1, $s2 //$s0 = 8
DIV $s0, $s1, $s2 //$s0 = 2
Se colocarmos o "I" na frente da operação, podemos calcular um registrador com um número.
ADDI $s0, $s1, 5 //4 + 5 = 9
SUBI $s0, $s1, 1 //4 - 1 = 3
MULI $s0, $s2, 5 //2 * 5 = 10
DIVI $s0, $s2, 2 //2 / 2 = 1
Abaixo, vídeos sugeridos para estudo dos operadores:
ler e gravar dados nA MEMÓRIA RAM
Para escrever na memória usamos o comando SW (Store Word).
Ex: A sintaxe abaixo representa respectivamente, o comando SW, o registrador cujo valor deseja armazenar na memória e o valor da posição do endereço de memória desejado, que no caso significa 0 + $zero(Registrador que por padrão possui o valor zero).
SW $s0, 0($zero)
Para ler na memória usamos o comando LW (Load Word).
Ex: A sintaxe abaixo representa respectivamente, o comando LW, o registrador cujo valor deseja armazenar na memória e o valor da posição do endereço de memória desejado, que no caso significa 0 + $zero(Registrador que por padrão possui o valor zero).
LW $s0, 0($zero)
instruções de desvio
São usados para saltar o código para fazer uma condição, uma repetição, etc. São comuns em if, while e for. Em assembly, primeiro utilizamos uma instrução de comparação (<, <=, >, >=). Após isso, verificamos se o valor retornado por essa instrução foi sim (1) ou não (0).
Instruções de comparação:
SLT - SET LOWER THAN (menor que)
SGE - SET GREATER EQUAL (maior ou igual)
Exemplo de sintaxe: SLT $T0, $S1, $S2 // Adiciona o valor 1 (true) ao registrador temporário $T0 se $S1 < $S2.
SGE $T0, $S1, $S2 // Adiciona o valor 1 (true) ao registrador temporário $T0 se $S1 >= $S2
BEQ (Branch Equal) - Compara o valor do registrador temporário obtido nas instruções acima, a qual se o resultado for igual ao do registrador comparado, ele realiza o salto.
BNE (Branch Not Equal) -Compara o valor do registrador temporário obtido nas instruções de comparação, a qual se o resultado NÃO for igual ao do registrador comparado, ele realiza o salto.
J (Jump) - Salta para o endereço sem fazer nenhuma condição.
Exemplos abaixo:
Em C#
Em Assembly fica:
Em C#
Em Assembly
Acesso a memória ram
Os registradores acessam a memória RAM para salvar ou ler dados:
Vetor em assembly
A maior diferença do vetor, é que em assembly os índices são de 4 em 4 bits, ou seja, a cada "casa" somam-se 4 unidades no endereço de memória. Logo, para calcular o deslocamento total, basta multiplicar o número desejado por 4.
Exemplo:
MULI $T2, $T0, 4
E depois é necessário ler a memória do vetor:
LW $S1, 12($T2)
Abaixo, vemos a soma dos valores de um vetor em C#.
Em Assembly ficaria semelhante a isso:
agora, resolva o exercício abaixo
Utilizando o conteúdo aprendido, transforme o código abaixo de C# para Assembly:
Resposta abaixo:
Conclusões
Esperamos ter solucionado suas dúvidas, ou ao menos tê-las criado!
Esse tutorial é uma adaptação de ASSEMBLY MIPS , feito por Assuério Batista.
Links úteis:
Comentários