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