AsM - Koprocesszor programozás II

 


Igaz azt ígértem, hogy csak egy számon keresztül foglalkozok a koprocesszor (ezután FPU) programozásával, de olyan alapvetô dolgok maradtak ki, melyeket szerintem az e témában érdeklôdôk meglehetôsen, s joggal hiányolhatnak.

 

Kis kiegészítést tennék az elôzô cikkhez itt - ott:

Mi is az FPU:

 

       Általános értelmezésben egy a központi-processzortól (CPU) elkülönített processzor egység mely egyszerû módon egészíti ki a CPU matematikai mûveleteit. Nem csak a fix ábrázolású egész számok mûveletét egészíti-ki gyorsítja, hanem a lebegôbontosan ábrázol
t számok, s velük végezhetô meveletek is alap utasítási közé tartozik. Általános, viszont sok-féle megnevezést használnak rá. Érdemes felsorolni, ha egy eredeti dokumentációban találkozunk velük akkor tudjuk, mint is olvasunk: 80x87 processzorok, MCP = Math CoProcessors, NDP = Numerical Data Processors, NPX = Numerical Processor eXtensions, FPU = Floating-Point Units, vagy egyszerûen "matematikai chip-ek".

A legegô-pontos számfelépítést és mûveleteket (+, -, *, /, gyökvonás = sqrt, maradék-képzés) szabványosították. Ezt a szabványt használják az összes FPU megtervezésénél, hogy a programok hasonlóan használhassanak különbözô gyártmányú FPU-kat. A szabvány
neve: "IEEE-754 Szabvány a bináris lebegôpontos matematikai szám mûveletekhez".

 

Intel 80x87 kontra Weitek FPU ?

 

Két FPU rendszerrôl lehetett hallani az Intel által gyártott 80x87 család és a Weitek koprocesszorok. A 80x87-rôl már sokat hallottunk, ill. elôzô számunkban is szót ejtettünk már róla, de a Weitek-már kihalóban lévô családról érdemes lenne pár szót mondani:

Két változat létezik a Weitek Abacus 3167 és a 4167 melyek KÉTszer gyorsabbak a i80387-nél. Ezek nem közvetlenül a CPU-t egészítik ki, hanem egy úgynevezett nagy-telj
esítményû memória-leképezésû I/O eszköz. Ez egy kicsit hülyén hangzik, írjuk körül:

A Weitek FPU igaz, hogy elvét tekintve nem az, de felhasználási területét tekintve igen:
egy RISC felépítésû, és ebbôl következôen nagy teljesítményû - gyors processzor. A RISC jelenti, hogy kevés utasítást definiáltak a processzorban - az-az a mikrokód kicsi - és a kevés utasításokat viszont nagy sebességel hajtja végre, általában pár óraciklus alatt. A létezô utasítások: betöltés - LOAD, kivétel - STORE, +, -, *, /, negatív-vétel, összehasonlítás, gyökvonás, ill. ezek pár kombinációja. A Weitek FPU-k vagy Single (32 bit-es) módon végzik el az utasításokat, vagy a 64-bit-es double módon mely fel olyan gyors, mint a Single. Ez azért érdekes, mert FIGYELEM: az 80x87-es FPU-k minden belsô számítást double-módon számítanak. A Weitek FPU-nak ellentétben a 80x87-esekkel 31 db belsô 32-bites 80386 felépítésû regisztere van (EAX, EBX, ECX, formájára), s nem a 80x87-es hasonló 8 db stack felépítésû regiszter. A Weitek-ek a dupla számokat két regiszteren tárolják.

Hogy adunk értéket a Weitek FPU-knak - hisz a 80x87-esekét multkor már láttuk - ?

Az elején említettem, hogy memória szervezésû a Weitek FPU. Ez azt jelenti, hogy a 0C0000000h fizikaicímen lehet elérni 64 KB-os blokkban
csak protected (védett) módban az ilyen FPU-t. A Weitek FPU regiszterekbe a 386+ -os MOVS utasítással írhatunk. (Lehet valós módban is körülményesebben használni egy memóriamangarrel, pl.: EMM386, QEMM. Az EMM386-nak kifejezetten van is egy Weitek support kapcsolója !) Általában az FS szegmens regiszter mutat a Weitek FPU által meghatározott szegmensre, s így írhatunk oda. A legtöbb DOS fordító nem támogatja a Weitek FPU használatát, így assembly nyelvben - vagy beszúrásokkal használhatjuk azt. A DOS-szal ellentétben a Unix kezeli a Weitek FPU-t is. Nos ennyit a Weitek FPU-ról ugyanis nincs kézközelben egy darab se így nem tudnék mûködô példaprogramokat írni, s gondolom az Olvasók közt se akad egy darab se. Akit érdekel s van Weitek FPU-ja az adja nekem, s írok rá példaprogramot ...

 

