Áttekintés
Mint a szorzásnak osztásnak is megkülönböztetjük az előjel nélküli és előjeles változatát.
Mint a szorzásnak osztásnak is megkülönböztetjük az előjel nélküli és előjeles változatát.
DIV: A DIV (előjelnélküli osztás) utasítás használható 8, 16 és 32 bites verzióban is. Egyetlen operandusa van, az osztó, ami lehet egy regiszter vagy egy memória cím. A szintaxisa:
DIV reg/mem8
DIV reg/mem16
DIV reg/mem32
A következő táblázat mutatja be a kapcsolatot az osztandó, az osztó, a hányados és a maradék között:
Osztandó | Osztó (operandus) | Hányados | Maradék |
AX | reg/mem8 | AL | AH |
DX:AX | reg/mem16 | AX | DX |
EDX:EAX | reg/mem32 | EAX | EDX |
A táblázatban leírtak értelmezése: Ha 8 bites az operandus, akkor az eredmény úgy áll elő, hogy az AL tartalmazza az AX/op hányadosát, a AH-ba pedig az AX/op maradéka kerül. Ha az operandus 16 bites, akkor AX-be a (DX:AX)/op hányadosa, DX-be pedig a (DX:AX)/op maradéka kerül. Ha az operandus 32 bites, akkor EAX-be az (EDX:EAX)/op hányadosa, míg az EDX-be az (EDX:EAX)/op maradéka kerül.
Példa:
A következő 8 bites előjelnélküli osztás esetén (83h/2h), a hányados értéke 41h, a maradék pedig 1h:
MOV AX, 0083h ; AX = 0083h (osztandó)
MOV BL, 2h ; BL = 2h (osztó)
DIV BL ; AL = 41h (hányados), AH = 01h (maradék)
A következő 16 bites előjelnélküli osztás esetén (8003h/100h), a hányados értéke 80h, a maradék pedig 3h. DX tartalmazza a felső 16 bitjét az osztandónak, ezért mindenképp ki kell nullázni még a DIV utasítás végrehajtása előtt:
MOV DX, 0 ; DX = 0000, osztandó nullázása (felső 16 bit)
MOV AX, 8003h ; AX = 8003h, osztandó (alsó 16 bit)
MOV CX, 100h ; CX = 100h, osztó
DIV CX ; AX = 0080h (hányados), DX = 0003h (maradék)
A következő 32 bites előjelnélküli osztás memória operandust használ, mint osztó:
.data
osztando QWORD 0000000800300020h ; 64 bites érték
oszto DWORD 00000100h
.code
MOV EDX, DWORD PRT osztando + 4 ; felső 32 bit
MOV EAX, DWORD PTR osztando ; alsó 32 bit
DIV oszto ; EAX = 08003000h(hányados),EDX = 00000020h(maradék)
IDIV: Az előjeles osztás közel megegyezik az előjelnélkülivel, egy fontos különbséggel: az osztandó előjel kiterjesztett kell, hogy legyen még az osztás elvégzése előtt. Az előjel kiterjesztés azt jelenti, hogy átmásoljuk a szám legfelső bitjét az összes felsőbb bit helyére az adott változóban vagy regiszterben. Ahhoz, hogy bemutassuk ennek a fontosságát, próbáljuk ki mi történik, ha kihagyjuk ezt a lépést. A következő kódban a MOV utasítással hozzá rendeljük a -101 értéket az AX regiszterhez, ami az EAX regiszter alsó 16 bitje:
.data
szoValtozo SWORD -101
.code
MOV AX, szoValtozo ; AX = FF9Bh
MOV BX, 2 ; BX = 2 (osztó)
IDIV BX ; DX:AX/BX (előjeles művelet)
Igaz, hogy az AX regiszterben benne van az FF9Bh, viszont az osztáskor a DX értékét nem állítottuk be, így az bármi lehet. Így teljesen kérdéses, hogy milyen eredményt kapunk, de az biztos, hogy nem helyeset. Tehát az út a helyes megoldáshoz, hogy használjuk a CWD utasítást, ami az AX regisztert előjelhelyesen kiterjeszti DX:AX-re még az osztás végrehajtása előtt:
.data
szoValtozo SWORD -101 ; 009Bh
.code
MOV AX, szoValtozo ; AX = FF9Bh
CWD ; DX:AX = FFFF FF9Bh
MOV BX, 2 ; EBX = 2 (osztó)
IDIV BX ; AX = DX:AX/BX = FFFFFF9B/2 =FFCD
A már tárgyalt MOVSX parancs használata hasznos lehet ilyen műveletek esetén.
MOVSX EAX, AX ; EAX = FFFF FF9Bh
; AX előjelhelyes kiterjesztése EAX-re
Osztásnál előfordulhat, hogy a hányados nem fér el az adott regiszterben, amiben tárolásra kerülne, ilyenkor azonnal abortál a program. Célszerű megelőző ellenőrzéseket végezni: