Lucifer of ZeroBit - Ja ljublju ASSEMBLY VIII. rész

        ÚÄÄÄ        ÚÄÄÄ     ÚÄ       ÚÄ
       ÚÄ  ÚÄ      ÚÄ   ÚÄ   ÚÄÚÄ   ÚÄÚÄ
      ÚÄ    ÚÄ      ÚÄÄ      ÚÄ  ÚÄÄ  ÚÄ
     ÚÄÄÄÄÄÄÄÄÄ       ÚÄÄ    ÚÄ   Ú   ÚÄ         Ja ljublju ASSEMBLY
     ÚÄÄ    ÚÄÄ   ÚÄ    ÚÄ   ÚÄ       ÚÄ            VIII.rész
     ÚÄÄ    ÚÄÄ     ÚÄÄÄÄ    ÚÄ       ÚÄ

 Lássunk neki az osztásnak és társainak. A következő utasításoknál NEM lehet közvetlen értékeket használni. Csak regisztert, vagy memóriatartalmat.

MUL utasítás (unsigned MULtiplication):


     Használat:  MUL forrás

     Ha a forrás byte, akkor az AX=AL*forrás műveletet végzi el. Ha a forrás szó, akkor az AX*forrás műveletet végzi el. Ekkor az eredmény DX:AX-ben adja vissza, vagyis az eredmény nagyobb helyiértékű szavát DX-ben, az alacsonyabbat AX-ben adja meg. CF és OF akkor lesz 1, ha byte forrás estén AH-ban, szó forrás estén pedig DX-ben van legalább egy 1 értékű bit.

     Példa:
    MOV AL,56h           ; AL-ben az egyik tényező, a másik 45h, ez most
       MOV CL,45h            ; CL-ben van ,de lehet máshol is, 45h byte
       MUL CL                  ; ezért az eredmény AX-ben képződik és 172eh lesz

       MOV AX,3476h         ; AX-ben az egyik tényező, a másik szó (1256h)
       MOV CX,1256h         ; ezért eredmény DX:AX-ben lesz. A szorzás
       MUL CX                  ; eredménye 03c1eba4h. Ebből DX-be a felső szó
                                   ; vagyis 03c1h kerül, míg AX-be az alsó, 0eba4h

 

IMUL utasítás (Integer MULtiplication):


     Használat:  IMUL forrás

     Ez előjelesen szoroz.
     Ha a forrás byte, akkor AL-lel szorozza és az előjeles eredmény AX-ben lesz. Ha a forrás szó, akkor AX-szel szorozza és a szintén előjeles eredmény DX:AX-ben lesz a MUL-nál leírt felbontásban.


     CF és OF akkor lesz 1, ha byte forrás esetén AH az AL-nek, vagy szó forrás esetén DX az AX-nek előjeles bővítése.

 

DIV utasítás (unsigned DIVision):

     Használat:  DIV forrás

     Előjel nélküli osztás.
     Ha a forrás byte, akkor AX regisztert elosztja forrással. A hányados AL-be kerül, a maradék pedig AH-ba. Ha a forrás szó, akkor DX:AX regisztert (így együtt 32 bitesek) osztja el forrással. Ekkor a hányados AX-be, a maradék DX-be megy.

     A jelzőbiteket nem bántja.

     Példa:
     MOV AX,3465h    ; az osztandó AX=3465h, az osztó CL=56h
       MOV CL,56h        ; az eredmény AL=9bh, ez a hányados
       DIV CL             ; és AH=53h, ez a maradék

       MOV DX,2345h      ; Az osztandó felső szava DX-ben, alsó szava AX-ben
       MOV AX,8765h      ; mivel duplaszót osztunk, az osztó CX-ben
       MOV CX,6543h      ; az eredmény: a hányados AX=592bh és
       DIV CX             ; a maradék DX=3a24h

     Az osztásnál vigyázni kell, mert ha 0-val osztunk, vagy a hányados nem fér el a neki kiszabott helyre, akkor osztáshiba, INT 00h hajtódik végre, ami gyakorlatilag a program végét jelenti, ugyanis a DOS ilyenkor visszaveszi a vezérlést és kilépteti a programot. Ez ellen vagy saját INT 00h megírásával (ehhez még nem tudtok eleget) vagy odafigyeléssel lehet védekezni. Ha elképzelhető, hogy az osztó helyén 0 van (pl.: memóriatartalommal osztasz), akkor osztás előtt ellenőrizd, hogy nem nulla-e. Ha pedig egy szót kis számmal osztasz, akkor inkább a dupla szavas osztást használd DX-ben 0-val, mert így biztos nem lesz a hányados túl nagy.

 

