0% acharam este documento útil (0 voto)
4 visualizações13 páginas

Significado e Estudo de MIPS Assembly

Este guia de estudos aborda a programação em Assembly, focando nas arquiteturas MIPS e RISC-V. Ele cobre fundamentos da linguagem Assembly, estrutura de programas, registradores, instruções essenciais, controle de fluxo, funções e a pilha, além de tutoriais práticos. O documento também destaca as diferenças entre MIPS e RISC-V, incluindo suas convenções de chamada e formatos de instrução.

Enviado por

delaquamaycon
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
4 visualizações13 páginas

Significado e Estudo de MIPS Assembly

Este guia de estudos aborda a programação em Assembly, focando nas arquiteturas MIPS e RISC-V. Ele cobre fundamentos da linguagem Assembly, estrutura de programas, registradores, instruções essenciais, controle de fluxo, funções e a pilha, além de tutoriais práticos. O documento também destaca as diferenças entre MIPS e RISC-V, incluindo suas convenções de chamada e formatos de instrução.

Enviado por

delaquamaycon
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Guia de Estudos Completo: Assembly MIPS e RISC-V

Este guia foi elaborado a partir dos seus materiais de slide para fornecer um roteiro
de estudos abrangente sobre programação em Assembly, com foco nas arquiteturas
MIPS e RISC-V.

Parte 1: Fundamentos da Linguagem Assembly


Antes de mergulhar nas especificidades de MIPS ou RISC-V, é crucial entender os
conceitos universais da programação Assembly.

1.1. O que é Linguagem Assembly?


A Linguagem Assembly é uma linguagem de programação de baixo nível, o que
significa que ela está muito próxima do hardware do computador. Cada arquitetura de
processador (como Intel x86, ARM, MIPS, RISC-V) tem seu próprio conjunto de
instruções e, portanto, sua própria linguagem Assembly.
●​ Correspondência Direta: Geralmente, uma instrução em Assembly corresponde
a uma única instrução de código de máquina (os 0s e 1s que o processador
entende).
●​ Por que aprender?
○​ Compreensão Profunda: Entender como o computador funciona em seu
nível mais fundamental (gerenciamento de memória, registradores, CPU).
○​ Otimização: Escrever código extremamente rápido para tarefas críticas onde
cada ciclo de clock conta.
○​ Depuração: Analisar o que acontece "por baixo dos panos" em linguagens de
alto nível como C++ ou Python.
1.2. Estrutura Básica de um Programa Assembly
Um programa em Assembly é tipicamente dividido em seções (ou segmentos) para
organizar dados e código.
●​ Seção .data: Onde você declara variáveis estáticas e constantes que seu
programa usará. Os dados são armazenados na memória principal.
○​ Exemplo de diretiva: .word para alocar 4 bytes para um número inteiro,
.asciiz para alocar espaço para uma string.
●​ Seção .text: Onde fica o código executável, ou seja, as instruções que o
processador irá executar.
○​ Exemplo de diretiva: .globl main para declarar o ponto de entrada main
como visível globalmente.
Questão de Prova (Conceitual):
“Explique a finalidade das seções .data e .text em um programa Assembly.
Dê um exemplo de uma diretiva que seria usada em cada uma e justifique
sua escolha.”

Parte 2: Guia de Estudos MIPS (com RARS)


Esta seção foca na arquitetura MIPS, muito comum em ambientes acadêmicos e
perfeitamente simulada pelo RARS (RARS MIPS Assembler and Runtime Simulator).

2.1. Registradores MIPS


Registradores são pequenas áreas de armazenamento de altíssima velocidade dentro
da CPU. MIPS possui 32 registradores de uso geral. É vital conhecer suas convenções
de uso.

Nome Número Uso Comum Quem Salva?

$zero $0 Valor constante 0 N/A


(não pode ser
alterado)

$v0-$v1 $2-$3 Valores de retorno de Chamado


funções e código de
syscall

$a0-$a3 $4-$7 Argumentos de Chamador


funções

$t0-$t9 $8-$15 Temporários (podem Chamador


ser sobrescritos)

$s0-$s7 $16-$23 Salvos (devem ser Chamado


preservados por
funções)

$sp $29 Stack Pointer N/A


(Ponteiro da Pilha)

$ra $31 Return Address Chamador


(Endereço de
Retorno)

Questão de Prova (Convenções):


“Você está escrevendo uma função em MIPS que precisa de 5 variáveis
temporárias. Dentro dessa função, você chama outra função. Quais tipos
de registradores ($t ou $s) você deve usar para armazenar suas variáveis
para garantir que seus valores não sejam perdidos após a chamada da
outra função? Explique o porquê.”
Resposta: Você deve usar os registradores $s (salvos). A convenção de
chamada MIPS dita que uma função chamada (callee) é obrigada a salvar
o valor original dos registradores $s na pilha e restaurá-los antes de
retornar. Já os registradores $t (temporários) podem ser livremente
sobrescritos pela função chamada.

2.2. Instruções Essenciais e Entrada/Saída


Instruções de Dados
●​ li $t0, 100: Load Immediate. Carrega o valor 100 no registrador $t0.
●​ la $a0, minhaString: Load Address. Carrega o endereço de memória da variável
minhaString em $a0.
●​ lw $t0, minhaVariavel: Load Word. Carrega o valor de 4 bytes armazenado no
endereço de minhaVariavel para $t0.
●​ sw $t0, resultado: Store Word. Salva o valor de $t0 no endereço de memória
resultado.
●​ move $t1, $t0: Copia o valor de $t0 para $t1.

Entrada e Saída com syscall


A interação com o usuário (ler teclado, imprimir na tela) é feita através de chamadas
de sistema (syscall).
1.​ Coloque o código do serviço em $v0.
2.​ Coloque os argumentos (se houver) em $a0, $a1, etc.
3.​ Execute a instrução syscall.

Serviço Código em $v0 Argumento(s) em $a0...

print_int 1 $a0 = inteiro a ser impresso

print_string 4 $a0 = endereço da string a


ser impressa

read_int 5 (Nenhum) - O resultado volta


em $v0

read_string 8 $a0 = buffer, $a1 = tamanho


máximo
exit 10 (Nenhum) - Termina o
programa

2.3. Tutorial Passo a Passo: "Olá Mundo" em MIPS


Vamos criar um programa que imprime uma mensagem e um número.

# Seção de dados: onde declaramos nossas variáveis​


.data​
mensagem: .asciiz "Olá Mundo do MIPS! O número é: " # String terminada com nulo​

# Seção de texto: onde escrevemos nosso código executável​
.text​
.globl main​

main:​
# --- Imprimir a string "Olá Mundo..." ---​
# Passo 1: Carregar o código do serviço 'print_string' (4) em $v0.​
li $v0, 4​

# Passo 2: Carregar o endereço da nossa variável 'mensagem' em $a0.​
la $a0, mensagem​

# Passo 3: Chamar o sistema operacional para executar o serviço.​
syscall​

# --- Imprimir o número 42 ---​
# Passo 1: Carregar o código do serviço 'print_int' (1) em $v0.​
li $v0, 1​

# Passo 2: Carregar o valor 42 em $a0, que é o argumento para print_int.​
li $a0, 42​

# Passo 3: Chamar o sistema.​
syscall​

# --- Finalizar o programa ---​
# Passo 1: Carregar o código do serviço 'exit' (10) em $v0.​
li $v0, 10​

# Passo 2: Chamar o sistema.​
syscall​

2.4. Controle de Fluxo: Desvios e Saltos


●​ Desvios Condicionais (Branches):
○​ beq $t0, $t1, rotulo: Branch if Equal. Salta para rotulo se $t0 == $t1.
○​ bne $t0, $t1, rotulo: Branch if Not Equal. Salta para rotulo se $t0 != $t1.
●​ Comparações:
○​ slt $t0, $s1, $s2: Set if Less Than. Se $s1 < $s2, então $t0 recebe 1, senão
recebe 0.
●​ Saltos Incondicionais (Jumps):
○​ j rotulo: Salta incondicionalmente para rotulo.
○​ jr $ra: Jump Register. Salta para o endereço contido em $ra. Usado para
retornar de funções.
2.5. Tutorial Passo a Passo: Loop para Somar de 1 a N
Este programa lê um número N e calcula a soma de 1 até N.

.data​
prompt_N: .asciiz "Digite um número N: "​
msg_soma: .asciiz "A soma de 1 a N é: "​
nova_linha: .asciiz "\n"​

.text​
.globl main​

main:​
# --- Solicitar e ler N ---​
li $v0, 4​
la $a0, prompt_N​
syscall​

li $v0, 5​
syscall​
move $s0, $v0 # Salva N no registrador salvo $s0​

# --- Inicializar variáveis do loop ---​
li $t0, 1 # i = 1 (contador do loop em $t0)​
li $s1, 0 # soma = 0 (acumulador em $s1)​

loop_inicio:​
# Condição de saída: se i > N, sair do loop.​
# Usamos bgt (Branch if Greater Than), uma pseudo-instrução.​
# bgt $t0, $s0, loop_fim é o mesmo que slt $at, $s0, $t0; bne $at, $zero, loop_fim​
bgt $t0, $s0, loop_fim​

# --- Corpo do loop ---​
# soma = soma + i​
add $s1, $s1, $t0​

# i = i + 1​
addi $t0, $t0, 1​

# Voltar ao início do loop​
j loop_inicio​

loop_fim:​
# --- Imprimir o resultado ---​
li $v0, 4​
la $a0, msg_soma​
syscall​

li $v0, 1​
move $a0, $s1 # Mover a soma ($s1) para $a0 para impressão​
syscall​

# --- Sair do programa ---​
li $v0, 10​
syscall​

Questão de Prova (Programação):


“Escreva um programa completo em Assembly MIPS que leia dois inteiros,
A e B, e imprima o maior deles. Se forem iguais, imprima qualquer um dos
dois.”
2.6. Funções e a Pilha (Stack)
●​ Chamando uma função: jal nome_funcao (Jump and Link). Salta para
nome_funcao e salva o endereço da próxima instrução em $ra.
●​ Retornando de uma função: jr $ra.
●​ A Pilha ($sp): A pilha é uma área da memória para armazenamento temporário.
Ela cresce de endereços maiores para menores. É usada para:
1.​ Salvar registradores $s que a função vai modificar.
2.​ Salvar $ra se a função for chamar outra função (chamada aninhada).
3.​ Passar argumentos extras que não cabem em $a0-$a3.

Tutorial Passo a Passo: Função Fatorial Recursiva


O fatorial é o exemplo clássico para entender a pilha. fat(n) = n * fat(n-1).

# ... (seções .data e main para ler o número e imprimir o resultado) ...​

# Função fatorial(n)​
# Argumento: $a0 = n​
# Retorno: $v0 = n!​
fatorial:​
# --- Prólogo da Função: Preparar a pilha ---​
# Alocar espaço para 2 palavras (8 bytes) na pilha: uma para $ra e outra para $a0.​
addi $sp, $sp, -8​
sw $ra, 4($sp) # Salvar o endereço de retorno do chamador​
sw $a0, 0($sp) # Salvar o 'n' atual​

# --- Caso Base: se n < 1, retorna 1 ---​
slti $t0, $a0, 1 # $t0 = 1 se n < 1​
bne $t0, $zero, caso_base​

# --- Passo Recursivo: n * fatorial(n-1) ---​
# Preparar argumento para a chamada recursiva​
addi $a0, $a0, -1 # $a0 = n - 1​

# Chamar a si mesma​
jal fatorial​

# Após o retorno, $v0 contém fatorial(n-1).​
# Precisamos restaurar o 'n' original para multiplicar.​
lw $a0, 0($sp) # Restaurar 'n' original da pilha para $a0​

# Calcular n * (n-1)!​
mul $v0, $a0, $v0 # $v0 = n * resultado da chamada recursiva​

# Pular para o final para restaurar a pilha e retornar​
j fim_funcao​

caso_base:​
li $v0, 1 # Retorna 1​

fim_funcao:​
# --- Epílogo da Função: Restaurar a pilha ---​
lw $ra, 4($sp) # Restaurar o endereço de retorno original​
addi $sp, $sp, 8 # Liberar o espaço alocado na pilha​

