Operace s čísly s plovoucí řádovou čárkou

Operace s čísly s plovoucí řádovou čárkou lze na procesorech x86 realizovat dvěma způsoby, pomocí jednotky FPU vycházející z koprocesoru x87 nebo pomocí instrukcí SSE. V tomto cvičení se budeme věnovat prvnímu způsobu.

Registry

Jednotka FPU pracuje s osmi registry ST(0) až ST(7), které tvoří zásobník. To znamená, že registr ST(0) vždy ukazuje na registr na vrcholu zásobníku, ST(1) na registr pod vrcholem zásobníku, atd. Jednotlivé operace pak pracují s vrcholem zásobníku, registrem ST(0) a případně dalším registrem nebo hodnotou v paměti. Pro úplnost dodejme, že velikost registrů ST(i) je 80 bitů a jsou v nich uložena čísla s rozšířenou přesností podle standardu IEEE 754, odpovídá to tedy typu long double v jazyce C.

Instrukce

Načítání a ukládání hodnot z/do registrů

  • FLD ST(i)/mem -- přidá na vrchol zásobníku hodnotu z registru nebo místa v paměti
  • FILD mem -- načte hodnotu z paměti, převede ji na číslo s plovoucí řádovou čárkou a přídá na vrchol zásobníku
  • FLDZ -- přídá na vrchol zásobníku hodnotu 0
  • FLD1 -- přídá na vrchol zásobníku hodnotu 1
  • FLDPI -- přídá na vrchol zásobníku hodnotu pi (3.141...)
  • FLDLN2, FLDLG2, FLDL2T, FLDL2E -- instrukce přídávají na vrchol zásobníku hodnotu logaritmů -- ln 2, log10 2, log2 10, log2 e
  • FXCH ST(i) -- prohodí obsah registrů ST(0) a ST(i)
  • FST ST(i)/mem -- uloží vrchol zásobníku do registru nebo do paměti
  • FSTP ST(i)/mem -- jako FST, ale odstraní hodnotu z vrcholu zásobníku
  • FIST mem -- převede hodnotu na vrcholu zásobníku na celé číslo a uloží do paměti
  • FISTP mem -- jako FIST, ale odstraní hodnotu z vrcholu zásobníku

Aritmetické operace

Základní aritmetické operace mohou mít několik podob v závislosti na použitých argumentech. Jednotlivé varianty si ukážeme na instrukci pro sčítaní, ale podobné varianty platí i pro operace odčítání, násobení a dělení.

  • FADD -- (bez jakýchkoliv operandů) sečte hodnoty ST(0) a ST(1) a výsledek uloží do registru ST(0)
  • FADD mem -- sečte hodnoty ST(0) a místa v paměti a výsledek uloží do registru ST(0)
  • FADD ST(0), ST(i) -- přičte k ST(0) hodnotu ST(i)
  • FADD ST(i), ST(0) -- přičte k ST(i) hodnotu ST(0)
  • FADDP ST(i), ST(0) -- přičte k ST(i) hodnotu ST(0) a odstraní hodnotu z vrcholu zásobníku
  • FIADD mem -- načte hodnotu z paměti, převede ji na číslo s plovoucí řádovou čárkou a přičte k ST(0)

Další aritmetické operace:

  • FSUB, FSUBP, FISUB -- jako FADD, FADDP, FIADD pro odčítání
  • FMUL, FMULP, FIMUL -- jako FADD, FADDP, FIADD pro násobení
  • FDIV, FDIVP, FIDIV -- jako FADD, FADDP, FIADD pro dělení
  • FSUBR, FSUBRP, FISUBR -- jako FSUB, FSUBP, FISUB ale odečítá čísla v opačném pořadí
  • FDIVR, FDIVRP, FIDIVR -- jako FDIV, FDIVP, FIDIV ale dělí čísla v opačném pořadí

Vybrané funkce implementované v jednotce FPU:

  • FABS -- do ST(0) uloží absolutní hodnotu ST(0)
  • FCHS -- otočí znaménko v ST(0)
  • FSQRT -- do ST(0) uloží druhou odmnocninu z ST(0)
  • FSIN -- do ST(0) uloží hodnotu sin(ST(0))
  • FCOS -- do ST(0) uloží hodnotu cos(ST(0))

Podmíněné operace

Podmínky jsou v FPU realizovány pomocí operace FCOM, která spočítá rozdíl dvou hodnot a podle toho nastaví příznaky v registru EF. Pro zjednodušení některých operací je možné použít instrukce pro podmíněné přířazení -- FCMOVcc (FCMOVE, FCMOVB, FCMOVBE, FCMOVNE, FCMOVNB, FCMOVNBE)

  • FCOM -- porovná ST(0) a ST(1)
  • FCOM ST(i)/mem -- porovná hodnotu ST(0) a registru nebo místa v paměti
  • FCOMP ST(i)/mem -- porovná hodnotu ST(0) a registru nebo místa v paměti a odstraní hodnotu z vrcholu zásobníku
  • FCOMPP ST(i)/mem -- porovná hodnotu ST(0) a registru nebo místa v paměti a odstraní dvě hodnoty z vrcholu zásobníku

Předávání argumentů a návratových hodnot

Čísla s plovoucí řádovou čárkou, které jsou předávány jako argumenty, jsou v konvenci C předávány přes zásobník. Návratová hodnota je předávána pomocí registru ST(0).

Před zavoláním funkce je nutné, aby registry ST(0)-ST(7) byly prázdné. Po návratu z funkce musí být registry ST(1)-ST(7) prázdné, pokud funkce nevrací hodnotu v registru ST(0) musí být i tento registr uvolněn.

Úkoly

  1. Napište v assembleru funkci double obvod_obdelnika(double a, double b), která spočítá obvod obdélníka.
  2. Napište v assembleru funkci double obsah_obdelnika(double a, double b), která spočítá obsah obdélníka.
  3. Napište v assembleru funkci double obvod_ctverce(double a), která spočítá obvod čtverce.
  4. Napište v assembleru funkci double obsah_ctverce(double a), která spočítá obsah čtverce.
  5. Napište v assembleru funkci double obvod_kruhu(double r), která spočítá obvod kruhu se zadaným poloměrem.
  6. Napište v assembleru funkci double obsah_kruhu(double d), která spočítá obsah kruhu se zadaným průměrem.
  7. Napište v assembleru funkci float avg(float a, float b, float c), která vrací průměr daných hodnot.
  8. Napište v assembleru funkci double heron(double a, double b, double c), která vypočítá obsah trojúhelníku podle Heronova vzorce: P = sqrt(s*(s-a)*(s-b)*(s-c)), s = (a+b+c)/2

Pro získání bodového hodnocení je potřeba splnit úkoly 1 až 8.


Last update on 18. 4. 2017 18:30
Powered by Schemik.

© Petr Krajča, 2010, 2012
petr.krajca (at) upol.cz