Keresés

Hirdetés

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

  • P.H.

    senior tag

    válasz dezz #654 üzenetére

    A 8/16/32/64 bites x86 készlet (folyamatosan bővítve a P1-ig) így néz ki:

    - othogonális stílusú utasítások: op dest,src forma, ahol dest és src vagy register, vagy cím, vagy közvetlen adat lehet, de nem lehet op mem,mem forma, értelemszerűen a dest nem lehet közvetlen.
    prefix | opcode | ModR/M(+SIB) | addr_offset | immediate (32 bitben a leghosszabb utasítás tizenvalahány byte-os lehet).
    pl. lock add [edi+ecx*2+0000100h],eax vagy add eax,20h
    Az kód alap cím- és adatméretet (default word = 16/32/64 bit, 8 bites adatméret mindenhol van, az más opcode) a kódszegmens bizonyos bitjei határozzák meg, ezért az addr_offset és az immediate egyenként 16/32/64 bites lehet. Lehetne, de ha valamelyik -128 és 127 között van, akkor az 8 biten kódolódik, decode idején előjelhelyesen kiegészítődik.
    A default word méretek között egy-egy utasítás erejéig a 66h (adatméret) és 67h (címméret) prefixekkel lehet váltani, 64->16 és 16->64 váltás nincs. Az opcode kódolja az adatméretet (8 vagy default word), a ModR/M és a 32 biten megjelent opcionális SIB (scale-index-base) kódolja az memóriaoperandus címének formáját és hosszát (8 vagy default word méret), ha van egyáltalán, illetve az egyik vagy mindkét register-operandust.
    - van egy nagycsomó egybyte-os egyoperandusú utasítás, közvetlenül opcode-ban kódolt argumentummal: nyolc külön darab INC, DEC, PUSH, POP,... utasítás van a 8 register-re, persze ezeknek van egy-egy 9. formája is, ami memóriaoperanduson dolgozik (ModR/M vagy SIB segítségével), minden 8 bit displacement-es feltételes urgásra (később 0Fh prefix-szel kiegészítve jelentek csak meg a default word displacement-es változatok).
    - a 8086 átvette a 8085 jórészt klasszikusan akkumulátoros/célregister-es utasításait is, ezek is egybyte-os utasítások, pl. a MOVSD 32 bitet beolvas a ESI által mutatott címról, azt kiírja a EDI által mutatott címre, majd továbblépteti 4-gyel a megfelelő irányba (ezt a EFLAGS egy bitje mutatja). Ha emellé odateszünk egy REP/REPZ vagy REPNZ prefixet, akkor ezt annyiszor ismétli, amennyi ECX értéke kezdetben (meg ha időközben a ZERO FLAG beállt/törlődött, összehasonlító jellegűeknél, mint CMPSD, SCASD). Viszont ezek némelyikének is van 8 bit-es argumentuma. Rengeteg utasítás tartozik ide is.
    - De hasonló jellegű utasítás máig az integer osztás (osztandó EDX:EAX-ben, eredmény EAX-be, maradék EDX-be), a port-I/O utasítások, és még sokan mások. Ezek egy 1 opcode byte-osak, egyik operandusuk fix, a másikat mondja egy ModR/M(+SIB) mondja meg.

    Még leírni se egyszerű. És ez még csak a kezdet, a rendszerutasításokat, mint time-stamp counter, controlregister-ek, descriptor table register-ek kezelését hagyjuk inkább.

    Az x87 utasítások opcode-ja 2 byte-os, az első (talán) 9 bit megegyezik, a többi 7 kódolja a műveletet, és hogy memóriacím vagy register a másik operandus, ha előbbi, jön a ModR/M(+SIB).

    Időközben elfogytak az egybyte-os opcode-ok, így a 486-os időkben már egy 0Fh byte-ot is fel kellett venni az új utasítások elé (pl. CPUID, de azért csak sikerült pl. 8 darab BSWAP utasítást elhelyezni a táblában...), mint 'alternative instruction set' prefix, ez később elvesztette prefix jellegét (a decode-nál nem volt mindegy P6-ig), az MMX és az SSE1 utasításokban mindben benne van. Az AMD a három dínó idején egyszerűen megduplázta a 0F prefix-et, így ők már akkor 3 byte-os opcode-nál tartottak.
    Az Intel sem fért bele teljesen a 2 byte-os opcode-ba SSE1 esetén, ezért ők mást találtak ki. A skalár és vektorutasítások (ADDSS és ADDPS) abban különböznek, hogy a skalár előtt ott egy REPZ prefix, innen ugyanaz a formája, mint a vektoros alaknak.
    De az SSE2-t is ábrázolni kellett valahogy, az megint több, mint 140 utasítás, itt az 66h adatméret-váltó prefixet tettek az SSE1 és az MMX megfelelő alakjai elé. De hogy ne legyen egyszerű, a skalár floating-point SSE2 előtt nem 2 prefix van (66h és REPZ), hanem csak egyetlen REPNZ.

    Az egészet fejeljük meg 64 bitben egy REX prefix-szel, hogy a plusz 8-8 általános és XMM registerhez hozzá tudjunk férni. Mindezek mellett az AMD és az Intel is bizonyos esetekben azt ajánlja, hogy NOP műveletek helyett a kód (cikluskezdés) 16/32 byte-os határra illesztését inkább az opcode-dal együtt nem értelmezhető prefix-ekkel tegyük meg (pl. x87-műveletek elé betett REPZ prefix-szel), mert a NOP-pal szemben ezek nem foglalnak macro-op és micro-op helyet...

    A kód a kódban, tehát hogy egy ugró utasítás célja egy másik utasítás azonnali értékének valamely belső byte-ja, ami onnan önmagában is értelmes utasítás, még 8 éve is egyetemi vizsgatétel volt assembly-ből.

    Nagyon egyszerűen: code segment az alapméretet adja, akárhány prefix lehet az opcode előtt, az opcode mondja meg az azonnali érték létét és hosszát, valamint, hogy van-e ModR/M byte, a ModR/M mondja meg, hogy van-e SIB byte, és utóbbi kettő, hogy van-e a címhez is azonnali érték. Mindezt módosítják a prefixek.
    Erre mondják azt sokan, hogy ki kellene dobni az egészet a fenébe, és egy teljesen új (lehetőleg regularized instruction field alapú) utasításkészletre áttérni.

    SSE2+ persze, addigra már megártott a sok .PDF, amit aznap olvastam :)

    [mod]: ...ha csak egyszer sikerülne pársoros hsz-t összehozni.

    [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