# Retornar ao chamador​
jr $ra​

Parte 3: Guia de Estudos RISC-V


RISC-V é uma arquitetura moderna, aberta e também baseada em princípios RISC. Ela
compartilha muitos conceitos com MIPS, mas possui diferenças importantes.

3.1. Registradores RISC-V


RISC-V também tem 32 registradores de uso geral (x0 a x31), mas os nomes
mnemônicos (ABI - Application Binary Interface) são um pouco diferentes.

Nome ABI Registrador Uso Comum Quem Salva?

zero x0 Valor constante 0 N/A

ra x1 Return Address Chamador


(Endereço de
Retorno)

sp x2 Stack Pointer N/A


(Ponteiro da Pilha)

a0-a7 x10-x17 Argumentos de Chamador


função e valores de
retorno (a0-a1)

s0-s11 x8-x9, x18-x27 Salvos (devem ser Chamado


preservados)

t0-t6 x5-x7, x28-x31 Temporários (podem Chamador


ser sobrescritos)

3.2. Formatos de Instrução


Uma característica chave do RISC-V é seu conjunto de instruções bem definido e
modular. As instruções se encaixam em alguns formatos básicos (R, I, S, B, U, J), o que
simplifica o design do processador.
●​ Formato R (Register): Operações entre registradores. Ex: add x5, x6, x7
●​ Formato I (Immediate): Operações com um valor imediato (constante). Ex: addi
x5, x6, 100
●​ Formato S (Store): Armazenamento de dados na memória. Ex: sw x5, 0(x6)
●​ Formato B (Branch): Desvios condicionais. Ex: beq x5, x6, rotulo

3.3. Entrada e Saída com ecall


Em RISC-V, a chamada de sistema é feita pela instrução ecall (Environment Call). A
convenção é similar à do MIPS, mas os registradores são diferentes.
1.​ Coloque o código do serviço em a7.
2.​ Coloque os argumentos em a0, a1, etc.
3.​ Execute ecall.

(Os códigos de serviço podem variar dependendo do simulador/SO. No RARS (que


também suporta RISC-V), os códigos são os mesmos do MIPS, mas usando os
registradores a7 e a0).

3.4. Tutorial Passo a Passo: Somando dois números em RISC-V


.data​
msg_1: .asciz "Informe o primeiro numero: "​
msg_2: .asciz "Informe o segundo numero: "​
resultado: .asciz "Resultado: "​

.text​
.global main​

main:​
# --- Ler primeiro número ---​
li a7, 4 # Código para PrintString​
la a0, msg_1 # Endereço da string em a0​
ecall​

li a7, 5 # Código para ReadInt​
ecall​
mv t0, a0 # Mover resultado (que vem em a0) para t0​

# --- Ler segundo número ---​
li a7, 4​
la a0, msg_2​
ecall​

li a7, 5​
ecall​
mv t1, a0 # Mover resultado para t1​

# --- Somar e imprimir ---​
add t2, t0, t1 # t2 = t0 + t1​

li a7, 4​
la a0, resultado​
ecall​

li a7, 1 # Código para PrintInt​
mv a0, t2 # Mover a soma (t2) para a0​
ecall​

# --- Sair ---​
li a7, 93 # Código para Exit em muitos ambientes RISC-V​
ecall​

Questão de Prova (Comparativa):


“Descreva as principais diferenças entre MIPS e RISC-V no que diz respeito
à convenção de chamada de sistema (syscall vs ecall) e aos registradores
utilizados para passar o código do serviço e os argumentos.”
3.5. Funções em RISC-V
O conceito é idêntico ao MIPS, mas com instruções e registradores diferentes.
●​ Chamando uma função: jal ra, nome_funcao (Jump and Link). Salva o endereço
de retorno em ra e salta.
●​ Retornando: ret (que é uma pseudo-instrução para jalr zero, 0(ra)).

A gestão da pilha (sp), salvamento de registradores s e do ra em chamadas aninhadas


segue a mesma lógica do MIPS.

Parte 4: Mapa Mental para Fixação


