Origin 2100 (rok dodani 2000, 2 GB RAM, 8 CPUs) mame jako hlavni studentsky server, a az letos ho se slzou v oku nahrazujeme za novejsi.
Jinak procesory MIPS maji spoustu zajimavych vlastnosti, o kterych by se dalo mluvit, napriklad:
– nema instrukce pro praci se zasobnikem – proste se jen jeden obecny registr „dohodou“ vyhradi jako ukazatel zasobniku, a instrukce typu PUSH, POP se rozpadaji na LOAD/STORE a inkrement/dekrement toho registru
– CPU muze byt nabootovana v big-endian nebo little-endian rezimu (kdysi existovaly dve binarni verze Linuxu pro MIPS podle endianity).
– CPU neumi delat nezarovnane pristupy do pameti (x86 umi, ale je to pomale a stoji to hodne kremiku), takze treba LOAD dvoubajtoveho cisla z liche adresy vyvola vyjimku (IRIX ji pak reportuje jako SIGBUS).
SGI (a dnes vlastne vsechny NUMA systemy) pouzivaji variantu „cc-NUMA“ (cache-coherent), coz znamena, ze programator se nemusi starat o koherenci pameti v jednotlivych uzlech. Funguje to zhruba tak, ze sice jeden radek cache muze byt na vice NUMA uzlech, ale jen pokud ty uzly jen ctou. Pokud nekdo chce zapisovat, musi se podivat jestli zapisuje nekdo jiny (pokud ne, staci jen vsem ostatnim prislusny radek cache zneplatnit a je mozno zapisovat). Tohle ovsem dela HW, nikoliv programator.
To ze je procesor primo navrhovany pro NUMA systemy se da vyuzit i v dalsich vychytavkach. Treba na x86 se zamky (spinlocky, semafory, …) delaji pomoci atomickych instrukci (LOCK, CMPXCHG, …). Na MIPS je mozne zamek udelat napriklad tak, ze procesor udela obycejny LOAD a STORE, jen potom programator muze testovat, jestli mezi LOAD a STORE nedosel pozadavek na zneplatneni (cili jiny procesor zapisoval). A pak pripadne muze LOAD/STORE sekvenci opakovat. Tohle je pekne, ze to vubec nikde nezamyka sbernici, a na rozdil od x86 se takto na sbernici netlucou libovolne dve „atomicke“ instrukce, ale jen ty, ktere opravdu sahaji na ten stejny zamek.
Kazdopadne ale diky za clanek.
-Yenya, http://www.fi.muni.cz/~kas/blog/
Zajímavé vlastnosti.
Dneska je zásobník nutností už proto, že to není jen fronta čísel ale je to hlavní součást vlákna… třeba jak jsou realizované skoky a návraty? Jistě, určitě to lze udělat uložením adresy do (simulovaného) zásobníku a dlouhým skokem a návrat skokem na adresu v zásobníku. Ale to už mi přijde jako trošku velká onanie.
CPU klidně může omezovat přístup na nezarovnané adresy. Povolování jako u x86 je spíš problém než výhoda, protože samotná vlastnost ničemu nepomůže a jen to napomáhá tvorbě kódu, který je neprenosný (tzv. medvědí služba programátorům). Naštěstí se na x86 tohle dá také zakázat a pak generuje výjimku
x86 postupně (doufejme) dospěje k zamykání na úrovni stránek. Už teď se doporučuje používání interlocked operací omezovat, protože to zdržuje a mnohem jistější je používat protokol acquire a release (tam kde je podporován). Nicméně dřív nebo později to dojde k zamykání stránek a potvrzování, že zápis nebyl v konfliktu.
Největší problém je při návrh knihoven pro řešení těchto věcí. Techniky pro jednu platformu nelze používat v jiné platformě a kolikrát to znamená redesign celého systému.
Naopak delat to takhle mi prijde lepsi, protoze je to obecnejsi a HW jednodussi. Na ARMu je takhle vlastnost taky. Kazda skokova instrukce ma ve svem operacnim kodu `L-bit', kterej kdyz je 1, zpusobi ze adresa nasledujici instrukce se pri provadeni skoku presune do tzv. Link-registru. To je uplne normalni register, ktery se da pouzivat na vypocty, pokud zrovna nedrzi adresu navratu. Obvykle se pak tento registr ulozi na zasobnik az ve volane funkci (na to je instrukce STMDA ktera umi ulozit podmnozinu registru kterou si clovek vybere pomoci bitove masky — takze 1 instrukci se ulozi navratova adresa i registry ktere by funkce jinak prepsala a jeste se dekrementuje ukazatel zasobniku, coz neni fixni registr ale dalsi parametr te instrukce, takze zasobniku muzu mit vic, kdybych to potreboval)
Vyhoda je takova, ze funkce ktere uz dal nic nevolaji nemusi tenhle registr davat na zasobnik, coz usetri trochu prenosu po sbernici.
Krom toho je CPU jednodussi protoze nemusi mit explicitni instrukce PUSH, POP a CALL.
Me to prijde celkem elegantni. Jeste jsem zapomel dodat ze navrat z funkce se provadi instrukci LDMIB, ktera vyzvedne registry opet podle masky a inkrementuje ukazatel zasobniku.
Tim ze misto link registru v masce uvedeme program counter (nebo jak se na intelu rika instruction pointer) tak se tim provede navrat z procedury.
Takže je to vlastně totéž. Vedle jednoduché instrukce skoku s ukládáním do registru a následné ukládání registru existuje poměrně komplikovaná funkce ukládání registrů do zásobníku.
Pro CISCovou strukturu jasně vítězí rozdělení na JMP a CALL/RET. PUSH a POP je vlastně jen obezlicka, aby člověk nemusel ukládat přes MOV na adresu [ESP] a pak ho inkrementovat/dekrementovat.
Pro RISCovou strukturu bych podporu zásobníku vůbec neviděl a skutečně jen jump s uložením instrukčního pointeru… třeba do registru, to už je v celku jedno.
Ještě by se slušelo dodat, že ani kompilátory pro CISC (x86) už push/pop nepoužívají a z instrukcí pracujících přímo s ESP tak zůstává už pouze call/ret. ESP se upraví na začátku podle potřeby a pak už se pracuje jenom s MOV.
Ke speciálním registrům – mj. má i registr zero (r31?), i.e. černá díra, která vrací vždycky 0 (teď doufám, že si to nepletu se Sparc či Alpha). Opět vede ke zobecnění některých instrukcí, které by jinak musely podporovat 2 i 3 parametrové varianty.
Ad LOCK – ono se to nezdá, ale rozdíl je obrovský – zatímco na ARM není mezi normálním a exclusive LOAD/STORE rozdíl, na vícejádru Intelu LOCK sežere mnohonásobek adekvátní instrukce bez LOCK.
Problém je, že x86 už dopředu asi nepůjde, MIPS(LE) dneska nikdo příliš vážně nebere, UltraSparc je s otazníkem, snad se časem prosadí ARM…
Imho Apple používal PowerPC, což byla ořezaná verze IBM POWER procesoru, který IBM dodává v midrange serverech, řady „System p“, nástupce AS/400 – http://en.wikipedia.org/wiki/POWER6 Rozhodně to není něco, co by mělo brzy umřít – třeba frekvence dosahují 5.0GHz, možnosti škálování co do počtu CPU jsou jinde než u x86, pokročilá podpora virtualizace.
Velmi zajímavá je i architektura IBM z10 – http://en.wikipedia.org/wiki/IBM_z10_%28microprocessor%29 – používá se v dnešních IBM Mainframe, System z. Ovšem asi to není nic perspertivního pro consumer segment. Věci jako zpětná kompatibilita do roku 1960 (System/360) a kontrola chyb/redundance na úrovni vnitřních sběrnic CPU a rezervního jádra na CPU modulu nejsou potřeba vždy a všude. Uvítal bych nějaký článek o podobných technologiích.
i MIPS ma nulovy registr (s trvalou hodnotou nula), protoze jeho existence zjednodusuje instrukcni sadu, resp. nektere instrukce se daji zapsat formou slozitejsi (triregistrove) instrukce, kde jeden z operandu je nulovy. Pekny napad, ktery se uchytil u i nekterych mikroradicu.
Me to teda jako nejak uzasny napad neprijde. Spis je to vyplytvani jednoho registru.
Kdybych na CPU ktery ma pritomne vsechny registry chtel toto chovani tak na zacatku programu udelam
xor r31,r31,r31. Jenze nekdy by se mi treba hodilo mit tam 1, nebo ten registr pouzit uplne k necemu jinemu. Takze bych radsi uvital obecnejsi CPU se vsemi registry.
Jedine to snad setri cas pri uklidu registru na zasobnik pri preruseni, ale to je myslim zanedbatelne.
ale musel by si to nulovat VZDY ked bi si si nebol isty.
Na urovni mikroinstrukcii je vyhodnejsie mat jednu instrukciu a moznost nuloveho registra (jednoduchsia implementacia ktora mnohonasobne zaplati realizaciu nuloveho registru) ako mat viac verzii danej instrukcie ci nedajboze tam davat operandy ako hodnoty (kopa zbytocnich presunou)
(1) To by delal kompilator. Kdyz je to tak vyhodny, tak by to bylo nejspis defaultne zapnuty temer pro cely program, a jen v hot spotech kde by se upotrebil ten registr by v nem bylo neco jineho nez nula. Takze by bylo potreba pocet hotspotu + 1 techto nulovacich instrukci.
(2) MIPS (R3000) nema mikrokod a tutiz ani mikroinstrukce.
mikroinistrukcie ma IMAO kazdi procesor. Ale nie kazdy ho ma updatovatelny a nie kazdy procesor z nich ma zlozene komplexne instrukcie.
Viacmenej kazda instrukcia ktora pozostava z viacerich ako z jedneho taktu pozostava z mikroinstrukcii. V pripade RISC procesorou su to viacmenej len podmienene a nepodmienene skoky.
Zalezi na tom cemu rikate mikroinstrukce. Jestli samotnemu faktu ze vykonani instrukce je rozdelene do nekolika fazi tak pak ma mikroinstrukce uplne vse.
Ja ovsem znam pojem `mikroinstrukce' jako elementarni operaci kterou muze provadet mikroprogram. Mikrokod je neco jako takovy mnohem podrobnejsi strojak, ktery pracuje primo s jednotlivymi castmi CPU. Instrukce jsou vetsinou pomerne siroke a jednotlive bity primo znamenaji napriklad ze se ma pripojit registr X k vnitrni sbernici, jiny bit instrukcniho slova pak treba znamena ze zaroven nastavit ALU tak aby secetla to co je na vnitrni sbernici s registrem A, atd a pak jsou tam jeste bity ktere urcuji jak bude mikroprogram pokracovat. Instrukce je rozdelena do nekolika mikroinstrukci, ktere se sekvencne vykonavaji. Mikroprogram je tabulka techto mikroinstrukci. Instrukce procesoru je mozne brat jako indexy do mikroprogramu, kde zacina implementace te ktere instrukce (samozrejme ze z operacniho kodu instrukce se pro tento ucel vezmou (a dekoduji) jen nektere bity – treba bity ktere urcuji nad kterymi registry instrukce pracuje se za pomoci mikrokodu z operacniho znaku instrukce extrahuji pozdeji).
Je i neco co se nazyva vertikalni mikrokod, ktery neni tak siroky, muzete si to predstavit tak ze tu puvodni tabulku nekdo `zkompresoval' tak aby byl dekoder do puvodni sirky realizovatelny dostatecne jednoduchym kombinacnim obvodem. To se zacalo pouzivat kdyz mikrokod (ktery mel puvodne zjednodusit navrh sekvencnich logickych obvodu) zacal zabirat stale vetsi a vetsi cast chipu.
Drive byl ulozen v pameti ROM, dnes (alespon nektere jeho casti) jsou ve FLASH aby je bylo mozne opravit pripadne chyby.
Na druhou stranu je mozne vtipnym navrhem instrukci vytvorit CPU,ktery se bez mikrokodu zcela obejde. Napriklad ARM-2 ma pouze obvodovy radic. A to i presto ze nektere instrukce trvaji vice taktu (jako treba nacteni vice registru) — proste je tam nekde `citac' ktery dokud je nenulovy, donuti radic pokracovat v ukladani registru do RAM.
S trochou nadsazky by se dalo rict, ze to co takovy procesor zpracovava jako instrukce jsou vlastne mikroinstrukce. Vyhodu to ma v tom ze je snadnejsi udelat pipeline — zatimco se jedna instrukce provadi, dalsi za ni se dekoduje a jeste dalsi se teprve nacita z pameti. Protoze kazda faze provadeni ma sve vlastni ridici obvody tak je toto mozne (take musi byt vykonne jednotky propojene `soukromymi sbernicemi', jedna sdilena by nestacila, protoze v jednom taktu je potreba komunikovat vetsinou v kazde fazi provadeni instrukce, tedy tolikrat jak hubokou mame pipeline). Neco takoveho by se s mikrokodem delalo celkem neohrabane.
Dnesni x86 procesory sice maji mikrokod, ale ten se pouziva jen pro zpracovani neprilis castych instrukci (jako prefixy rep, enter/leave a podobne divnosti), ktere tam jsou kvuli kompatibilite s starsimi x86 procesory — v manualu optimalizace je vyslovene nedoporucuji pouzivat, protoze kdyz CPU takovou instrukci potka, vykonava jeji mikrokod seriove a tudiz nemuze vyuzit pipelining. Instrukce tak potom muze trvat i desitky taktu CPU.
Pro srovnani jak muze byt mikrokod neefektivni: MC68000 obsahoval neco kolem 70k transistoru a navrhovalo ho nejmene 10 lidi. Pritom na 8MHz dosahoval vykon okolo 0.8 MIPS. Procesor ARM-2
dosahoval 4 MIPS na 8MHZ, navrhovali ho 2 lide (jeden z nich instrukce, druhy obvodovou impklementaci) a spotrebovali 28k transistoru. Pritom i 68000 byl ve sve dobe velmi dobry procesor.
Zde se muzete podivat jak vypada chip ARM:
http://media.techworld.com/cmsdata/slideshow/3201497/arm_acorn_10_thumb555.jpg
A takto vypada Motorola 68000:
http://www.thocp.net/hardware/pictures/cpu/motorola_68000_1979.jpg
Dva cerne obdelniky v horni pulce chipu, ktere vypadaji jako cache je podle meho nazoru pamet ROM ve ktere je ulozen mikrokod (cache tento CPU nemel).
Zde se muzete poucit o procesoru ARM:
http://noel.feld.cvut.cz/vyu/scs/prezentace2007/arm_AT91SAM7X/
Ono to totiz je motivovano necim uplne jinym, nez si vsichni programatori mysli.
Jde o to, ze pokud dojde z nejakeho duvodu k pipeline stallu, tak je potreba nejak vlozit onu „bublinu“, coz se krasne implementuje tak, ze se nekam do pipeline vlozi instrukce typu add r0, r0, r0 (ktera obvykle prave proto ma v instrukcnim slove same nuly/jednicky), ktera nic nedela. Mit na to nejakou separatni logiku je dnes pravdepodobne daleko rozumnejsi reseni, nicmene v porovnani s celou datovou cestou tech puvodnich riscovych procesoru takova logika opravdu neni zanedbatelna.
Mam taky dojem ze MIPS sa usadil v azii a tam si zije spokojnim zivotom ;-) A beru ho tam aj vazne. Ale Power procesory sa pomaly rozliezaju svetom a IMAO je otazka casu kedy skoncia aj v „peckch“. co som pocul zz teraz IBM vyraba viac Power procesorou na neservrovy trh ako na ten serverovy (a rozdiel je zevraj radovy).
Ale samozrejme na MIPSu je normalni kompilator C a normalne se pracuje se zasobnikem. Jen ten zasobnik neni z hlediska CPU neco specialniho, s cim by se pracovalo vyhrazenymi instrukcemi. Coz povazuju za prudce elegantni.
Podobne konstrukce (registry vyhrazene v ABI platformy pro nejaky specialni ucel, i kdy sam procesor je povazuje za bezne registry) se vyuzivaji casto. Treba registr gp v IA64, ktery se pouziva pro optimalizaci volani funkci v lokalnim modulu (vizte Intel Itanium Software Conventions & Runtime Architecture Guide).
-Yenya
O MIPSech i dalsich typech RISCovych procesoru vyjde samostatny clanek, uz to davam dohromady. Ta instrukcni sada je opravdu velmi jednoducha a instrukce jsou navrzeny tak, aby se provadely s minimalni „spotrebou“ kremiku, psat na MIPS prekladac musi byt urcite mnohem jednodussi nez na x86 (i kdyz x86_64 uz je na tom lepe).
Jinak MIPS zdaleka neumira, spis naopak – pred par (?) lety si na MIPSove jadro koupily patent i cinske firmy a dava se do ruznych embedded zarizeni. I tento prispevek velmi pravdepodobne prosel pres nejake routery apod. s MIPSem.
Zdravim z FOSDEMu :-), kde se mj. docela diskutovalo o ARMech a MIPSech.