Princip, kde se u 32-bitových instrukcí vynuluje horních 32bitů registru byl velmi kontroverzní u AMD64 a tak je celkem zajímavé, že to u AArch64 dělají stejně. Zajímalo by mě, jestli tyhle procesory mají nějakou obdobu Kompatibilního režimu u AMD64, tj. možnosti spustit 32bitový userland process and 64bitovém jádře.
K tomu Archimedovi: údaj, že měl přes 4 MIPS je zavádějící. Acorn tohle tehdy náležitě rozmazával v reklamách, ale samozřejmě přitom nezmínil jistý "detail" a sice že ten procesor měl JENOM instrukce, které bylo možné vykonávat v jednom cyklu. Na rozdíl od M68000 u Amigy a ST neměl žádné složitější operace, například dělení a dokonce i násobení se muselo dělat čistě softwarově a výsledné rutiny samozřejmě vyžadovaly pár desítek cyklů. Archimedes byl ve své době úžasný počítač, znatelně rychlejší, než Atari a Amiga, ale ne osmkrát rychlejší, jak tvrdila propaganda.
Hm, proč bylo nulování horních 32 bitů kontroverzní? IMHO je to docela praktické - speciálně o virtuálních jazyků (JVM) používá běžně 32-bitová aritmetika (nebudu teď polemizovat o výhodách a nevýhodách) a následně se pak výsledek musí použít nějakým způsobem pro adresování. A v té chvíli se nemusí těch 32 bitů explicitně mazat. Opačný případ - že bych chtěl horních 32 bitů použít, když počítám spodních - si těžko dokážů představit. Snad jen load immediate, ale pro ty jsou stejně speciální instrukce a použití aritmetiky tam nedává moc smysl...
Ta kontroverze nějak souvisela s pointerovou aritmetikou - vývojáři překladačů chtěli moct používat 32 bitové instrukce pro výpočet adres prvků ve vektorech apod. Jinak s tím taky souvisí jedna zajímavá historka. Opkód 0x80, který se na x86 odjakživa používal jako NOP, byla ve skutečnosti opravdická instrukce. Pokud si vzpomínám, bylo to cosi jako MOV al, al bez aktualizace stavového registru. V praxi taková operace nemá žádný efekt a tudíž běžně suplovala jako NOP (který starý x86 jinak neměl). Ovšem u AMD nastal problém, že vzhledem k ostatním volbám návrhu (32 bitové instrukce se mají chovat stejně + nulování horních bitů) tenhle nevinný opkód najednou znamenal vynulovat čtyři horní oktety v rax! Takže už žádný NOP ale normální pořádná instrukce. U AMD proto předefinovali instrukční sadu tak, aby 0x80 znamenalo skutečný pravý NOP a stará nesmyslná operace s al se tak ztratila. Zkrátka, v zájmu zachování zpětné kompatibility AMD muselo změnit operaci, která nedělá nic, tak, aby nadále pořád nedělala nic, ovšem jiným a zpětně nekompatibilním způsobem :))
Zdravím a trošku dodám k tomu MIPS: ta jednotka je takto definována, někdy má smysl to porovnávat, někdy je to samozřejmě hodně nefér (například nějaký primitivní RISC-I versus například IBM procesory s mikroprogramem pro vyšší jazyky). I tady je to porovnání RISC versus CISC, takže na jednu stranu je pravda, že to není fér, na stranu druhou to programátoři mohou vidět přesně naopak - kde má M68k prefixy s podmínkami (na dobu vzniku geniální věc)? Kde má obdobu LDM/STM, která je skutečně používaná překladači pro zásobníkové rámce. Když dojde na mul/div,je to samozřejmě jinak, to potom řešily další ARM jádra :-)
Rozhodně nechci ARM nijak shazovat, opravdu měl řadu na svou dobu zajímavých inovací a navíc Archimedes byl tuším jeden z vůbec prvních mikropočítačů s 32bitovou sběrnicí. I tak si ale myslím, že jablka se musí porovnávat s jablky. Uvažovat v MIPS má smysl všude tam, kde jde o tok instrukcí jako takových: při návrhu prediktorů, cache, sběrnice atd... Z programátorského hlediska je ale IMHO důležité jedině to, jak rychle dokáže procesor provést daný výpočet. Příklad budiž skalární součin čili násobení s akumulátorem (když už tu byla řeč o 3D hrách). Torzo takové smyčky bude - zjednodušeně - MOV-MOV-MUL-SHR-ADD. Dejme tomu, že pracujeme ve fixní čárce a s 16bitovými hodnotami, což bylo typické. Na M68 trvalo načtení 16 bitové hodnoty, s post-inkrementací ukazatele, 4 cykly. 16 bitové ADD byly (pokud se nepletu) taky 4 cykly. MUL bylo monstrum, trvalo tuším nějakých cca 50 cyklů (!). Shift o 16 bitů se dělal instrukcí SWAP, která sice trvala 26 cyklů ale kupodivu to bylo pořád rychlejší, než obecné instrukce shift. Celkem to dává 88 cyklů při taktu 8 MHz (na Atari ST. Amiga běžela na 7 MHz). Na ARM trval load z RAM (předpokládám) 1 cyklus, shift a součet taky po jednom, MUL nebylo vůbec a muselo se dělat ručně. Buďme benevolentní a předpokládejme, že máme nějakou supr dupr rutinu, která to zvládne za 30 cyklů (u 16 bitových operand). Takže celkem 34 cyklů při 4 MHz. Suma sumárum, pokud mám ty čísla správně, tak to Archimedes teda zvládl o nějakých 13% rychleji, než nejrychlejší stroj s M68K. To není málo, ale je to přece jenom úplně jiná realita, než co se tehdy snažil vsugerovat marketing o 4 MIPS versus 0.5 MIPS.
Dnes už si to nepamatuji zcela přesně, měl jsem A4000 a dost pro něj programoval v asm (nebo kombinaci BASIC+asm), ale s tím jedním cyklem to není pravda (alespoň pro ARM250). Většina instrukcí 1 cyklus, pár 2 taktových (v nějakých kombinacích) a nejdelší paměťové (LD, ST) 4 cyklové. Ale knížku jsem prodal s počítačem, takže nemám, kam se podívat. Naopak shifty se dělaly v barell shifteru jako součást jakékoliv instrukce, takže i násobení se dalo napsat velmi rychle - trošku "roztahat" smyčku, použít posun a podmínku jako součást instrukce sčítání...
Ale jo já to beru, na druhou stranu ten výběr násobení je taky dost nefér (když první ARMy naschvál násobičku neměly), protože zase tak pomalé to na ARMech není a zadruhé to nemusí být úplně častá operace (desktop, GUI programy, textové editory, databáze, překladače... doplňte si sami další). Naopak rychlé 32bitové transfery jsou skutečně násobně rychlejší a projeví se (pozitivně) prakticky všude.
[fyi - za domácí úkol si dávám projít si objkód Dooma a zjistit, kolik má v interní smyčce MULů, fakt to nevím a možná budeme překvapeni]
První Archimedy běžely na 8 MHz, takový ty další (co vypadali jako Amiga 500 - vše v klávesnici), např. na obr. 3 už běžely na 12 MHz. Už si nepamatuju, musím se doma podívat do knížky, ale myslím, že už ty první měli Arm v2 a ten MUL měl ne? DIV sice ne, ale MUL jo. Arm v1 byl v podstatě prototyp a maximálně se dával do BBC Micro jako second processor card.
A pravdu má kolega nade mnou, některý instrukce měly 2 takty. S těma 4 nevím... mrknu se.
Volaci konvence na AMD64 neni dvakrat krasa, ale zrovna to zarovnani ma prakticke opodstatneni. Jelikoz mas zarucene, ze zasobnik je zarovnan na 16B, neni problem tam rychle odsunout XMM-registry na zasobnik.
Mnohem vetsi sranda je AArch32, krome toho, ze je zhruba tak alegantni jako AMD64, tak je tam treba perla, ze pokud se jedna o volani bezne funkce, jsou argumenty s plovouci radovou carkou predavany pres FP registry, ale pokud se jedna o variadickou funkci, jsou argumenty s plovouci radovou carkou predavany pres GP registry.
Na základě https://community.arm.com/processors/b/blog/posts/the-top-5-things-to-know-about-cortex-a53 a TRM (http://infocenter.arm.com/help/topic/com.arm.doc.ddi0500d/DDI0500D_cortex_a53_r0p2_trm.pdf kapitola 2.1.1) jsem si celkem jistý, že Cortex-A53 prediktor skoků má.
Zkusím to upřesnit - skutečně to pro dnešní potřeby plně dostačuje a hlavně - je to připraveno na postupné zvyšování až na celých 64 bitů. Interní změny při rozšíření budou IMHO dost minimální, takže ARM může kdykoli (dopředu) zareagovat a tu změnu do nových jader prosadit.
Je to úplně jiná situace, než ta klasická hláška o DOSu, protože tam to měli natvrdo zadrátované, celkově architektura postavená na 16bitovém segmentu a 16bitovém offsetu byla dost hnusná (ani nechci vzpomínat :-), takže byla změna prakticky nemožná. Dtto přechod z 32bitů na 64bitů.
Jen upozornění, 68k má k dispozici 8 datových a 8 adresových registrů (chybně uvedeno 7). Důvod, proč se občas kreslí jako 8 + 7 a SSP/USP zvlášť, je právě ten, že registr A7 je jako jediný s implicitní funkcí zásobníku v několika málo operacích (BSR - volání podprogramu, PEA - uložení operandu/efektivní adresy na vrchol zásobníku).
Co se týče nulování horních 32-bitů 64-bit registrů, tak v každém případě zachování původního obsahu (tak jak je to při 16-operacích na 32 x86) je ta nejhorší možní volba. Znamená buď zduplikovat logiku přejmenovávání registrů na každou půlku zvlášť a řešit instrukce tak, jako by měly dvojnásobný počet vstupních závislostí anebo ponechat regsitru v rámci přejmenovávání v celku a řešit každou 32-bitovou operaci, která zapisuje výsledek do jiného registru než jsou vstupy, jako operaci s další vstupní závislostí na předchozím obsahu výstupního registru. Efekt přerušení závislostí/přejmenování v daném výstupním registru se tedy nekoná.
Jestli rozšiřovat vždy znaménkově nebo nulami může být sporné. Možnost volby je nejlepší, ale zabírá prostor pro zakódování jiných užitečných instrukcí. Společnost ARM zároveň tvrdí, že volitelné omezení výpočtu na 32-bitů může mít využité k snížení spotřeby. Když si pak představíme i jednu z nezákladnějších ALU operací, sčítání ADD, tak pro výpočet spodních 32-bitů je potřeba opravdu o mnoho méně tranzistorů/hradel než pro celých 64-bitů. Komplexnost logické funkce CLA (předvýpočet přenosů) roste nelineárně (nejspíš exponenciálně nekontroloval jsem to teď) s počtem výstupních bitů. Vzhledem k tomu, že velikost spotřebované energie na instrukci pro CMOS architekturu je daná především počtem signálů/spojů, na kterých dojde ke změně logické úrovně, tak zafixování vstupů horní půlky sčítačky (především CLA) na nule může vést k podstatné úspoře.
To je samozřejmě pravda, ale nesmí se zapomínat, že A7 se přece jenom chová zvláštně. Například na rozdíl od A0-A6 se inkrementuje o dva bajty i při osmibitových operacích. Od ostatních se liší i tím, že M68k má dva stack pointery, USP a SSP, a A7 se vždycky mapuje na jeden z nich podle toho, v jakém režimu procesor zeovna beží.
Naopak A6 je adresový registr jako jiný, i když tradičně slouží jako frame pointer.
To je samozřejmě pravda, ale nesmí se zapomínat, že A7 se přece jenom chová zvláštně. Například na rozdíl od A0-A6 se inkrementuje o dva bajty i při osmibitových operacích. Od ostatních se liší i tím, že M68k má dva stack pointery, USP a SSP, a A7 se vždycky mapuje na jeden z nich podle toho, v jakém režimu procesor zeovna beží.
Naopak A6 je adresový registr jako jiný, i když tradičně slouží jako frame pointer.