Unidade de Ponto Flutuante

A UPF tem seu próprio conjunto de registradores. Eles são organizados como uma pilha (de 8 registradores):


              --------------
              |             |
              --------------
          |   |             |
          |   --------------
pilha     |   |             |
cresce    |   --------------
         \ /  |             |
              --------------
              |             | <- st(0)  ---- top
              --------------
              |             |
              --------------
              |             |
              --------------
              |             |
              --------------

A cada instante, o nome st(0) se refere ao registrador no topo da pilha, st(1) ao anterior ("abaixo" do topo), e assim por diante. Cada registrados da pilha de ponto flutuante tem 80 bits, para maior precisão nas operações.

As instruções de transferência de dados da UFP, FLD? e FSTP? (Load e Store) movimentam dados entre memória principal e pilha de registradores.Não é possível movimentar dados diretamente entre os registradores da CPU e os da UPF.

As instruções FILD? e FIST? realizam conversões entre a representação em ponto flutuante e a representação de inteiro em complemento a 2.

atenção!! Essa é uma pilha de registradores, dentro da CPU, e não tem nada a ver com a pilha de registros de execução, cujo topo é apontado por ESP!!!!

Passagem e retorno de valores

A passagem de valores float ou double para uma função deve ser feita, como sempre, através da pilha. A convenção little-endian do pentium é estendida para o caso do double, ou seja, a palavra menos significativa deve aparecer em endereços de memória menores do que a mais significativa.

Quando uma função C retorna um valor float ou double, esse valor deve ser retornado no topo da pilha de registradores da UPF.

Exemplo de Uso da UFP

  1. A função C abaixo:
    double soma (double a, double b) {
      return a+b;
    }
    
    poderia ser escrita em assembly como:
    soma:   push  %ebp
            mov   %esp, %ebp
    
            fldl  8(%ebp)		/* carrega para a pilha da UPF a variável a */
            faddl 16(%ebp)      /* adiciona b */
    
            mov %ebp, %esp
            pop %ebp
            ret
    
  2. A função C abaixo:

    double dot (double a[], double b[], int tam) {
      int i;
      double res = 0.0;
      for (i=tam;i>0;i--)
        res += a[i]*b[i];
      return res;
    }
    
    poderia ser escrita em assembly como:
    dot:    push %ebp
            mov %esp, %ebp
    
            mov 8(%ebp), %eax   /* endereco de a */
            mov 12(%ebp), %ebx  /* endereco de b */
            mov 16(%ebp), %ecx  /* tam -  i vai ficar em um registrador! */
            mov $0, %edx
            fldz                /* coloca zero na pilha de registradores da UPF */
    
    fori:   cmp $0, %ecx
            je fim
    
            fldl (%eax)
            fmull (%ebx)
            faddp %st(0), %st(1) /* soma st(0) com st(1), resultado em st(1), pop st(0) */
    
            add $8, %eax		/* atualiza endereco de a[i] */
            add $8, %ebx 		/* atualiza endereco de b[i] */
            dec %ecx    		/* atualiza i */
            jmp fori
    
    fim:    mov %ebp, %esp 		/* resultado ja' esta' na pilha! */
            pop %ebp
            ret
    
Referência