Kik használják az FPU-kat ?

 

 

Ezek közül leginkább a CAD alkalmazások használják ki az FPU-k teljesítményét. Pl. az AutoCAD R10 már el se fut FPU nélkül.

 

A GUI-k (grafikus felhasználói felületek = Graphical User Interface), mint a MS-Windows, vagy OS/2 NEM használják, mert egész számokkal dolgoznak. Míg a UNIX ill. Linux-os X-Windows furcsa módon tudja hasznosítani !

 

Nézzünk egy statisztikát a koprocesszor alkalmatása során fellépô sebesség növekedésre:

 

Program

80387 FPU nélkül

80387 FPU-val

Sebesség növekedés:

Art&Letters

87.0 sec

34.8 sec

150%

Quattro Pro

8.0 sec

4.0 sec

100%

Wingz

17.9 sec

9.1 sec

97%

Mathematica

420.2 sec

337.0 sec

25%

Corel Draw

471.0 sec

416.0 sec

13%

Freedom Of Press

163.0 sec

77.0 sec

112%

Lotus 1-2-3

257.0 sec

43.0 sec

597%


 

Hogyan mûködik egy 80287-es (vagy újabb) FPU ?

 

Nagyobb lenne a költség, ha 80286 memória-védelmi részét (MMU) át kellett volna rakni a 80287+-es FPU-kra, így a CPU felette áll az FPU-nak és a CPU-ba érkeznek be az utasítások amiket ellenôrizve a CPU ad ki az FPU-nak. Az FPU utasítások általában a 0F8h - 0FFh CPU port-okon érkeznek be.

Az elsô utasítást töltjük be az FPU-ba e
kkor a /BUSY flag még nulla. Az utasítást végrehajtja s közben a /BUSY flag = 1. Így ha mûvelet végrehajtás közben zaklatnánk az FPU-t addíg kell várnunk amíg a /BUSY flag nem egyenlô nullával. Persze az utasítások betöltését CPU végzi. Ezért nem szükséges az assembly kódban minden koprocesszor utasítás elé WAIT-et rakni, mint réget a 8086-osoknál, mert van szinkronizáció ! VISZONT a WAIT-nek van másik szinkronizációs feladata a mégpedig ha az FPU egy memóriaoperandusba ír akkor viszont KELL, a mûködés elvébôl tekintve !

A 80287-esek még szinte teljesen hasonlítanak elôdjeikre a 8087-esekhez, és az a furcsa dolog, hogy egy 8 MHz-en futó 8087-es gyorsabb, mint egy 80287-es ! Ez részint abból is adódik, hogy 2/3 sebességgel megy csak a 80287 FPU, mint a 80286-os CPU a szinkronizáció megoldása végett.

Elôszôr a Cyrix találta ki, hogy a 80287 FPU dupla sebességgel menjen, mint a CPU. Pl.: 10 MHz 80286 és 20 MHz Cyrix 287.

 

A 80837 újítási

 

A hasonlóság megmaradt nagy részt a 80287-hez, de vannak pozitív újítások is !

800000F8h - 800000ffh IO porton lenne elvileg elérhetô az FPU. Teljesen 32 bit optimalizált lett a 80387 a 80386-tal egyetemben, egységgé. Sikerült a 40 óra-körról 14-20-ra csökkenteni egy utasítás végrehajtási idejét. IGAZ a konkurencia, más 387 klónok ezt már 16 alá tudtás süllyszteni.

 

A további teljesítmény növelés csak az egybetokozással oldható meg így a
486-osokkal (486 DX) egy tokba van építve a un. 80487. Ami már jelentôs kevésbbé dokumentált változásokat hozott. (Pár tudható dolog, egy cache-t használnak az pipline-os utasítás végrehajtásra.)

A iPentium-okkal is egy tokban van az FPU.

 

Érdemes szót ejteni az
IIT 3c87 FPU-ról mely nem csak gyorsabb volt az i80387-nél hanem új hasznos utasításokat is tartalmazott:

 

