- 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! No último artigo da série MIPS eu mostrei como compilar o comando FOR e, portanto, dessa forma, todos os comandos de controle foram tratados nesta série. Em outros artigos, também expliquei as instruções aritméticas, lógicas e relacionais, assim como também os procedimentos. De maneira geral, vimos praticamente tudo a respeito de MIPS. Como existem muitas instruções, eu tratei das mais importantes aqui nesta série, mas se você consultar a documentação oficial do MIPS, você encontrará muitas outras, que normalmente são variações das principais. Falta falar sobre Ponto Flutuante, que será o tema deste artigo. Vamos nessa então?
Ponto Flutuante
O coprocessador 1 do MIPS é usado para Ponto Flutuante (P.F.). Ele lida com precisão simples, o que é equivalente a 32 bits, e precisão dupla, 64 bits. Se observarmos no MARS, veremos uma parte dedicada somente a este coprocessador, conforme mostra a Figura abaixo.
Os registradores são numerados de $f0 até $f31. Note também que somente os registradores pares possuem suporte à precisão dupla. Além disto, existem oito flags de código de condição (cc) que são testados, ou alterados, por instruções de movimentação condicionais, desvio e comparação. As instruções lwc1, swc1, mtc1 e mtc1 fazem a movimentação dos valores de precisão simples nesses registradores, enquanto as instruções l.s, l.d, s.s e s.d, fazem a movimentação de precisão dupla. A tabela a seguir resume as instruções de movimentação rapidamente:
Instrução |
opcode |
rs |
rt |
rd |
shamt |
funct | |
|
6 bits |
5 bits |
5 bits |
5 bits |
5 bits |
6 bits | |
mfhi rd |
0 |
0 |
rd |
0 |
0x10 | ||
mflo rd |
0 |
0 |
rd |
0 |
0x12 | ||
mthi rs |
0 |
rs |
0 |
0x11 | |||
mtlo rs |
0 |
rs |
0 |
0x13 | |||
mfc0 rt, rd |
0x10 |
0 |
rt |
rd |
0 | ||
mfcl rt, fs |
0x11 |
0 |
rt |
fs |
0 | ||
mtc0 rd, rt |
0x10 |
4 |
rt |
rd |
0 | ||
mtc1, rd, fs |
0x11 |
4 |
rt |
fs |
0 | ||
movn rd, rs, rt |
0 |
rs |
rt |
rd |
0xb | ||
movz rd, rs, rt |
0 |
rs |
rt |
rd |
0xa | ||
movf rd, rs, cc |
0 |
rs |
cc |
0 |
rd |
0 |
1 |
movt rd, rs, cc |
0 |
rs |
cc |
1 |
rd |
0 |
1 |
|
6 bits |
5 bits |
3 bits |
2 bits |
5 bits |
5 bits |
6 bits |
Os bits de 21 a 26 das instruções de ponto flutuante usam o código 0 quando for precisão simples, e 1 para precisão dupla. Vamos agora ver vários exemplos de instruções de ponto flutuante.
Instruções de P.F.
Vamos conhecer a instrução absoluto. Veja o código Assembly MIPS abaixo:
1 2 3 4 5 |
.data numero1: .float -10.5 .text lwc1 $f0, numero1 abs.d $f2, $f0 |
Diferente do que vínhamos fazendo, que era usar a instrução li para carregar números imediatos, ou la para endereços de memória, aqui devemos usar lwc1 e lwc2. Além disso, como é um número real, de precisão simples ou dupla, devemos definir o tipo do dado numérico, da mesma forma que faríamos em linguagens de programação de médio e alto nível. Não é tão difícil assim não é mesmo? Basta seguir o mesmo raciocínio lógico na programação que você conhece.
Então, primeiro, declaramos o tipo de número, usando um label. Neste exemplo, numero1 é o label que leva ao valor, do tipo float, -10.5. Somente depois disso, conseguir carregar o número para um registrador. No exemplo que estamos trabalhando, eu carreguei o numero1 para o registrador $f0, que é um registrador que lida com precisão dupla. Feito isto, aí sim podemos usar o valor em alguma instrução. Ao executar esse código Assembly MIPS no MARS você verá que ele funcionará corretamente.
A instrução abs.d encontra o valor absoluto de ponto flutuante double, enquanto a instrução abs.s, encontra o valor absoluto de ponto flutuante simples. Basicamente toda as instruções de ponto flutuante tem uma versão idêntica para precisão simples, denotada por s, e precisão dupla, denotada por d. O exemplo a seguir mostra a soma entre dois valores de ponto flutuante, usando tanto precisão simples, quanto dupla.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 .text lwc1 $f1, numero1 lwc1 $f3, numero2 lwc1 $f0, numero3 lwc1 $f2, numero4 add.d $f4, $f2, $f0 add.s $f5, $f1, $f3 |
Note que para carregar e calcular os números em precisão dupla, eu usei os registradores pares, e para a precisão simples, usei os registradores ímpares. Também usei a palavra chave double para indicar números de precisão dupla. O exemplo a seguir mostra como usar a instrução de comparação igual.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 .text # números float lwc1 $f1, numero1 lwc1 $f3, numero2 # números double lwc1 $f0, numero3 lwc1 $f2, numero4 # verifica se $f0 é igual a $f2 # a resposta fica no cc: 1 se igual, 0 se diferente c.eq.d $f0, $f2 # verifica se $f1 é igual a $f3 # a resposta fica no cc: 1 se igual, 0 se diferente c.eq.s $f1, $f3 |
A seguir, apresento vários com todas as instruções de ponto flutuante, tanto para precisão simples, quanto para precisão dupla. Se você quiser ver o resultado no console, você deve usar as chamadas do sistema para isto, conforme mostrei no artigo sobre o FOR. Isto pode dar um pouco mais de trabalho, mas é interessante fazer para treinar seu conhecimento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text lwc1 $f1, numero1 lwc1 $f3, numero2 lwc1 $f0, numero3 lwc1 $f2, numero4 lwc1 $f5, numero5 # compara se $f0 é menor que $f2 # a resposta fica no cc: 1 se menor igual, 0 se diferente c.le.d $f0, $f2 c.le.s $f1, $f3 # compara se $f1 é menor que $f3 # a resposta fica no cc: 1 se menor igual, 0 se diferente c.lt.d $f0, $f2 c.lt.s $f1, $f3 |
Código de conversão entre precisão simples e dupla:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text lwc1 $f1, numero1 # $f1 número de precisão simples lwc1 $f3, numero2 # $f3 número de precisão simples lwc1 $f0, numero3 # $f0 número de precisão dupla lwc1 $f2, numero4 # $f4 número de precisão dupla lwc1 $f5, numero5 # $f5 número inteiro de precisão simples # converte simples para dupla # $f1 é o número de precisão simples # $f4 é o registrador que vai receber o número convertido cvt.d.s $f4, $f1 # converte dupla para simples # $f0 é o número de precisão dupla # $f7 é o registrador que vai receber o número convertido cvt.s.d $f7, $f0 |
Código de conversão de números inteiros para precisão simples e dupla:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text lwc1 $f1, numero1 # $f1 número de precisão simples lwc1 $f3, numero2 # $f3 número de precisão simples lwc1 $f0, numero3 # $f0 número de precisão dupla lwc1 $f2, numero4 # $f4 número de precisão dupla lwc1 $f5, numero5 # $f5 número inteiro de precisão simples # converte inteiro para dupla # $f5 é o número inteiro de precisão simples # $f4 é o registrador que recebe o número convertido cvt.d.w $f4, $f5 # converte inteiro para simples # $f5 é o número inteiro de precisão simples # $f4 é o registrador que recebe o número convertido cvt.s.w $f7, $f5 |
Convertendo para número inteiro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text lwc1 $f1, numero1 # $f1 número de precisão simples lwc1 $f3, numero2 # $f3 número de precisão simples lwc1 $f0, numero3 # $f0 número de precisão dupla lwc1 $f2, numero4 # $f4 número de precisão dupla lwc1 $f5, numero5 # $f5 número inteiro de precisão simples # converte dupla para inteiro # $f0 é o número de precisão dupla # $f4 é o registrador que recebe o número convertido cvt.w.d $f4, $f0 # converte simples para inteiro # $f1 é o número de precisão dupla # $f7 é o registrador que recebe o número convertido cvt.w.d $f7, $f1 |
Divisão:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 .text # números de precisão simples lwc1 $f1, numero1 lwc1 $f3, numero2 # números de precisão dupla lwc1 $f0, numero3 lwc1 $f2, numero4 # divisão dupla div.d $f4, $f0, $f2 # divisão simples div.s $f5, $f1, $f3 |
Multiplicação:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 .text # números de precisão simples lwc1 $f1, numero1 lwc1 $f3, numero2 # números de precisão dupla lwc1 $f0, numero3 lwc1 $f2, numero4 # multiplicação dupla mul.d $f4, $f0, $f2 # multiplicação simples mul.s $f5, $f1, $f3 |
Subtração:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 .text # números de precisão simples lwc1 $f1, numero1 lwc1 $f3, numero2 # números de precisão dupla lwc1 $f0, numero3 lwc1 $f2, numero4 # subtração dupla sub.d $f4, $f0, $f2 # subtração simples sub.s $f5, $f1, $f3 |
Raíz Quadrada:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text # números de precisão simples lwc1 $f1, numero1 lwc1 $f3, numero2 # números de precisão dupla lwc1 $f0, numero3 lwc1 $f2, numero4 # raíz quadrada dupla sqrt.d $f4, $f0 sqrt.d $f6, $f2 # raiz quadrada simples sqrt.s $f5, $f1 sqrt.s $f7, $f3 |
Truncamento:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.data numero1: .float 10.5 numero2: .float 2.5 numero3: .double 5.3 numero4: .double 15.9 numero5: .float 3 .text # números de precisão simples lwc1 $f1, numero1 lwc1 $f3, numero2 # números de precisão dupla lwc1 $f0, numero3 lwc1 $f2, numero4 # truncamento dupla trunc.w.d $f4, $f0 trunc.w.d $f6, $f2 # truncamento simples trunc.w.s $f5, $f1 trunc.w.s $f7, $f3 |
Conclusão
Para o artigo não ficar muito longo e cansativo, termino o assunto aqui. No próximo artigo veremos como trabalhar com as instruções de load/store e também arrays.
Sdds o próximo artigo, kkkkkkkkkk. Muito bacana esse artigo!
Obrigada e desculpe a demora!!!!
Oi Bruno, obrigada pelo seu comentário. Eu vou conferir. Tentarei responder e esclarecer todas as dúvidas nos artigos até domingo que vem (17/01/2021), assim como postar as respostas dos exercícios. Mais uma vez obrigada e solicito que aguarde ok. [ ]s