- Arquitetura de Conjunto de Instruções MIPS
- Primeira Instrução MIPS
- Compilação de Expressões no MIPS
- Convertendo uma instrução com Array no MIPS
- Armazenando um valor em Array no MIPS
- Instruções LW e SW com Array no MIPS
- Instrução IF Simples no MIPS
- Instrução IF Composto no MIPS
- Instrução SLT no MIPS
- Operações Lógicas no MIPS
- Operação Lógica AND no MIPS
- Operação Lógica OR no MIPS
- Operação Lógica NOT no MIPS
- Endereços de Memória no MIPS
- Operandos Imediatos e Constantes no MIPS
- Compilando Arrays com índice variável no MIPS
- Testando as instruções MIPS no MARS
- Executando um Array no MARS para MIPS
- Sinal e Overflow no MIPS
- Compilando instruções com ou sem Sinal, Overflow e Imediato no MIPS
- Compilando While no MIPS
- Compilando Switch/Case no MIPS
- Compilando Funções e Procedimentos no MIPS
- Compilando Procedimentos Recursivos e Aninhados no MIPS
- Detalhamento da Compilação de Procedimentos no MIPS
- MIPS: Instruções de Multiplicação
- MIPS: Instruções de Divisão
- MIPS: Subtração e outras instruções
- Compilando o comando FOR no MIPS
- Ponto Flutuante no MIPS
- Convertendo Código de Máquina em Assembly MIPS – Parte 1
- MIPS: Resolução dos exercícios – Parte 1
- MIPS: Resolução de Exercícios Parte 2
Oi pessoal!!! Nos artigos anteriores eu mostrei a vocês as instruções MIPS de Multiplicação e Divisão. Hoje aprenderemos mais sobre instruções aritméticas MIPS. Preparados?
Subtração com overflow
Sub = Subtract Word (Subtrair palavra). O valor da palavra de 32 bits no registrador RT é subtraído do valor de 32 bits no registrador RS para produzir um resultado de 32 bits. Se a subtração resultar em estouro aritmético (overflow) do complemento de 2 de 32 bits, o registrador de destino não será modificado e ocorrerá uma exceção de Integer. Se não houver overflow, o resultado de 32 bits será colocado no registrador rd.
Sintaxe: sub rd, rs, rt
Formato:
opcode |
rs |
rt |
rd |
shamt |
funct |
000000 |
|
|
|
|
0x22 |
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits |
Exemplo:
1 2 3 4 |
.text li $s2, 10 #carrega o valor imediato 10 no registrador s2 (li = load immediate) li $s3, 2 #carrega o valor imediato 3 no registrador s3 sub $s1, $s2, $s3 #executa a subtração entre s2 e s3 |
Figura:
Como podemos notar pelo Exemplo, a instrução SUB funciona da mesma forma que a instrução ADD e nós já a estudamos em outros artigos!
Subtração sem overflow
O valor da palavra de 32 bits no registrador RT é subtraído do valor de 32 bits no registrador RS e o resultado aritmético de 32 bits é colocado registrador RD. Nenhuma exceção de estouro de número inteiro ocorre sob nenhuma circunstância.
Sintaxe: subu rd, rs, rt
Formato:
opcode |
rs |
rt |
rd |
shamt |
funct |
000000 |
|
|
|
|
0x23 |
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits |
Exemplo:
1 2 3 4 |
.text li $s2, 10 #carrega o valor imediato 10 no registrador s2 (li = load immediate) li $s3, 2 #carrega o valor imediato 3 no registrador s3 subu $s1, $s2, $s3 #executa a subtração entre s2 e s3 |
Figura:
Valor Absoluto
Essa instrução é na verdade uma pseudoinstrução. Caso você não saiba o que é valor absoluto, aqui você pode encontrar uma explicação.
Sintaxe: abs r_destino, r_source
Exemplo:
1 2 3 |
.text li $s2, -10 abs $s1, $s2 |
Figura:
O número -10 em hexadecimal é fffffff6, o qual é armazenado no registrador $s2 (ou registrador $18). O registrador $s1 é o $17 e o registrador $s2 é o $18. Vejamos o que acontece no MARS:
Na primeira linha vemos a instrução ADDIU que faz uma soma do número imediato 0xfffffff6 (-10) com o valor zero do registrador $0 (zero) e armazena o resultado no registrador $18 ($s2). Na segunda linha temos a instrução SRA que já foi explicada também no artigo sobre multiplicação. A instrução SRA executa um deslocamento aritmético à direita, de uma palavra, por um número fixo de bits, que no nosso caso aqui é o valor 0x0000001f (31). Quando executamos esta linha, o registrador $s2 tem o valor 0x000000f6, e o registrador $1 passa ter o valor 0xffffffff. Na terceira linha temos a instrução XOR que é uma operação lógica. XOR significa exclusive or (ou exclusivo) e tem a seguinte tabela verdade:
E1 |
E2 |
S |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
Onde E1 é entrada 1, E2 é entrada 2 e S é saída. Quando a entrada E1 for zero e a entrada E2 também for zero, a saída será zero. Observe que quando a E1 for um, e a E2 também for um, a saída também será zero. Note também que quando E1 é igual zero e E2 é igual a um, a saída é um, e quando E1 é um e E2 é zero, a saída também é um. Isso significa que, quando as entradas forem iguais, a saída será zero e, quando as entradas forem diferentes a saída será um. Esse é o comportamento da XOR.
Em nosso exemplo será executada uma operação XOR entre os registradores $1 e $18, os quais valem no momento da execução 0xffffffff e 0xffffff6, que vai resultar no valor 0x00000009, o qual é armazenado no registrador $17. Por fim, na quarta linha, é executada a instrução sub entre os valores armazenados nos registradores $17 (0x00000009) e $1 (0xffffffff) e o resultado, 0x0000000a (10), é guardado em $17.
A operação XOR combina o conteúdo do registrador RS e do registrador RT em uma operação exclusiva de bit a bit (bitwise) lógica e coloca o resultado no registrador RD. Em termos mais simples seria algo como RD = RS XOR RT, onde sabemos que RD é o registador destino (nosso S da tabela verdade) e RS e RT são os registradores fonte (nosso E1 e E2 da tabela verdade). O formato da instrução XOR é:
Formato:
opcode |
rs |
rt |
rd |
shamt |
funct |
000000 |
|
|
|
|
100110 |
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits |
É dessa foram que se obtém o número absoluto em linguagem assembly MIPS. Vamos ver um exemplo com o número +10 (que é A em hexadecimal):
1 2 3 |
.text li $s2, +10 abs $s1, $s2 |
Note que a execução ocorreu exatamente da mesma forma que antes!
Contar uns iniciais
clo = Count Leading Ones in Word (Conte os uns iniciais na palavra). O objetivo desta instrução é contar os uns iniciais em uma palavra. Os bits de 31 até 0 do registrador geral RS são escaneados do bit mais significativo para o menos significativo. O número de uns iniciais é contado e o resultado é gravado no registrador RD. Se todos os bits de 31 até 0 foram configurados no registrador RS, o resultado será gravado no registrador RD.
Um detalhe importante: para estar em conformidade com a arquitetura MIPS32 e MIPS64, o software deve colocar o mesmo número de registrador nos campos RT e RD da instrução. A operação da instrução é IMPREVISÍVEL se os campos RT e RD da instrução contiverem valores diferentes.
Sintaxe: clo rd, rs
Formato:
opcode |
rs |
rt |
rd |
shamt |
funct |
0x1c |
|
0 |
|
0 |
0x21 |
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits |
Exemplo:
1 2 3 |
.text li $s2, -10 clo $s1, $s2 |
Figura:
No MARS você notará que a quantidade de uns será armazenada no registrador $17, que neste caso será 0x0000001c. Teste com outros números e veja o acontece.
Contar zeros iniciais
clz = Count Leading Zeros in Word (Conte os zeros iniciais na palavra). O objetivo desta instrução é contar os zeros iniciais em uma palavra. Os bits de 31 até 0 do registrador geral RS são escaneados do bit mais significativo para o menos significativo. O número de zeros iniciais é contado e o resultado é gravado no registrador RD. Se todos os bits de 31 até 0 foram configurados no registrador RS, o resultado será gravado no registrador RD.
Um detalhe importante: para estar em conformidade com a arquitetura MIPS32 e MIPS64, o software deve colocar o mesmo número de registrador nos campos RT e RD da instrução. A operação da instrução é IMPREVISÍVEL se os campos RT e RD da instrução contiverem valores diferentes.
Sintaxe: clz rd, rs
Formato:
opcode |
rs |
rt |
rd |
shamt |
funct |
0x1c |
|
0 |
|
0 |
0x20 |
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits |
Exemplo:
1 2 3 |
.text li $s2, 10 clz $s1, $s2 |
Figura:
No MARS você notará que a quantidade de zeros será armazenada no registrador $17, que neste caso será 0x0000001c. Teste com outros números e veja o que acontece.
Negar valor com overflow
Esta instrução realiza a negação de um número hexadecimal.
Sintaxe: neg r_destino, r_source
Exemplo:
1 2 3 |
.text li $s1, 10 neg $s0, $s1 |
Figura:
Negar valor sem overflow
Esta instrução realiza a negação de um número hexadecimal. A diferença desta instrução para a anterior é apenas o fato de que esta não trata overflow, enquanto que a NEG trata o overflow. Atente-se para o opcode dado na execução do MARS conforme mostra a Figura.
Sintaxe: negu r_destino, r_source
Exemplo:
1 2 3 |
.text li $s1, 10 negu $s0, $s1 |
Figura:
Resto
Esta pseudoinstrução coloca o resto do registrador r_source1 dividido pelo registrador r_source2 no registrador r_destino.
Sintaxe: rem r_destino, r_source1, r_source2
Exemplo:
1 2 3 4 |
.text li $s1, 10 li $s2, 2 rem $s0, $s1, $s2 |
Figura:
A pseudoinstrução REM, e a REMU, a seguir, abrem uma sequencia de instruções que incluem BNE, BREAK, DIVU e MFHI, todas elas nós já estudamos. Como exercício, vou pedir para que vocês tentem compreender o que está acontecendo, já que as instruções são conhecidas! Deixem suas dúvidas nos comentários tá bom.
Resto sem sinal
Esta pseudonstrução coloca o resto do registrador r_source1 dividido pelo registrador r_source2 no registrador r_destino. Se um operando for negativo, o resto não é especificado pela arquitetura MIPS e depende da convenção da máquina.
Sintaxe: remu r_destino, r_source1, r_source2
Exemplo
1 2 3 4 |
.text li $s1, 10 li $s2, 2 remu $s0, $s1, $s2 |
Figura:
Conclusão
Por hoje é só pessoal! Mas continuem atentos, em breve mais artigos com mais instruções!