A konkurensek ez idô tájt (1989) elôrébb jártak az Interl-nél, hisz az Intel fejlesztette a CPU és FPU-kat, viszont a konkurencia dolga csak az volt, hogy tovább fejlessze. Így nem volt nehéz jobb FPU-t kihozni. Pl. a Cyrix FasMath 83D87 FPU-ja 50%-kal volt gyorsabb a hasonló Intel-nél valós alkalmazásoknál. A védettmódú 3D Studio-nál viszont csak 6%-kal tudott többet produkálni.

 

Az elsô Intel lépés a gyorsításért 80386 és 80387 egybeintegrálása volt így IntelRapidCAD néven futott ez a CPU. Meg lehet figyelni az azonos frekvencián mûködô chip-ek gyorsaság növekedését:

 

Program

80387-tel

IntelRapidCAD

Sebességnövekedés

AutoCAD 11

52 sec

32 sec

63%

AutoShade/Renderman

180 sec

108 sec

67%

Mathematica(Windows )

139 sec

103 sec

35%

SPSS/PC+ 4.01

17 sec

14 sec

21%



 

 

Az i486DX újítási

 

Nos persze az i486DX nem közvetlenül egy koprocesszor, hanem két processzor a CPU és FPU véglegesen egybeintegrált összességét jeleni. Ezt az ú j chip-et 1989-ben mutatta be az Intel. Pontosan úgy lehetne definiálni, hogy egy nagy 'parancs-csatornájú' (pipeline) 80386-os arhitektúra, mely egy új jobb 80387-es FPU-val van egybeintegrálva. Továbbá a sebesség növekedés érdekében új modosításokat vezettek be: 8 KB-os nem meghatározott kód/adat cache.

Az újítások eredménye képen a 80386 CPU + 80387 FPU-knál azonos frekvencián a 80486 DX kétszer-háromszor gyorsabb lett. (Logikus a 80486 DX-nek az InterRapidCAD tekinthetô bizonyos elôdjeként.)

Fontos megjegyezni, hogy a 486DX-50 felett már hûtôventillátor szükséges, hisz ez a processzor már 80-90 ºC-os hôt is képes termelni. A hûtôventillátorok 40-60 ºC-ra hûtik a CPU-t, míg a legideálisabb a 25-30 ºC-k lenne.

 

A DX2-krôl és az i486SX-rôl

 

Nos csak pár szót érdemes erre pazarolni, pl. egy 486DX2-50 ugyanazt a teljesítményt nyújtja processzorilag, mint egy 486DX-50. A DX után a 2 szám jelzi, hogy
az alaplap frekvenciáját megkétszerezték, így lett a 25 MHz-bôl 50 MHz. A DX2-es megoldások olcsóbbak, mint az azonos frekvenciájú DX-ek, de a DX2-esek alaplapi mûveletei logikus fele akora frekvenciával mennek, kisebb a teljesítmény. A PCI ezt a problémát oldja meg az alaplap és a buszok frekije állandó, míg a CPU 2.5 vagy 3 szoroz.

 

Vajon mit jelent az SX posztfixum ?

Hát biztosan NEM azt amit a 386-osoknál, hogy 16-bit-et, hanem itt azt jelenti, hogy ezek a CPU-k:

FPU nélkül vannak szállítva. S külön lehet FPU-t i80487-et venni hozzá. Ez nem más, mint üzleti fogás - olcsó úgymond. 486-os adnak el. Igaz a 486SX-ek a hibás FPU-ju 486DX-ekbôl lettek. (A 486 egyik tán legfôbb értelme, hogy CPU - FPU egyben van, itt ezt bontották meg, szerintem, így jelentôs sebesség csökkenést értek el.)

Mivel a 486SX és 486DX lábkiosztása és tokozasa különbözô, az alaplapok is különböznek. Ha valaki új CPU-t akart annak alaplapot kellet volna cserélnie, HA az Intel nem találja ki az OverDrive-ot amit SX foglalatba lehetett tenni, megduplázódott a teljesítmény.

 

Lássuk mára betervezett gyakorlati feladatunkat a koprocesszorral kapcsolatban:

 

Úgy gondolom megfelelô elméleti és történeti áttekintést nyújtottam, így inkább térjün át a gyakorlati dolgokra, melyek elôzô számunkból még hiányozhattak a Kedves Érdeklôdô Olvasóknak (micsoda rövidítés: KÉO). Az FST - FLD - FADD - FSUB - FMUL - FDIV utasításokat maximálisan kimerítettük az elôzô számban, DE a vizsgálatok gyakorlati megvalósítása még csak most jön:

 

