Ponto Flutuante no MIPS

instrução MIPS LW e SW IF Simples no MIPS

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.

Mars Ponto Flutuante
Mars Ponto Flutuante

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:

.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.

 

.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.

 

.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.

 

.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:

.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:

.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

.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:

.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:

.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:

.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:

.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:

.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.

Outros artigos da série

<< Compilando o comando FOR no MIPS
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Elaine Cecília Gatto
Bacharel em Engenharia de Computação. Mestre em Ciência da Computação. Doutoranda em Ciência da Computação. Co-fundarora e Líder das #GarotasCPBr. Pesquisadora Convidada no Grupo de Pesquisa: "Artes em Tecnologias Emergentes" do Programa de Pós Graduação em Design na UNESP Campus Bauru. Cantora, Docente no Magistério Superior, Geek, Nerd, Otaku e Gamer. Apaixonada por Michael Jackson, Macross, Rocky Balboa, Séries, Filmes, Cervejas e Vinhos. Mais informações sobre mim você encontra em: http://lattes.cnpq.br/8559022477811603.

Deixe um comentário

avatar
 
  Notificações  
Notificar