Áttekintés
A szorzás esetében megkülönböztetjük az előjeles, és előjel nélküli számok szorzását. Ezen két műveletre külön-külön utasítás is van a processzorban.
A szorzás esetében megkülönböztetjük az előjeles, és előjel nélküli számok szorzását. Ezen két műveletre külön-külön utasítás is van a processzorban.
32 bites módban az egész értékek összeszorzása elvégezhető, mint egy 32, 16 vagy 8 bites művelet.
MUL: 32 bites módban a MUL (unsigned MULtiply - előjelnélküli szorzás) utasításnak három verziója van: az első verzió egy 8 bites operandust szoroz össze az AL regiszterrel. A második verzió egy 16 bites operandust szoroz össze az AX regiszterrel. A harmadik verzió egy 32 bites operandust szoroz össze az EAX regiszterrel. A szorzó és a szorzandó méretének mindig meg kell egyeznie és a szorzat mindig ennek a méretnek a kétszerese. A három formátum elfogad regisztert és memória címet is operandusként, viszont sosem közvetlen operandust (konstanst):
MUL reg/mem8
MUL reg/mem16
MUL reg/mem32
A MUL utasításnak tehát egy operandusa van, ami a szorzó. Az alábbi táblázat mutatja be az alapértelmezett szorzandót és a szorzatot, attól függően, hogy mekkora mérető szorzót adtunk meg:
Szorzandó | Szorzó | Szorzat |
AL | reg/mem8 | AX |
AX | reg/mem16 | DX:AX |
EAX | reg/mem32 | EDX:EAX |
A táblázatban leírtak értelmezése: ha az AL regiszter tartalmát megszorozzuk egy 8 bites operandussal, akkor az eredmény az AX regiszterbe kerül. Az AX megszorozva egy 16 bites operandussal, az eredmény a DX és AX regiszterekbe kerül, ami azt jelenti, hogy a szorzat felső 16 bitje a DX regiszterbe, míg az alsó 16 bit az AX regiszterbe kerül tárolásra. Ugyanezen az elven működik az EAX regiszter megszorzása egy 32 bites operandussal, mely során az eredmény az EDX és EAX regiszterekbe kerül. Mivel a cél operandus mérete kétszer akkora, mint a szorzandó és a szorzó mérete, ezért túlcsordulás nem fordulhat elő. A Carry flag 1 értéke jelzi, ha történt átvitel 8 bites szorzás esetén az AH-ba, 16 bites szorzás esetén az DX-be, illetve 32 bites szorzás esetén az EDX-be.
MOV AL, 150d ; AL = 96h
MOV BL, 10d ; BL = 0Ah
MUL BL ; AX = AL * BL = 96h * 0Ah = 05DCh
MOV AX, 8000d ; AX = 1F40h
MOV BX, 5000d ; BX = 1388h
MUL BX ; DX:AX = AX * BX = 1F40h * 1388h = 0262 5A00h
MOV EAX, 1000000d ; EAX = 000F 4240h
MOV EBX, 5000000d ; EBX = 004C 4B40h
MUL EBX ; EDX:EAX = EAX * EBX = 0000 048C 2739 5000h
MUL WORD PTR [SI] ; DX:AX = AX * (SI helyen a memóriában
; található szó)
; Kell a WORD PTR, mert a fordító nem tudja, hány bites
; művelet! Természetesen a WORD helyett használhatunk BYTE,
; illetve DWORD típust is
IMUL: Előjeles szorzás. Működése hasonló a MUL utasításhoz, azzal a különbséggel, hogy az IMUL megőrzi a szorzat előjelét. Az x86-os utasítás halmaz három különböző formátumát támogatja az IMUL utasításnak: egy-, kettő-, illetve három operandusos verzió.
Az egy operandusú verzió használata megegyezik a MUL utasításéval:
Példa:
MOV AL, -2d ; AL = 0FEh
MOV CL, 3d ; CL = 03h
IMUL CL ; AX = 0FFFAh
IMUL két operandussal (80286-tól): az első operandus egy regiszter (16 vagy 32 bites), a második operandus lehet regiszter, memóriahivatkozás vagy közvetlen érték (konstans), az elsővel egyező bitszélességű. Az eredmény az első operandusban keletkezik. Nagyon fontos, hogy itt nincs bitszélesség kiterjesztés, tehát nincs átvitel 16 bites szorzás esetén DX-be, illetve 32 bites szorzás esetén EDX-be. A C és O flag mutatják, ha van elveszett átvitel.
Példa:
MOV AX, -2d ; AX = 0FFFEh
MOV BX, 5d ; BX = 5h
IMUL AX, BX ; AX = AX * BX = 0FFF6h
IMUL AX, 3h ; AX = AX * 3h = 0FFE2h
ADAT1 DD 912, 920, 928, 936, 944 ; adatszegmens tartalma
MOV EDX, offset ADAT1
IMUL AX, [EDX] ; AX = AX * [EDX] = 9520h
; (nincs átvitel, elvesszük az előjelet!)
; átvitellel, helyesen FFFF 9520h lenne
IMUL három operandussal (80386-tól): az első operandus egy regiszter (16 vagy 32 bites), a második operandus lehet regiszter vagy memóriahivatkozás, a harmadik operandus egy közvetlen érték (konstans). A második és a harmadik operandus kerül összeszorzásra és az eredmény az első operandusban keletkezik. A két operandusos verzióhoz hasonlóan itt sincs bitszélesség kiterjesztés, viszont az O és C flag jelzik az elveszett átvitelt.
Példa:
MOV BX, 3d ; BX = 3h
IMUL AX, BX, 6d ; AX = BX * 6h = 3h * 6h = 0Ch