Vizsgálatok:


FCOM

CMP ST(0), ST(1)

FCOM ST(i)

CMP ST(0), ST(i)

FCOM mem4r

CMP ST(0), Single

FCOM mem8r

CMP ST(0), Double

FCOMP

CMP ST(0), ST(1), pop

FCOMP ST(i)

CMP ST(0), ST(i), pop

FCOMP mem4r

CMP ST(0), Single, pop

FCOMP mem8r

CMP ST(0), Double, pop

FCOMPP

CMP ST(0), ST(1), pop, pop (!)

FICOM mem2i

CMP ST(0), Integer

FICOM mem4i

CMP ST(0), Longint

FICOMP mem2i

CMP ST(0), Integer, pop

FICOMP mem4i

CMP ST(0), Longint, pop


 

C3

C2

C1

C0

 

0

0

?

0

ST > op

0

0

?

1

ST < op

1

0

?

0

ST = op

1

1

?

1

ST nem hasonlítható össze


(A C3, C2, C1, C0 bit-ekrôl alább !)

 

Ezek a használható formák nézzünk egy példát az alkalmazásra:

Írjunk egy függvényt, hogy két pl. Single változó közûl melyik a kisebb. A függvény visszatérési értéke legyen 1 ha az elsô Single változó kisebb. 1 ha szigorúan nagyobb (nagyobb nem egyenlô), és 2 ha egyenlôek.

Lássuk a példát és alább a magyarázatot:

 

Itt van a függvény forrásódja !


Mit csinál a fenti függvény:

A függvénynek két paramétert adunk át cím szerint, az Operandus1 és Opernadus2 Single lebegôpontos típusu numerikus 32-bit-es változókat.

Nos a program ilyen egyszerû lenne.

 

Elôször gondoltam bemutatok egy programot amit koprocesszor assem
bly-s programozásával írunk meg, pl. a prím vagy Armstrong számok kiszámítására de ezek a mai gépek olyan gyorsak, hogy simán Pascal-ból pillanatok alatt kész van egy bonyolultabb probléma, így semmi értelme bonyolultan megírni egy programot assembly-vel, ha Pascal-ból kitûnôen megy.

Inkább lássunk pár utolsó adalékot e témához:
Megígértem a C3 - C0 állapotbitek leírását, lássuk:

 

Ezet az állapot-bit-ek az FPU állapotszóban találhatóak (FPU Status Word), lássuk az állapotszó kiosztását:

 


 

 
A fenti bit kiosztásban látható, hogy a C3 - C0 bit-ek hol helyezkednek el, továbbá más hasznos információkat is lekérdezhetünk az FSTSW paranccsal.

 

Lássuk a vezérlôszó (FPU Control Word) kiosztását és bit-jeinek szerepét:



Mi leginkább a kerekítési és mantissza beállítási szabályokra vagyunk kíváncsiak:

 

A Round két bitbôl áll:

00 = a legközelebbi pároshoz kerekít ez az alapbeállítás

01 = lefelé kerekít negatív irányba

10 = lefelé kerekít pozitív irányba

11 = a mantisszát 0 felé kerekíti

 

Preciziós - mantissza hossz beállítások. Ez is két biten helyezkedik el, az adott bit-ek helyzete:

00 = 24 bit hosszú mantissa

01 = foglalt

10 = 53 bit hosszú mantissza

11 = 64 bit hosszú mantissza, ez az alapbeállítás

 

Fontos, hogy a precizió (jelen esetben mantissza hossz) csökkentéséven NEM nô a mûveletek elvégzésének gyorsasága !

 

A vezérlôszó utasításai:


FSTCW mem2i

mem2i <= 80x87 vezélôszó

FNSTCW mem2i

(ugyanaz de nincs szinkron várakozás: nowait)

FLDCW mem2i

80x87 vezérlôszó <= mem2i


 

 

Nos a koprocesszor programozásának alapjait most már tényleg kivégeztük, itt szerintem mindenki bôségesen elegendô inforációt találhatott ahhoz, hogy el tudjon indulni e témában.

Aki az alábbiak alapján nem értene valamit, vagy nem tudott volna elindulni akkor eMail-ezzen !

A cikk Winword DOC formátumban

Bérczi László
eMail:PC-XUser@IDG.HU, Subject: "AsM rovat"
BELA@MI.STUD.PMMFK.JPTE.HU


Vissza a PC-X User 10 fôoldalához