>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Práce s koprem (koprocesorem ;-)
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Nedávno, dělajíce 4kb Intro na Demobit '96 (který byl stejně
odložen), jsem byl donucen dělat v čistém assembleru. Což se až
donedávna nestalo, neboť jsem ještě nikdy nebyl limitován velikostí
výsledného kódu. Takže se do ASM přepisovaly pouze kritické části
programů ...
A protože Pasquil i C se za Vás starají o práci s koprem, nikdy
nebylo nutno hlavu zatěžovat tím, jak vůbec pracuje - až nedávno.
A při té časové tísni jsem narazil na KATASTROF+LN- nedostatek
jakékoliv STRAVITELN+ informace o koprech ... vše jsem musel lovit
ze zdrojáků a za použití různých helpů ...Něco málo o tom, co jsem
vykoumal, zde přináším :
Koprocesor obsahuje registry, podobně jako procesor. Má jich
podstatně méně, ale někdy je jejich celková kapacita větší než volné
místo na mém HDD :-) Jedná se o datové a pomocné registry.
Datové : je jich 8 a každý má 80 bitů. Koprocesor totiž interně
pracuje POUZE s 80ti bitovými RE+LNÝMI čísly. Pokud mu
zadáte číslo třeba typu integer a 64bit on si ho stejně, po
zapsání do jednoho z registrů, převede do těch 80ti
reálných bitů (reálných míněno ve smyslu floating-point).
Tyto registry jsou značeny jako ST(X), kde X je číslo
jednoho z 8mi registrů. S těmito registry se zachází
podobně jako se zásobníkem (STACK) typu LIFO (Last In -
First Out). To znamená že se číslo zapíše "nahoru" a ty, co
tam byly před ním, se jakoby sesunou o 1 dolu. Registr,
který je "nahoře" (tj. hodnota vložená jak poslední) je
označen jako ST(0) (nebo ekvivalentně ST) , a ostatní
následují za ním. Příklad:
ST(0) 10.3987
ST(1) 1.75344
ST(2) ....
vložím číslo 22 :
ST(0) 22
ST(1) 10.3987
ST(2) 1.75344
ST(3) ....
Pokud se stane, že vám "zásobník" (=registry ST(X))
přetečou, je generována nějaká výjimka v řídícím registru
(SF,C1).
Pomocné : jsou 3 po 16ti bitech.
Řídící: nastavuje parametry některých funkcí procesoru.
Uvedu nejdůležitější:
bit 8 - 9 : (PC - Precision control)
nastavování přesnosti - pokud
nastavíte menší přesnost,je výpočet rychlejší.
Možnosti jsou následující:
00 : 24 bitů
01 : nikde jsem nevypátral
10 : 53 bitů
11 : 64 bitů (standartně)
bit 10-11 : (RC - Round control)
nastavování způsobu zaokrouhlování. Nastavení:
00 : normální zaokrouhlování
01 : zaokrouhlení dolů
10 : zaokrouhlení nahoru
11 : truncate :) čili useknutí des. části
Stavové: něco jako registr (E)FLAGS u procesoru. Odráží
momentální stav (psychický ;-) koprocesoru.
bit 8,9,10,14 : tyto bity jsou nastaveny podle proběhnuvší
operace
bit 11 - 13 : obsahuje číslo registru ST, který je právě
"nahoře"
bit 6 : (SF - Stack fault). Nastává při chybné operaci s
registry ST.Buď jsme chtěli vložit více jak 8 čísel,
nebo jsme chtěli více jak 8 čísel vybrat.
Doplňující: obsahuje informace obsahu o každém z 8mi ST
registrů (po 2 bitech). Může v něm být :
00 - registr je obsazen
11 - registr je prázdný
01 - v registru je nula
10 - v registru je nějaké speciální číslo
(+- nekonečno a tak ...)
Možná, že si mnozí řeknou: "No jo, ale von nám zapoměl popsat tvar
reálných čísel". Nezapoměl, ale nepopíšu je, neboť je dost dobře
nechápu.
Ono je totiž dost dobře možné pracovat s koprem, aniž bysme tento
tvar znali. Jak ? Za pomoci fixed-point.
Ale napřed popíšu "pár" užitečných instrukcí koprocesoru:
Instrukce pro práci se zásobníkem:
FLD : nahraje do registru ST reálné číslo v paměti (32,64,80bit)
ex: Mov ST(0), promenna
; promenna muze byt DWORD,QWORD,TBYTE
FLD1 : nahraje do registru ST hodnotu 1
FLDPI: nacpe tam Pí
FLDZ : -"- nulu
FILD : nahraje do ST číslo typu INTEGER (16,32,64 bit)
FST : reálné číslo z ST(0) nahraje do proměnné a FSTP navic
vyjme tuto hodnotu ze zásobníku (tj. jakoby posune všechny
zbylé o 1 nahoru)
ex: Mov promena, ST(0)
Pop ST(0) (jen uz FSTP)
FIST/FISTP: číslo INTEGER nahraje z ST(0) do paměti (zkonvertuje
jej z reálného čísla)
FDECSTP/FINCSTP: sníží/zvýší o 1 hodnotu v bitech 11-13 stavového
registru. Prostě se změní číslo registru, který je nahoře
- místo ST(2) bude "nahoře" (= v ST(0) ) třeba ST(1), nebo
ST(3) v druhém případě.
FFREE : vyprázdní daný registr
př: FFREE ST(6) ... vyprázdní 6ku ...
Pozn :
• Instrukce končící na P (FISTP,FSTP,FMULP,FDIVP ...) jsou od
svých "nepéčkových" ekvivalentů rozdílné tím, že odstraní
hodnotu na vrcholu zásobníku. Dalo by se rozložit na
instrukce AKCE a POP. Je to docela užitečná vlastnost ...
Příklady níže.
• Zápis ST je ekvivalentní zápisu ST(0) - v obou případech máme
na mysli ten registr, který je "nahoře".
• Instrukce bez operandu (FSQRT,FSIN,FCOS...) pracují tak, že
nahradí hodnotu v ST hodnotou, kterou vypočítá.
FISTP prom - uloží ST(0) do prom a odstraní ST(0)
ze zásobníku (tj. všechny ostatní
posune o 1 nahoru)
FMULP ST(x),ST - udělá : ST(x)=ST(x)*ST a ST vymaže
FSIN - udělá ST = sin(ST)
Aritmetické instrukce :
FABS
FADD
FCOS/FSIN/FSINCOS
FCHS
FPTAN/FPATAN
FRNDINT
FMUL/FMULP/FIMUL ...
FDIV/FDIVP/FIDIV ...
FSQRT
FSUB
FXCH
a další ...
Instrukce ovládání kopru :
FINIT: nutno zavolat na začátku programu - inicializuje kopr.
FNINIT: provede inicializaci, ale bez interní kontroly - což je
rychlejší
FWAIT: je ekvivalentní instrukci WAIT
FSAVE
FRSTOR
FSTENV
FSTCW
Teď k té práci s koprem ... není totiž nic jednoduššího, než použít
fixed point. To znamená, že si do kopru hodíte nějakou hodnotu a on
si ji převede (bohudíík) na reálné číslo (80bitové). Pak si můžete
dělit, násobit, kosínovat, odmocňovat a tak ...
Mno a nakonec to celé vynásobíte konstantou tak velkou, aby
zachovala všechna velká čísla a dostatek desetinných - prostě abyste
se vešli do těch výsledných 16/32/64 bitů (vyberte si co chcete :-).
Mno a pak použijete instrukci FIST/FISTP a ta to pěkně hodí do
paměti.
A je po práci s koprem ...
Hodím sem příklad v ASM, který slouží na předpočítání SIN tabulky
(0-360 stupňů)...
Examplesák na práci s koprem
výheň