Tak FPU tedy Intel umel a umi delat (na rozdil od CPU :). Chtelo by to potom porovnat, jak rychle ty FPU jsou, protoze imho 8087 mela pomaly algoritmy, kdezto treba u Pentia to snad bylo co takt, to dokoncena FPU operace. ale mozna si to pletu a nektery operace byly pomalejsi.
Nebyl v 87 implementovanej CORDIC?
FDIV na Pentiu generovalo 2 bity výsledku za CLK a po celou dobu dělení nešlo zahájit jinou FPU operaci.
FMUL šlo zahájit jen každý druhý CLK.
Na Pentiu a na K5 byla ještě float a int násobička sdílená.
Od Pentia byla instrukce FXCH párovatelná, daly se tím levně přejmenovat registry a k FPU stacku přistupovat jako k nezávislým registrům.
Na Pentiu a na K5 byla ještě float a int násobička sdílená.
Mas pro to nejake podklady?
To spis vypada ze az P4 melo neduh ze to tahalo skrze delsi jednotku (vyssi frekvence, mene urovni kombinacni logiky), zatimco osatni stara pentia ne, a integer multiply se tam delalo klasicky (nejspi jen na jedne) z u,v pipelin. Nasobicku mezi INTALU a FPALU nejde sdilet, jsou to prakticky jine mista v kremiku.
ref.: https://cr.yp.to/2005-590/fog.pdf
An integer multiplication takes approximately 9 clock cycles on P1 and PMMX; 4 on PPro, P2 and P3; and 14 on P4. It is therefore often advantageous to replace a multiplication by a constant with a combination of ...
Jestli jste to zkoušel programem napsaným v Pascalu a přeloženým Turbo/Borland Pascalem, tak to mohl být spíš problém překladače. Když jsem si ke své 386 pořídil koprocesor (kvůli programu Mathematica), tak jsem si chtěl hned vyzkoušet, o kolik je to rychlejší, a napsal jsem si jednoduchý prográmek, který kreslil Juliovu množinu a počítal to ve floatech. Při překladu s použitím koprocesoru to sice rychlejší bylo, ale IIRC jen asi třikrát, což u programu, který v podstatě nic jiného než float aritmetiku nedělal, bylo docela zklamání.
Pak jsem se ale podíval na přeložený program a zjistil jsem, že překladač každou aritmetickou operaci provedl tak, že zkopíroval argumenty do FPU, provedl příslušnou FPU instrukci a pak zkopíroval výsledek zpátky. A i v případě, že se ten výsledek hned vzápětí znovu použil (třeba při násobení tří čísel), tak ho stejně znovu nakopíroval zpátky do FPU. Tak jsem zkusil tu vnitřní smyčku přepsat do assembleru tak, aby se hodnoty do FPU posílaly jen jednou, celý výraz se spočítal v FPU a použil se jen finální výsledek. Zrychlení bylo asi tisícinásobné.
Jj, to si pamatuji, investoval jsem do 287 a takhle to vypadalo. Mam ten dojem, ze duvodem bylo zjednoduseni prekladace. Pri sw reseni se do kodu vlozilo volani floating funkce z knihovny, pri pouziti FPU se tam vlozil monoliticky kus kodu bez zavislosti (v FPU - ST reg.) na predchozi/nasledujici fp operaci.
pri pouziti FPU se tam vlozil monoliticky kus kodu bez zavislosti (v FPU - ST reg.) na predchozi/nasledujici fp operaci.
Asi to souvisí i s tím, co se řeší v jiné části této diskuse. Pokud se data mezi CPU a FPU předávala opravdu tak neefektivním způsobem, jak se tam píše, tak se ani nedivím, že jejich neustálé posílání tam a zpátky spotřebovalo víc času než samotný výpočet.
Pokud mne paměť neklame, je rezervovaná konkrétní výjimka, která se vyvolá, pokud procesor narazí na FPU instrukci, ale FPU není k dispozici. Emulátor instaluje obsluhu této výjimky, která se podívá na instrukci, provede její emulaci (v CPU) a vrátí se, načež se pokračuje další instrukcí. Stejně funguje (nebo spíš asi fungovala) emulace FPU v linuxovém jádře.
Tahle SW podpora byla ve Windows od 3.x, takže narozdíl od macOS Classic nebyl problém (Apple programy od určité verze Motoroly počítaly s koprocesorem, např. Excel, a on ho pak vyhodil v laptopech, protože se čip v jedné generaci přehříval).
V DOSu určitě byla podpora třetích stran, ale třeba Pascal si to řešil sám, čímžto to bylo znatelně rychlejší - podporu FPU zjistil jednou a pak modifikoval instrukce v kódu (rychlost, jakoby byl program zkompilován jen se SW podporou).
Pamatuji si, ze na 386 jsem pod dosem (simulace ve SPICE apod.) mel v tech nevyuzitych 3 MB nejaky 900 kB emulator koprocesoru. Z velikosti je zrejme, ze byl zalozen na rozsahlych LUT, a zrychleni oproti klasickym emulatorum bylo v zavislosti na typu operaci az nekolikanasobne (jednociferne). Ono cekat na vypocet hodinu nebo tri hodiny byl stale rozdil.
Tak dlouho jsme zlepsovali matematicke vypocty na pocitacich, az jsme se "vratili" na 8 bit float. FP8 jako E4M3 (4-bit exponent, 3-bit mantisa), nebo
E5M2 (5-bit exponent, 2-bit mantisa)
To se dnes hodi na AI, protoze je to mene narocne na vsechno (energie, pocet tranzistoru, ulozeni, prenos) a na AI to staci.
A FP8 neni v IEEE 754, zatim.
Nuz bezne FPGA maji 6-vstupove LUT, takze pokud bude ALU hardcoded (2-bit operace, 2x 4bit data), tak by tech 10 bitu slo namapovat na vystupni data snad i v 1 cyklu pres 1 GHz, i kdyz na bezne aplikace si lze dovolit to rozsekat na vicetaktovou pipeline.
Nemusi to byt nutne ROM ve fyzicke realizaci, viz treba ta zabugovana PLA v pentiu, z nedavneho koumani jeho kremiku od Kena, kdy oprava dokonce prinesla zrychleni protoze byla vystupni entropie mensi.
Mozna nekdo z ASIC navrharu nam sdeli jake jsou prakticky frekvence u urciteho poctu levels of logic, nebo tedy hodnevstupe funkce :)
Neměly FPU v sobě už 486 DX ? Já myslím, že ano.
Viz:
https://cs.wikipedia.org/wiki/Intel_80486
14. 1. 2025, 18:59 editováno autorem komentáře
No právě vy píšete : "Až mnohem později (konkrétně u Pentia) se matematický koprocesor stal nedílnou součástí mikroprocesoru, což znamená, že dnes již není nutné"
tak buď to blbě chápu nebo tam máte renonc :) Jinak díky za vaše články, jsou skvělé i ty staré o zvukovkách atd... :D
Já si stále hraju s https://86box.net/ myslím, že na tom i pracují češi a pouštím dětem hudbu přes covox :D Perfektní emulátor téměř jakéhokoliv stroje, zvukovky, graf.karty atd...
jo tak, už chápu. No situace 486 je kvůli SX a DX trošku složitější, to jsem si chtěl nechat na příště :-). Ta myšlenka napsaná do jedné nepřesné věty byla taková, že u Pentia je vždy na 100% součástí i matematický koprocesor, u 8088/8086/80286/80386 je to vždycky samostatný čip a prostě 486 je taková princezna koloběžka. Nějak to zkusím vylepšit.
Aby to nebylo tak jednoduché, tak to platilo pro Intel Pentium, ale ne nutně ostatní 80586, viz NexGen Nx586 ( https://www.cpu-world.com/CPUs/Nx586/NexGen-Nx586-P133.html ). Nechávaje teď stranou nízko-výkonné a nízko-nákladové embedded varianty, které se prodávají dodnes...
... od x86_64 stejně všichni používají SSE.
u Pentia je vždy na 100% součástí i matematický koprocesor, u 8088/8086/80286/80386 je to vždycky samostatný čip a prostě 486 je taková princezna koloběžka
V těch 486 od Intelu byl taky vždy, jen se v některých (SX) nedal používat. :-) Myslím, že jediné 486, kde koprocesor opravdu nebyl, byly takové ty podivnosti jako 486DLC od některých alternativních výrobců.
Ja jsem si pro zobrazeni floating point na slabsich embedded oblibil format "%a", "%A". Kod vlastni implementace je relativne kratky, takze i rychlost je prijatelna a nebrzdi tolik, jako std knihovna, a pritom se z toho zobrazeni da i jen pohledem odhadnout, o jakou hodnotu se jedna. Treba 10.01->0x412028f6 (<<1 -> 0x824051EC)->0x1.4051ecp+3.
Tady je pěkná webová aplikace, která zobrazuje jednotlivé "kusy" IEEE-754 čísla: https://marekknapek.github.io/float/#?n=0x40490fdb
Vstupní řádek tam není, hex zadání lze udělat pomocí fragment části URL (za křížkem). Dále tam chybí klasické dekadické zadání či nejkratší možný dekadický výstup, který bez ztráty přesnosti konvertuje zpět. To ale není triviální, jsou na to knihovny, ale chtěl jsem to napsat na zelené louce v C. Další podobná aplikace je na https://www.h-schmidt.net/FloatConverter/IEEE754.html ale ta umí pouze float, já tam mám i double a quadruple.
Zrovna nedavno vysel zajimavy text, ktery ukazuje, kde a jak byly ruzne floating konstanty ulozeny v FPU v prvnich Pentiich. Doporucuji!
http://www.righto.com/2025/01/pentium-floating-point-ROM.html
1 je to tam, kde se snazili redukovat "undefined behaviour", viz
https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero#Programming_languages
The C and C++ standards do not specify the result of 0⁰ (a domain error may occur). But for C, as of C99, if the normative annex F is supported, the result for real floating-point types is required to be 1 because there are significant applications for which this value is more useful than NaN[28] (for instance, with discrete exponents); the result on complex types is not specified, even if the informative annex G is supported.
Dobrý úvod do problematiky, ale musím říct, že se už těším na další díl, jestli se tam dostaneme k vlastnímu fungování spolupráce CPU a FPU. Zarazil mě tady ten pro mě ne úplně jasný a přesný pojem "pomocí sdílení sběrnice". Našel jsem si jedno PDF, kde popisují 8087 s modelem "sdílení toku instrukcí" což má být asi to, co myslíte, a "model 80387". Mimo jiné obojí potřebuje vlastní typ přerušení, jak jsem očekával. Tak jsem zvědavý na podrobnější popis a následně pak i na popis instrukční sady FPU. Např. jak se v praxi přenášely ty 80bit hodnoty a ne jen ořezané na 64 bitů? A ten přenos do RAM zařizoval CPU nebo mělo FPU svoje DMA?
Sdileni sbernice umoznuje x86 pomoci pinu "#HOLD", kdyz se aktivuje a cpu potvrdi odevzdani, tak je masterem jiny obvod, ktery muze delat pristupy kam jenom chce.
Viz https://www.righto.com/2023/08/intel-8086-bus-hold.html
Spravna odpoved je "FPU melo svoje DMA", data neslo sdilet mezi CPU registry a FPU jinak, nez obloukem skrze RAM.
jeste se k tomu dostanu, ale podrobny popis zapojeni a signallingu je tady https://roboticelectronics.in/8087-interfacing-with-8086/
Mozna zacit az s popisem signalu TEST, tam je sdileni popsano. Ale dostaneme se k tomu
(jaky by mel byt problem s 80 bity? prenesou se normalne 10x bajt nebo 5x slovo, jestli se ptate na toto)
Já jsem našel stručný popis v https://dougx.net/gaming/coproc.html#howtheywork
A tam se mi potvrdily dvě věci, co jsem čekal:
- CPU a FPU musejí mít definovaný vlastní (společný) typ přerušení,
- nestačí sdílet sběrnici, musejí sdílet něco jako instrukční registr (v této terminologii je to BIU ?)
A jestli dobře koukám, tak v tom dokumentu, co odkazujete, se to potvrdilo. Ale přiznávám, že jsem oboje jen proletěl.
Ohledně těch 80 bitů mě jenom zaujalo, že se to muselo načítat po kouskách, na 8087 počítám dokonce jen po 16 bitech, protože ještě neměla 32bitové registry... To muselo být cyklů navíc! Nevyplatilo se jednodušší výpočty dělat v CPU? Na ty praktické záležitosti jsem právě zvědavý: jak se to opravdu používalo.
BIU obecně znamená Bus Interface Unit.
Ano, data se do FPU přenášela normálně po externí sběrnici, takže po 8/16 bitech (tam nezáleží na šířce registrů, omezuje to šířka sběrnice). Rychlé to extra nebylo, ale zase FP operace v SW emulátoru byly mnohem pomalejší. Třeba IDIV mělo 171-190+EA cyklů a IMUL na tom nebyl o moc líp se 134-160+EA cykly. A to při SW FP operacích bylo potřeba mnohem více instrukcí, včetně normalizací, převodů operandů na stejné exponenty atd.
Tak ty stare procesory nebyli vubec pipelinovane - byl to v podstate stavovy automat co si jel to sve dokola, tudiz pak mate tento vykon:
Intel 8086: 0.330 MIPS at 5.000 MHz
Coz znamena prumerne 15 taktu "sbernice" na instrukci.
Ohledne instrukci - k cemu preruseni? To se v pripade FPU pouziva jen k indikaci chyby, a je to drat bokem dokola, do standardniho radice preruseni.
Instrukci registr se nesdili (nic takoveho ani neexistuje). Oba cipy dekoduji sled instrukci - a ty co pro nej urceny nejsou (podle prefixu) jednoduse ignoruji. V podstate by se dalo rict, ze to cele ridi procesor (vcetne treba cteciho cyklu pro IMM argument instrukce), a koprocesor nasloucha.. a kdyz uslysi magicke sluvko (svoji instrukci) tak se probere k nejake cinnosti. V pripade ze potrebuje sbernici, tak si ji prevezme.
"instrukčním registrem" jsem myslel interní registr nepřístupný programátorovi, místo kam se z RAM načte kód instrukce a následně zpracovává - rozhoduje CPU/FPU, převádí na mikrokód apod.
Neznám pořádně architekturu x86, takže neřeknu terminologicky věci správně (proto jsem rád za tento seriál), myslel jsem to obecně jak fungují procesory.
Také lovím z drahé děravé paměti a pamatuji oslnění nejprve SW FPU emulátorem (majstrštych bylo ukrást ty opravdu rychlé, optimalizované a žeroucí jen 230KB RAM), který jsem posléze nahradil a do prázdně zející patice osadil úžasnou I80387 na mé I80386DX s nejprve 1MB RAM (a to si ještě namapování BIOSu ukouslo podstatný kus... asi 30%, řešilo se to v DOS x86 para virtual módem zavedením jednoho .sys modulu jehož jméno teď hned nevytáhnu z rukávu), jenže Borland Turbo Pascal i C/C++ vyžadoval tý paměti pro svůj start 2MB... tak se mi podařilo přesvědčit rodiče to druhé mego dokoupit... (za podstatně jinou láci než se o pár let později na delši dobu ustálila cena 1MB/1000 Kč) a pak jsem si mohl vybrat, zda-li nabootuju Linux kernel v0.9 s TCP/IP stackem a nebo ušetřím cca 350kB RAM (pro TCP/IP) a budu psát a debugovat (bez network části) BBS kód běžící posléze na bbs.vslib.cz...
Perlička těchto FPU byla ta, že patice byla kompatidebilní => k I80386 jste mohli osadit I8087 (i na můj vkus pomalý<g>) nebo I80287, kterýžto byl o poznání lepší výkonově (to jsem chvíli měl, protože I80387 byl skoro násobně(!) dražší). Nejsem si ale jist, zda-li byly funkční všechny možné kombinace a pokud si to tedy pamatuji dobře nešlo to obráceně - např. I80387 nešlo osadit k I80286.