Programação Assembly​
├── 1. Fundamentos​
│ ├── Linguagem de Baixo Nível​
│ ├── Estrutura do Programa​
│ │ ├── .data (Variáveis, Constantes)​
│ │ └── .text (Código, Instruções)​
│ └── Registradores (Armazenamento rápido na CPU)​
│​
├── 2. Arquitetura MIPS (RARS)​
│ ├── Registradores ($v, $a, $t, $s, $sp, $ra)​
│ ├── Instruções​
│ │ ├── Aritméticas (add, addi, sub, mul, div)​
│ │ ├── Dados (li, la, lw, sw, move)​
│ │ └── Controle de Fluxo (beq, bne, slt, j, jr)​
│ ├── Syscalls (Entrada/Saída via $v0)​
│ └── Funções (jal, jr $ra, Pilha $sp)​
│​
├── 3. Arquitetura RISC-V​
│ ├── Registradores (zero, ra, sp, a0-a7, s0-s11, t0-t6)​
│ ├── Formatos de Instrução (R, I, S, B, U, J)​
│ ├── Instruções (Similares ao MIPS, sintaxe pode variar)​
│ ├── Ecalls (Entrada/Saída via a7)​
│ └── Funções (jal, ret, Pilha sp)​
│​
└── 4. Tópicos Avançados (Comuns a Ambos)​
├── A Pilha (Stack)​
│ ├── Prólogo e Epílogo de Funções​
│ └── Salvamento de Registradores​
├── Recursão​
├── Vetores (Arrays)​
│ ├── Alocação de Memória​
│ └── Cálculo de Endereço (base + índice * tamanho_do_tipo)​
└── Strings (Vetores de caracteres com terminador nulo)​

Parte 5: Tabela de Resolução de Problemas


Use esta tabela como um guia rápido para decidir como abordar problemas comuns.

Tipo de Conceitos-Cha Instruções Instruções Estratégia /


Problema ve Envolvidos Comuns (MIPS) Comuns Dica
(RISC-V)

Cálculos Registradores, add, addi, sub, add, addi, sub, Carregue os


Matemáticos Instruções mul, div, mflo, mul, div, rem operandos da
Aritméticas mfhi memória para
registradores
(lw), execute a
operação e
armazene o
resultado (sw).

Tomada de Desvios beq, bne, slt, beq, bne, blt, Use uma
Decisão Condicionais, bgt, ble bge comparação
(if/else) Comparações (slt) seguida de
um desvio (bne,
beq) para criar a
lógica if. O else
é o código que
não é saltado.

Loops Desvios bne, beq, addi, j bne, beq, addi, j 1. Inicialize o


(for/while) Condicionais e contador. 2. Crie
Incondicionais, um rótulo de
Contadores início. 3.
Verifique a
condição de
saída. 4. Corpo
do loop. 5.
Incremente. 6.
Salte (j) para o
início.
Chamada de Convenção de jal, jr $ra, jal, ret, a0-a7 Passe
Funções Chamada, $a0-$a3, $v0 argumentos nos
Simples Argumentos, registradores a,
Retorno chame com jal,
pegue o
resultado do
registrador de
retorno
($v0/a0).

Funções A Pilha ($sp), addi $sp, $sp, addi sp, sp, -X, Prólogo: Salve
Recursivas / Endereço de -X, sw, lw, jr $ra sw, lw, ret $ra e os
Aninhadas Retorno ($ra), registradores $s
Registradores que for usar na
Salvos ($s) pilha. Epílogo:
Restaure-os na
ordem inversa e
retorne.

Manipulação Endereçamento la, lw, sw, sll la, lw, sw, slli Carregue o
de Vetores de Memória, (para multiplicar (para multiplicar endereço base
(Arrays) Loops, Ponteiros índice) índice) do vetor em um
registrador. Para
acessar vetor[i],
calcule
endereço_base
+ i * 4 (para
words). Use um
loop para iterar.

Manipulação Vetor de bytes, la, lb (Load la, lb, sb Trate strings


de Strings Terminador Byte), sb (Store como vetores de
Nulo, Loops Byte) bytes. Um loop
que termina
quando
encontra o
caractere nulo
(\0) é a
abordagem
padrão.

Você também pode gostar