Last modified: Mon Jun 29 08:35:16 UTC+0200 2026 © A. Tarpai
x86 MUL/IMUL, DIV/IDIV and sign-extension instructions
These instructions were quite something in the era: The 8088 contains its own hardware 8-bit and 16-bit signed and unsigned "multiply" and "divide" instructions. (The Intelligent Machines Journal 79 Apr 18 Price 75 cents)
8086 MUL/IMUL and DIV/IDIV
8086 had 4 instructions:
- unsigned (DIV) and signed (IDIV) integer division of accumulator
- unsigned (MUL) and signed (IMUL) integer multiplication of accumulator
The integer division result is in the form of
Dividend
----------- = Quotient + Remainder*
Divisor
* aka modulus
The result is in register(s) and implicit for both: AX or DX:AX. DX is used as the high-order part of the result (MUL/IMUL) or for Remainder (DIV/IDIV).
8086 DIV/IDIV
With sign-extension helper instructions of dividend before division:
CBW 98 CWD 99
+----+----+ +---------+---------+
|ss<-| AL | |ssssss<--| AX |
+----+----+ +---------+---------+
AX DX AX
Divide Divide
signed/unsigned signed/unsigned
AX by BYTE R/M DX:AX by WORD R/M
into AH:AL into DX:AX
W=0 DIV/IDIV W=1 DIV/IDIV
+----+----+ +---------+---------+
| WORD | AX | DWORD | DX:AX
+----+----+ +---------+---------+
|BYTE| R/M | WORD | R/M
÷ +----+ ÷ +---------+
___________________ ________________________________
+----+----+ +---------+---------+
| AH | AL | AX | DX | AX | DX:AX
+----+----+ +---------+---------+
REM QUOT REMAINDER QUOTIENT
Examples:
DIV BL DIV BX
IDIV BYTE [BX+4] IDIV WORD [BX+4]
8086 Sign-extension instructions before IDIV
8086 had also sign-extension helper instruction before IDIV division. 3 clk. One opcode:
+---------------+
|1 0 0 1 1 0 0 w|
+---------------+
W=0 98 CBW - Convert Byte to Word (AX <-- AL)
W=1 99 CWD - Convert Word to Double Word (DX:AX <-- AX)
Sign-extension of dividend before IDIV
+----+----+ +---------+---------+
|ss<-| AL | |ssssss<--| AX |
+----+----+ +---------+---------+
AX DX AX
CBW CWD
Convert Convert
Byte to Word Word to Doubleword
These can be handy in many other situations. Eg. CWD, as a one-byte instruction, can be used to zero out DX – when AX stores a positive value. Or move zero to AH using CBW.
Signs of result in signed integer division (IDIV)
Dividend
----------- = Quotient + Remainder
Divisor
Quotient: Signed division mathematically
Remainder: Signed Modulus, i.e. SIGN OF DIVIDEND
Sign of quotient and remainder are such, so we can get dividend back by multiplication:
The rule is when
A ÷ b = q + r
then
A = b × q + r
-A 0 A
<-----------------------------+----------------------------->
|
|---|-----|-----|-----|-----|-----|-----|-----|-----|---|
-r b b b b | b b b b +r
A ÷ b = q + r
____________________________
23 ÷ 5 = 4 + 3
23 ÷ -5 = -4 + 3
-23 ÷ 5 = -4 + -3
-23 ÷ -5 = 4 + -3
A = b × q + r
____________________________
23 = 5 × 4 + 3
23 = -5 × -4 + 3
-23 = 5 × -4 + -3
-23 = -5 × 4 + -3
8086-style DIV/IDIV overflow: Divide error
After DIV/IDIV all flags are undefined. DIV/IDIV raises exception 0 Divide error, when something went wrong:
- Dividend is zero
- Quotient is too large
Unsigned DIV test for too large quotient:
255x10 255x10+5 256x10 ------ = 255 + 0 -------- = 255 + 5 ------ = would be 256! + 0 10 10 10 MOV AX, 255*10 MOV AX, 255*10+5 MOV AX, 256*10 MOV BL, 10 MOV BL, 10 MOV BL, 10 DIV BL DIV BL DIV BL AX= 00 FF AX= 05 FF #Divide error
Using IDIV all these would be #Divide error (FF = -1).
Signed IDIV test for too large quotient:
For IDIV, the signed-result should fit into Quotient register:
127x10 127x10+5 128x10 ------ = 127 + 0 -------- = 127 + 5 ------ = would be 128! + 0 10 10 10 MOV AX, 127*10 MOV AX, 127*10+5 MOV AX, 128*10 MOV BL, 10 MOV BL, 10 MOV BL, 10 IDIV BL IDIV BL IDIV BL AX= 00 7F AX= 05 7F #Divide error
As APPENDIX C 8086/8088 COMPATIBILITY CONSIDERATIONS in 80286 AND 80287 PROGRAMMER'S REFERENCE MANUAL 1987 states:
"Do not Rely on IDIV Exceptions for Quotients of 80H or 8000H.
The iAPX 286 can generate the largest negative number as a quotient for IDIV instructions.
The iAPX 86 will instead cause exception 0."
Indeed, tested on real hardware:
127x10 127x10+5 128x10+5 ------ = -127 + 0 -------- = -127 + 5 -------- = -128 + 5 -10 -10 -10 MOV AX, 127*10 MOV AX, 127*10+5 MOV AX, 128*10+5 MOV BL, -10 MOV BL, -10 MOV BL, -10 IDIV BL IDIV BL IDIV BL AX= 00 81 AX= 05 81 AX= 05 80 81 = -127 81 = -127 80 = -128 OK!
8086 MUL/IMUL
The "product twice the size of the input operand" and result "always fit":
Multiply Multiply
signed/unsigned signed/unsigned
AL by BYTE R/M AX by WORD R/M
into AX into DX:AX
W=0 MUL/IMUL W=1 MUL/IMUL
+----+ +---------+
|BYTE| AL | WORD | AX
+----+ +---------+
|BYTE| R/M | WORD | R/M
× +----+ × +---------+
_________________ ______________________________
+---------+ +---------+---------+
| WORD | AX | DWORD | DX:AX
+---------+ +---------+---------+
Examples:
MUL BL MUL BX
IMUL BYTE [BX+4] IMUL WORD [BX+4]
8086-style MUL/IMUL overflow: OF=1 CF=1
Following MUL/IMUL flags are undefined – except OF/CF. These are set together to signal some kind of overflow, but what?
As Mnemonics © Intel, 1978 in iAPX 86, 88 USER'S MANUAL 1981 states..
For unsigned MUL: "If the upper half of the result (AH for byte source, DX for word source) is nonzero, CF and OF are set; otherwise they are cleared. When CF and OF are set, they indicate that AH or DX contains significant digits of the result. The content of AF, PF, SF and ZF is undefined following execution of MUL."
For signed IMUL: "If the upper half of the result (AH for byte source, DX for word source) is not the sign extension of the lower half of the result, CF and OF are set; otherwise they are cleared. When CF and OF are set, they indicate that AH or DX contains significant digits of the result. The content of AF, PF, SF and ZF is undefined following execution of IMUL."
The key here is "indicate that AH or DX contains significant digits". Consider 2 × 64 on 8-bits for IMUL and MUL:
IMUL overflow: MUL overflow:
01000000 AL: 64 01000000 10000000
00000010 BL: 2 00000010 00000010
×___________________________ ×_________________ ×__________________
00000000 10000000 AX: 128 00000000 10000000 00000001 00000000
^ ^ ^
| | |
OF=1 CF=1 OF=0 CF=0 OF=1 CF=1
MOV BL, 2 MOV BL, 2 MOV BL, 2
MOV AL, 64 MOV AL, 64 MOV AL, 128
IMUL BL MUL BL MUL BL
2 x 64 = 128 2 x 64 = 128 2 x 128 = 256
Signed NO Unsigned Unsigned
overflow overflow overflow
on LO on LO on LO
128 = -128: two positive 128 fits 256 does not fit
terms on LO yield into 8-bits into 8-bits
negative product
OF/CF ALU detection:
MUL: HI non-zero
IMUL: HI is not the sign extension of LO
The "result always fit" is true, – so in this case overflow-detection is only a warning. OF=1 CF=1 signals the product does not fit into the original operand size of 8/16-bits.
Note that this OF=1 CF=1 is consistently defined for the other signed muls, where the product is the same size.
186/286 IMUL by immediate
186/286 added one new opcode for multiplication by immediate constant: IMUL REG = R/M × IMMED.
+---------------+ +---+-----+-----+ +- - - - -+ +-------------+ +-------------+
|0 1 1 0 1 0 s 1| |MOD REG R/M | | DISP | | DATA | | DATA if s=0 | 286 IMUL opcode
+---------------+ +---+-----+-----+ +- - - - -+ +-------------+ +-------------+
69/6B
s=0: word immediate follows
s=1: byte immediate follows and sign-extension to word
The multiplication is signed with only WORD size operands making WORD size product.
Operation:
REG = R/M x IMMED
IMUL 6B IMUL 69
s=1 s=0
+---------+ +---------+
| WORD | R/M | WORD | R/M
+---------+ +---------+
+----+----+ +---------+
|ss<-| | IMM8 | WORD | IMM16
+----+----+ +---------+
_________________ _________________
+---------+ +---------+
| WORD | REG | WORD | REG
+---------+ +---------+
Examples:
6B FB FF imul di, bx, -1
6B 3C FF imul di, [si], -1
69 FB 0210 imul di, bx, 0x1002
69 3C 0210 imul di, [si], 0x1002
Assemblers also allow this short form:
imul dx, 5 ; = imul dx, dx, 5 (r/m and dest reg is the same)
IMUL by immediate overflow: OF=1 CF=1
Same as 8086. OF=1 CF=1 signals the signed product does not fit into 16-bits.
Although signed multiplication, works for unsigned values as well (just don't trust overflow: OF=1 CF=1)
MOV BX, 0x4000
IMUL AX, BX, 2
AX = 8000
^
|
OF=1 CF=1
correct 16-bit
unsigned result
386 DIV/IDIV
There are no new instructions for integer division since the 8086. The only extension is for 32-bit: when W=1 and 32-bit operand-size, 386 divides a 64-bit value in EDX:EAX by 32-bit R/M.
The corresponding sign-extension helper instruction is also extended (and given a new mnemonic):
operand-size = 16 operand-size = 32
D=0 or D=1 and 66h D=1 or D=0 and 66h
CBW 98 CWD 99 CDQ 99
+----+----+ +---------+---------+ +-------------------+-------------------+
|ss<-| AL | |ssssss<--| AX | |ssssssssssssssss<--| EAX |
+----+----+ +---------+---------+ +-------------------+-------------------+
AX DX AX EDX EAX
W=0 DIV/IDIV W=1 DIV/IDIV W=1 DIV/IDIV
+---------+ +---------+---------+ +-------------------+-------------------+
| WORD | AX | DWORD | DX:AX | QWORD | EDX:EAX
+----+----+ +---------+---------+ +-------------------+-------------------+
|BYTE| R/M | WORD | R/M | DWORD | R/M
÷ +----+ +---------+ +-------------------+
_________________ ____________________________ ___________________________________________________
+----+----+ +---------+---------+ +-------------------+-------------------+
| AH | AL | AX | DX | AX | DX:AX | EDX | EAX | EDX:EAX
+----+----+ +---------+---------+ +-------------------+-------------------+
REM QUOT REMAINDER QUOTIENT REMAINDER QUOTIENT
Examples:
div bl div bx div ebx
idiv byte [ebp+4] idiv word [ebp+4] idiv dword [ebp+4]
Divide error:
- R/M IS NULL
- TEMP = SIGNED DIV
- If TEMP a positive result is greater than 7FH/7FFF/7FFFFFFFH or a negative result is less than 80H/8000H/80000000H
386 MUL/IMUL
8086 style MUL/IMUL: one-operand
Same 8086 instruction. The extension is for 32-bit: when W=1 and D=1 (or 32-bit operand-size), 386 multiplies two 32-bit values and the result is 64-bit value in EDX:EAX.
operand-size = 16 operand-size = 32
D=0 or D=1 and 66h D=1 or D=0 and 66h
8086/386 8086/386 16-bit 386 32-bit
MUL F6 /4 MUL F7 /4 MUL F7 /4
IMUL F6 /5 IMUL F7 /5 IMUL F7 /5
W=0 W=1 W=1
16-bit 32-bit
+----+ +---------+ +-------------------+
|BYTE| AL | WORD | AX | DWORD | EAX
+----+ +---------+ +-------------------+
|BYTE| R/M | WORD | R/M | DWORD | R/M
× +----+ +---------+ +-------------------+
_________________ ______________________________ ____________________________________________________
+---------+ +---------+---------+ +-------------------+-------------------+
| WORD | AX | DWORD | DX:AX | QWORD | EDX:EAX
+---------+ +---------+---------+ +-------------------+-------------------+
Examples:
mul bl mul bx mul ebx
imul byte [ebp+4] imul word [ebp+4] imul dword [ebp+4]
386 Signed IMUL immediate, the three-operand type
When operand-size = 16, it works the same way as the 186/286-style IMUL immediate.
Extended to 32-bit: when W=1 and D=1 (or 32-bit operand-size), 386 multiplies two 32-bit values with possible sign-extension of byte to dword. The result is 32-bit value in REG.
386 IMUL immediate:
REG = R/M x IMMED operand-size = 32 operand-size = 16 D=1 or D=0 and 66h D=0 or D=1 and 66h IMUL 6B IMUL 69 IMUL 6B IMUL 69 s=1 s=0 s=1 s=0 +-------------------+ +-------------------+ +---------+ +---------+ | DWORD | R/M | DWORD | R/M | WORD | R/M | WORD | R/M +--------------+----+ +-------------------+ +----+----+ +---------+ |ssssssssssss<-| | IMM8 | DWORD | IMM32 |ss<-| | IMM8 | WORD | IMM16 × +--------------+----+ +-------------------+ +----+----+ +---------+ __________________________________________________________ _______________________________________ +-------------------+ +-------------------+ +---------+ +---------+ | DWORD | REG | DWORD | REG | WORD | REG | WORD | REG +--------------+----+ +-------------------+ +---------+ +---------+ Examples: 6B FB FF imul edi, ebx, -1 6B 3E FF imul edi, dword [esi], -1 69 FB 02100000 imul edi, ebx, 0x1002 69 3E 02100000 imul edi, dword [esi], 0x1002 also can be used for: imul dx, 5 (r/m and dest reg is the same)
386 Two-operand signed IMUL
386 added a new IMUL instruction: two-operand GP REG type
+-------------+ +-------------+ +-------------+ +- - - - -+ | 0F | | AF | | MOD REG R/M | | DISP | 386 IMUL opcode +-------------+ +-------------+ +-------------+ +- - - - -+
Operation:
REG = REG x R/M operand-size = 32 operand-size = 16 D=1 or D=0 and 66h D=0 or D=1 and 66h +-------------------+ +---------+ | DWORD | REG | WORD | REG +-------------------+ +---------+ | DWORD | R/M | WORD | R/M × +-------------------+ +---------+ _____________________________ __________________ +-------------------+ +---------+ | DWORD | REG | WORD | REG +-------------------+ +---------+ Examples: 0F AF FB imul edi, ebx 0F AF 3C imul edi, [esi] 66 0F AF C2 imul ax, dx
Notes.
1. One-op (8086) MUL/IMUL will always fit (result is double size).
If the high-order bits of the product are 0, the CF and OF flags are cleared; otherwise, the flags are set.
2. Two/three-op IMUL product is truncated.
The CF and OF flags are set when the signed integer value of the intermediate product differs from the sign extended operand-size-truncated product, otherwise the CF and OF flags are cleared.