zzzzIDIV utasítás (Integer DIVision):


     Használat:  IDIV forrás

     Előjeles osztást végez. Egyébként ugyanaz, mint DIV. A maradék előjele megegyezik az osztandó előjelével. Következnek a bitforgató/léptető utasítások. A számláló minden utasításban egy közvetlen byte vagy a CL lehet. A cél mindenhol regiszter vagy memóriatartalom lehet.

 

SAL utasítás (Shift Arithmetic Left):


     Használat:  SAL cél, számláló

     A célt számlálószor balra lépteti, mégpedig úgy, hogy a jobb oldalon 0-t hoz be, a bal oldalon kilépő bitet pedig CF-be írja.

     Példa:
       SAL AL,3        ; legyen AL=11010011b, ezt 3-szor léptetve
                       ; AL=10011000b-t kapunk és CF=0 lesz, mert
                       ; ez lépett ki utoljára a bal oldalon
                                                                                
       SAL AX,CL       ; AX=1111011000111011b és CL=6, ekkor a léptetés után
                       ; AX=1000111011000000b lesz és CF=1, mert az utolsó
                       ; kilépő bit 1 volt

 

SAR utasítás (Shift Arithmetic Right):

     Használat:  SAR cél, számláló

     A célt számlálószor jobbra lépteti úgy, hogy a jobb oldalon kilépő bit CF-be kerül, a legfelső bit pedig ismétlődik. Ez az ismétlődő bit kerül SF-be is.

 

     Példa:
       SAR AL,3        ; AL=10011010b legyen, ekkor AL=11110011b és CF=0 lesz

 

SHL utasítás (SHift logical Left):


     Ugyanaz mint SAL.

 

SHR utasítás (SHift logical Right):


     Használat:  SHR cél, számláló

     A célt számlálószor jobbra lépteti, mint a SAR, de ez a bal oldalon 0-kat hoz be mindig.

 

     Példa:
       SHR AL,2      ; legyen AL=11000011b, ekkor AL=00110000b és CF=1 lesz

 

ROL utasítás (ROtate Left):


     Használat:  ROL cél, számláló

     A célt számlálószor balra forgatja. A forgatás során a cél legmagasabb helyiértékű bitje a legalacsonyabba kerül, a többi bitet pedig eggyel balra lépteti a proci. A legmagasabb helyiértékű bit a CF-be is belekerül.

 

     Példa:
       ROL AL,4       ; legyen AL=11001011b, az utasítás után AL=10111100h
                      ; vagyis helyet cserélt az alsó és a felső 4 bit
                      ; CF pedig 0, mert utoljára egy 0 lépett ki bal oldalon

       ROL BX,CL      ; Legyen CL=6 és BX=110011111000011b, az utasítás után
                      ; BX=111000011110011b és CF=1, mert ez lépett ki
                      ; utoljára a bal oldalon

 

ROR utasítás (ROtate Right):


     Használat:  ROR cél, számláló

     A célt számlálószor jobbra forgatja úgy, hogy a cél legkisebb helyiértékű bitje a legmagasabba kerül, valamint belemásolódik CF-be is. A többi bit jobbra lép.

 

     Példa:
       ROR AL,3       ; AL=11010001b, ekkor AL=00111010b és CF=0 lesz

 

RCL utasítás (Rotate through Carry Left):


     Használat:  RCL cél, számláló

     A célt számlálószor balra forgatja a CF felhasználásával. Úgy kell tekinteni, mintha CF lenne a cél legmagasabb helyiértékű bitje és ezután balra forgatnánk.

 

     Példa:
       RCL AL,2       ; legyen AL=11100101b és CF=0, ekkor AL=10010101b és
                      ; CF=1 lesz

 

