Hirdetés

Új hozzászólás Aktív témák

  • P.H.

    senior tag

    Dekódolás/utasításfordítás

    A 32 byte-os blokkokat, melyek az utasításcache-ből érkeznek, a Predecode/Pick Buffer-be másolja, kisorjázza az utasításokat (egy több byte-os utasítás kezdődhet az egyik blokk végén és végződhet a következő blokk elején), azok jellege ilyenkor már ismert, tehát mehetnek a megfelelő dekóder-lépcsőkre: az egyszerű utasítások, melyek egy (Single) vagy két (Double) elemi egységre fordulnak, a DirectPath-nak nevezett egyszerű dekóderbe kerülnek, a komplex, 3 vagy több elemi egységre forduló utasítások a VectorPath-ra (a mikrokód dekóderbe) kerülnek. Ezeket az egységeket a továbbiakban macro-opoknak nevezzük (a cikk MOP-nak nevezi őket, én a továbbiakban maradok az AMD szerinti elnevezésnél).

    Órajelenként legfejlebb 3 macro-op hagyhatja el a dekóder-fokozatot. A DirectPath-dekóder órajelenként vagy 3 db 1 macro-opra forduló, vagy 1 db 1 macro-opra és 1 db 2 macro-opra forduló, vagy pedig ''1,5 db'' 2 macro-opra forduló utasítást dekódol. A komplex utasítások akár több, mint 3 macro-opot is eredményezhetnek, ezért több órajelre lehet szükség a feldolgozásukhoz. Annak elkerülése végett, hogy két út kimeneti macro-opjai konfliktusba kerüljenek a dekóder-lépcsők elhagyásakor (órajelenként legfejlebb 3 macro-op kerülhet ki, akárhonnan is jöjjön), ezért a K8 és a K10 képes képes egyszerre, párhuzamosan küldeni egyszerű és a komplex utasításokat a két útra.

    Minden macro-op két micro-opból állhat: egy integer vagy lebegőpontos aritmetikai micro-opból és egy memóriahozzáférési micro-opból (ezek egyikéből vagy mindkettőből). Ez a két micro-op egészen az ütemezőig egy egységet képez, az ütemezőkben válnak el és futnak függetlenül egymástól.

    A dekódereket elhagyó órajelenkénti 3 macro-op egy hármas csoportot alkot. Számos esetben a dekóderek csak 2, sőt esetenként csak 1 macro-opot generálnak az adott órajelben, pl. váltakozó DirectPath és VectorPath utasítások esetén. Az ilyen, nem teljes hármasokat üres macro-opok egészítik ki hármasokká, így kerülnek tovább.

    Vektorjellegű (128 bites) SSEx utasítások a K8 processzorok esetében 2 db 64 bites macro-opra fordulnak le, egy-egy külön a felső és az alsó 64 bites félnek, emiatt ezek esetében az ideálishoz képest felére csökkentve a dekódolási sávszélességet, és kétszer annyi helyet foglalva a belső pufferekben (pl. az ütemezőkben). A K10 natív 128 bites FPU-egységeinek köszönhetően nincs szükség erre a darabolásra többé. K8 esetében a legtöbb SSEx-utasítás DirectPath Double úton fordult, 2 macro-opra, K10 esetében ezek DirectPath Single 1 macro-op utasítások. Továbbá néhány SSEx-utasítás, amely K8 esetében VectorPath úton (3 vagy több macro-op) fordult, K10 esetében DirectPath (Single vagy Double) lett, 1 vagy 2 macro-opot adva. (Ezt azért emeli ki a szerző, mert a korábbi, 64 bites feldolgozást használó Intel processzoroknál is a fordítás 128 bites egységekre történt, így kerültek be az végrehajtó egységekbe, ott 2 db 64 bites darabban kerültek feldolgozásra, majd az egység elhagyása előtt összeállt az eredmény 128 bitre. Tehát a natív 128 bitre váltás önmagában nem befolyásolta számottevően pl. a dekódolást.)

    A vermet használó utasítások dekódolása szintén egyszerűsödött. A legtöbb veremművelet CALL-RET (eljáráshívás és visszatérés) illetve PUSH-POP utasítás, ezek egyetlen macro-opra fordulnak K10 esetében, továbbá a Sideband Stack Optimizer segítségével ezen az utasítások láncolata egymástól független, párhuzamosan végrehajtható egységekre fordul.



    Sideband Stack Optimizer

    Ez az egység a Core és Core 2 CPU-k Stack Pointer Tracker egységével megegyezően működnek. Miért van szükség ezekre? Az x86 a CALL, RET, PUSH és POP utasításokat használják eljárások hívásra, eljárásokból visszatérésre, paraméterek átadására és a register-értékek átmeneti mentésére. Ezek az utasítások a verem tetejére mutató ESP register-t módosítják, sorozatuk tehát csak egymás után hajtható végre, mert a bemeneti registerértékük (az ESP) értéke függ a programsorrendben előző utasítás eredményétől (amit az ugyancsak az ESP register-be ír).

    A két táblázatban bemutatja, hogy egy általános eljáráshívás PUSH-PUSH-...-PUSH-CALL-PUSH-PUSH sorozat, egy eljárás befejezése pedig POP-POP-...-POP-RET szekvencia, és ez milyen elemi műveletekre fordul le K8 és K10 esetében.

    Mint látható, egy eljáráshívás a paraméterek átadásával, a vezérlésátadással és bizonyos register-értékek átmeneti elmentésével jár, melyek mindegyike módosítja az ESP registerek értékét. Ez az utasításláncolat nem párhuzamosítható, és a vermet érintő későbbi utasítások is csak a lánc teljes lefutása után férhetnek hozzá a veremhez.

    Mindkét gyártó megoldása azonos elven alapul: az ESP register a processzor mélyén a lehető legkevesebb esetben módosul, pontos értékét nem is ismeri a Sideband Stack Optimizer, csak egy számlálót tartalmaz. A lefordítandó utasításokról tudja, hogy azok mennyivel módosítjanák az ESP értékét, az utasításokat egy ESP+xxx memóriahozzáférésre fordítja, ahol xxx a számláló aktuális értéke, majd a számlálót növeli/csökkenti az utasításnak megfelelően. Ezenkívül ismer még egy speciális szinkronizáló macro-opot, ez egyszerű ADD ESP,counter alak, és ha bizonyos utasításokkal találkozik fordítás közben (pl. amelyek már alapvetően ESP+xxx alakúak), leküld még a lefordított utasítás előtt a futtató egységekhez egy ilyen szinkronizálást, majd nullázza a számlálóját. Az ESP+xxx alakra fordított memóriahozzáférő utasítások pedig egymástól függetlenül végrehajthatók, illetve az eljárástörzs betöltheti a paramétereket akár már a verem teljes lekezelése előtt (out-of-order).

    Ennek, a megnövekedett méretű return-address puffernek, valamint az indirekt ugrások hatékonyabb kezelése jótékonyan befolyásolja sok kis, specializást eljárásokat alkalmazó programok futását (tipikus C/C++ megközelítés).

    A K10 dekóderei ugyan nem képesek órajelenként 4 utasítás fordítására, mint a Core 2-éi megfelelő körülmények között, de ez nem jelent szűk keresztmetszetet: az átlagos feldolgozás majdnem mindig eléri a 3 művelet/órajel ütemet, így a K10 dekóderei kielégítően és egyenletesen ellátják a végrehajtási egységeket, mind az üresjáratokat, mind az utasítástorlódásokat elkerülve.



    Instruction Control Unit (ICU)

    A lefordított macro-op hármasok az Instruction Control Unit-ba kerülnek, mely továbbítja őket az átrendezési pufferbe (Re-Order Buffer, ROB). Ez utóbbi 24 db ilyen hármas tárolására képes, így legfeljebb 24x3=72 macro-opot képes kezelni egyszerre.
    Innen a macro-opok az integer vagy az FPU-egység ütemezőibe is bekerülnek, pontosan abban a sorrendben, ahogy a dekódolási fázisból érkeztek (~programsorrendben), de a ROB egészen addig tárolja őket, amíg be nem fejezték életútjukat a CPU-n belül (lefutnak, eredményük ismert lesz, továbbá programsorrendben véglegesítődnek, tehát nem kerülnek érvénytelenítésre pl. egy téves elágazásbecslés miatt). A véglegesítés (retirement, visszavonulás) során továbbítják eredményüket a memóriába, vagy befolyásolják a CPU-környezetet (jobban nem tudom megfogalmazni, tehát az architectural state-et módosítják, a programsorrentben utánuk következő utasítások az ő eredményeiket fogják látni). A ROB feladata tehát, hogy a téves elágazásbecslés, megszakítás, kivétel, stb. miatt feleslegessé vált macro-opokat és eredményeiket eldobja.

    Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

Új hozzászólás Aktív témák