HALICERY

free-time coding, hardware dev, articles

Top
Home 8042 Blogs About
Home IntelEssential 16/32-bit Instructions DIVMUL

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:

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:

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:

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.