RCR utasítás (Rotate through Carry Right):

   
     Használat:  RCR cél, számláló

     A célt számlálószor jobbra forgatja CF segítségével. Itt Łgy kell
     venni, hogy CF a cél legkisebb helyiértékű bitje és így forgatunk.

 

     Példa:
       RCR AL,2       ; legyen AL=11100101b és CF=1, így AL=11111001b és
                      ; CF=0 lesz


     Ezek az utasítások nagyon hasznosak lehetnek, mikor egy számot szorozni vagy osztani kell 2 hatványával. Hogy miért? Mert ha egy számot eggyel balra tolunk, akkor az olyan, mint ha 2-vel szoroztuk volna. Gondolj arra, hogy mi van akkor, ha egy decimális szám végére egy nullát írunk. A szám 10-szeresére nő. Egy bináris szám balra léptetése, ha a jobb oldalon egy 0-t hozunk be, pontosan ugyanazt jelenti mintha egy 0-t a végére írtunk volna, ezért a számrendszer alapjával szorzott értéke lesz. A számrendszer alapja most éppen 2. Jobbra forgatásnál éppen a fordítottja, vagyis 2-vel osztódik. DE!! Negatív számok osztásánál más a hányados képzése, mint IDIV esetén. A hányadost lefele kerekíti a léptetéses osztás, azaz a kapott hányados kisebb lesz, mint a valódi. Pozitív és negatív számokra is igaz, hogy ha többet léptetünk jobbra, akkor a maradékot nem jól kapjuk meg, mert a léptetés után CF mindig csak a legutolsó lépés maradékát (volt-e vagy sem) tárolja. Ezért az ilyen módŁ osztásokat ajánlott lépésenként elvégezni.

     Nézzünk egy példát erre a lefele kerekítésre!
   Léptessük -13-at jobbra háromszor, azaz osszuk el 8-cal. -13 kettes komplemensben ábrázolva 11110011b. Hajtsuk végre a
SAR 11110011b,3 utasítást. Azért a SARt, mert ez megőrzi a szám eredeti előjelét

  I. léptetés:    11111001b       CF=1
        Az eredmény átírva decimálissá -7 és van egy maradék, mert CF=1. Már most látszik a lefele kerekítés (angolul ezt úgy mondják, hogy a "negative infinity", azaz a negatív végtelen felé kerekítenek, így talán érthetőbb, mi az a lefele kerekítés ebben az esetben), mert -13/2 az testvérek között is -6 és maradt -1, míg itt -7 és marad +1.

   II. léptetés:   11111100b       CF=1
        A hányados -4 és CF=1 maradékot jelez. Tehát -13/4 az -4 és marad +1. Ez így nem igazán jó, mert -4*4+1=-15. A baj az, hogy lazán elfelejtettük az előző maradékot. így az igazi maradék 11b azaz +3. Így már helyes az eredmény, de itt is eltér az IDIV-től, ami -3 hányadost és -1 maradékot adna vissza.

   III. léptetés:  11111110b       CF=0
        A hányados -2 és CF=0 nem jelez maradékot. Tehát -13/8=-2 és marad 0? Á, dehogy...! Megint nem figyeltük az előző maradékokat, ezért a tényleges maradék 011b=+3. Kész is vagyunk mert -2*8+3=-13!! Az IDIV bezzeg -1 hányadost és -5 maradékot adna vissza és ez is jó (sőt ez egyezik a suliban tanultakkal mert -13-ban a 8 egyszer van
        meg), mert -1*8-5=-13.

     Összegezve: -13/8 pontos értéke -1 és -2 között van. Lefele (negatív végtelen felé) kerekítve -2-t választom hányadosnak és ehhez kapom meg a maradékot, ami itt +3 lesz. Felfele (azaz 0 felé) kerekítve pedig a -1-et választom eredménynek és ehhez számolok maradékot. Remélem világos!?

     A következő cikkben elmondom a logikai műveleteket és végre visszatérünk a programhoz, ahonnan indultunk, de most már felfegyverkezve mindenféle hasznos tudással

Lucifer of ZeroBit

©2000. Fearless Criminal Force. Minden jog fenntartva!