Hirdetés

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

  • P.H.

    senior tag

    válasz #95904256 #530 üzenetére

    Téged is megzavart, hogy magát a CPU-t és az execution unit-okat is pipe-nak nevezik (én is, de az össes dokumentácó ilyen). Megpróbálom leírni röviden az K7-en levezetve a microarchitecure-t. K7-en, mert alapvetően alig tér el a K8 és a K10-től, és ehhez nagyon részletes dokumentációt adott ki az AMD.

    [kép]
    Maga a teljes CPU egy pipeline, csak 3-way superscalar miatt órajelenként max. 3 ottani adategység léphet tovább a következő stage-re (minden ábrán minden szint között legalább 3 nyíl megy függőlegesen). A lépések, órajelenkénti bontásban:

    [kép]
    cycle 1. FETCH: kiszámolja a következő utasításablak címét (+branch prediction, CALLs, RETs, ...), amit az L1-ből vagy a memóriából be kell tölteni.
    cycle 2. SCAN
    : meghatározza az egyes utasítások elejét és végét, majd vagy a DirectPath-ra (legfejlebb 6 utasítás/órajel) és VectorPath-ra továbbítja őket (legfejlebb 1 utasátás/órajel).
    cycle 3. ALIGN1 (DirectPath): 8-byte-os sorokban kapja az utasításokat, minden sorban legfejlebb 3 utasítás lehet (ekkor még minden 1 byte-os x86 utasítás VectorPath-ra került), 9 ilyen sort pufferel. Minden órajelben legfejlebb 3 utasítást megpróbál továbbítani az ALIGN2-be.
    cycle 3. MECTL (VectorPath): a kapott VectorPath-utasításhoz meghatározza a microcode-ROM belépési címét.
    cycle 4. ALIGN2 (DirectPath): prefix-ek, az opcode-, ModR/M- és SIB-byte-ok megkeresése, és ezen információk továbbítása.
    cycle 4. MEROM (VectorPath): a microcode-ROM-ot megnyitja (indexeli, nem is tudom, hogy mondjam) az adott belépési pontnál.
    cycle 5. EDEC (DirectPath): az ALIGN2-ből és a MEROM lépcsőtől kapott infomációk alapján macro-opokká dekódolja az utasításokat. Ezenkívül meghatározza az azonnal argumentumokat, register-pointereket és eltolásokat.
    cycle 5. MEDEC/MESEQ: közvetlenül a microcode-ROM-ból jönnek a macro-opok (ezek saját különálló belső register-csoporton dolgoznak)
    cycle 6. IDEC/Rename: a macro-opok elosztódnak a két ütemező között. Az összes macro-opnak, ami az FPU-egységbe kerül, a register-argumentumai leképeződnek a belső registerfile egy-egy elemére (itt fordul át pl. az 'XMM1' vagy 'MM6' a megfelelő sorszámú belső register sorszámára - 88- vagy 120-entry register file).

    Innen az összes macro-op a Instruction Control Unit-ba (ICU) kerül. Innentől a pipe egy hurok, tehát tovább innen indulnak a macro-opok, és itt is fejezik be pályafutásukat (visszavonulás/retirement), vagy az machine state-nek (register-ek, flags, ...) eredményük szerinti felújításával, vagy kiléptetéssel (mert téves elágazási ágjóslat volt), illetve itt váltódnak ki a kivételek is. Ez osztja el a macro-opokat az integer és a FPU-egységek felé.

    [kép]
    Az integer egység:
    cycle 7. SHED: az integer ütemező, itt várják meg a macro-opok, hogy megérkezzen az összes input adatuk. (És AMD-nél valóban megvárják, nem úgy, mint Netburst alatt.) Közvetlen kapcsolata van a result bus-sal, így az input adatok nem a véglegesített machine state-ből jönnek, hanem rögtön a kiszámolás után. Innentől az elemi egységek a macro-opok helyett micro-opok, ezekből egyszerre legfejlebb 6 léphet tovább órajelenként, 3-3 az ALU-kba és az AGU-kba.
    cycle 8. EXEC: a micro-opok végrehajtódnak, az eredményüket kiteszik a result bus-ra. Ha egy macro-opban levő minden micro-op lefutott, akkor az ICU elindítja a visszavonulási (retirement) folyamatot.
    cycle 9. ADDGEN, cycle 10. DCACC, cycle 11. RESP: address generation (effektív -> lineáris cím konverzió, az effekív címet számolják az AGU-k), Data Cache access, Response, load/store kapcsolat a Data Cache-sel.

    [kép]
    Az FPU-egység sokkal ''érdekesebb'':
    cycle 7. STKREN: stack rename órajelenként legfeljebb 3 macro-opot fogad az ICU-ból, valamint x87 utasításoknál az ST(x) alakú stack-relatív formát fordítja a megfelelő sorszámú belső register sorszámára (88- vagy 120-entry register file)
    cycle 8. REGREN: register-átnevezés. Minden művelet eredménye fizikailag más register-be íródik (tehát az ADDSS xmm0,xmm2 formában a bemeneti értékek mondjuk az fp15 és fp54 fizikai register-ek, de az eremény NEM az fp15-be fog íródni, hanem egy másik register-be.
    cycle 9. SCHEDW: sheduler write, akkor íródnak a macro-opok az ütemező pufferébe, órajelenként 3.
    cycle 10. SHED: maga az ütemező. Innentől megint a micro-op az elemi egység. Az ütemező folyamatosan scan-neli a puffer-ét, legfejlebb 3 olyan micro-opot keresve, amiknek már nem kell várniuk a bemeneti értékeikre, hogy továbbítsa ezeket az EXECUTION UNIT-ok felé. Minden micro-op csak bizonyos unit-ban indulhat el, néhány micro-op csak ''bizonyos időben'', mind a háromra keres egy-egy ezeknek megfelelőt. Azok még a következő órajelben a cycle 11. FREG stage-ben a register-ekből kiolvassák a bemeneti értékeiket (minden unit saját, belső register-eivel dolgozik, nem közvetlenül a register-file-ba), majd elindul a futtatásuk.

    És ezek az execution unit-ok az FADD, FMUL és az FSTORE/FMISC. Órajelenként egy micro-opot tudnak fogadni, az ábrán megnézve a CPU 15 stage-es pipe-ja itt (megint, mint ahogy a két ütemező felé, vagy a 3 ALU/AGU esetében) elágazik, az FEXEC1-FEXEC4 az 12., 13., 14. és 15. stage-ek vertikálisan, de ezek 3 különálló pipe különböző szintjei. Valójában nem is három, mert egy-egy unit megintcsak többfelé ágazik, csak a port közös bennük. Ráadásul ezeknek az ágaknak nem is mindegyike teljesen pipe-olt (pl. az osztó), és nem is egyforma hosszúak (az MMX ALU csak 2 lépcsős, FEXEC12 és FEXEC 13 szintje van csak), de a leghosszabb ág is csak négy stage hosszú.
    az FADD alágai: 3DNow!/SSE adder, MMX ALU/shifter, FP adder
    az FMUL alágai: 3DNow!/MMX multiplier/reciprocal, MMX ALU, FP multiplier/divider/square root (ez utóbbi úgy pipe-olt, hogy négy lépcső hosszú, de az egyik lépcsőben mondjuk 30 órajelig marad az micro-op számolás közben).
    Említettem, hogy a portok órajelenként tudnak egy micro-opot fogadni, viszont az alágak nem törvényszerűen. Ezért szokták megadni utasításszinten a latency mellett a throughput-ot mint legfontosabb adatot, azaz, hogy ugyanaz az ALÁG hány órajelenként tud új utasítást fogadni. Ha az alág pipe-olt, akkor órajelenként egyet, de ha nem, akkor meg kell várni majdnem a teljes lefutást. Például az lappangása K8-on DIVPD 37 órajel, és a következő DIVPD 34 órajel múlva indulhat el. Viszont ezen 34 órajel alatt az FMUL egység vígan tud fogadni és lefuttatni 34 szorzó micro-opot.
    A másik lényeges dolog ezeknek az egységeknek a szélessége. Ha K8-ról beszélünk, akkor ott egy 64 bites összeadó van az FADD egyégben, ezért egy ADDPD macro-opja két összeadó micro-opot fog tartalmazni, ezek egymás utáni órajelekben lépnek be az FADD potján, egymás után mennek a pipe-stage-eken, a második 1 órajellel később fejeződik be, ezért programozói szinten ADDPD utasítás lappangása 5, átvitele 2. Tegyünk mellé még egy 64 bites összeadót, ekkor az ADDPD-hez csak egy micro-op kell, nem gyorsítunk semmit magukon az elemi összeadókon, és máris az ADDPD lappangása 4, átvitele 1 lesz.

    Remélem, így már tisztább.

    [Szerkesztve]

    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