Assembler 8086 divide 32 bit number in 16 bit number

15,381

Solution 1

The method below is similar to long hand division on pencil and paper, dividing a 2 digit numerator by a single digit divisor. For example 99/4:

    2 4    (quotient)
  -----
4 | 9 9
    8
    -
    1 9
    1 6
      -
      3    (remainder)

Start off with dx = 0 and ax = high order of numerator. After the first div instruction, the remainder in dx is what's left of the high order of the numerator for the second divide. This method could be enhanced to handle a numerator and quotient of any size, as long as the divisor is a 16 bit value.

num     dd      10000000h
dvsr    dw      2000h 
quot    dd      ?
rmdr    dw      ?
;       ...
        mov     cx,dvsr                ;cx = dvsr
        xor     dx,dx                  ;dx = 0
        mov     ax,word ptr [num+2]    ;ax = high order numerator
        div     cx                     ;dx = rem, ax = high order quotient
        mov     word ptr [quot+2],ax   ;store high order quotient
        mov     ax,word ptr [num]      ;ax = low  order numerator
        div     cx                     ;dx = rem, ax = low  order quotient
        mov     word ptr [quot],ax     ;store low  order quotient
        mov     word ptr [rmdr],dx     ;store remainder

Solution 2

With the 16-bit div instruction, you need to put the upper 16 bits of the dividend into dx and the lower 16 bits in ax. You've done the latter for the first div, but you set dx to 0, so you end up computing 0h/2000h, which is 0.

Instead, you want something like:

mov bx, offset num
mov ax, [bx]
mov dx, [bx+2]
mov cx, word ptr divisor
div cx

Of course, this only works as long as the result fits in 16 bits—if it does not, the div instruction will raise a #DE exception.

Solution 3

The code written in answer 1 is the only exact. I written similar code, that divide D1 by D2:

Function Div32Bit(D1:LongInt;D2:Word):LongInt; Assembler;

Asm
 LEA   SI,D1
 Mov   CX,[SS:SI]
 Mov   AX,[SS:SI+2]
{AX:CX contains number to divide by}
 Mov   BX,D2
{BX contains number that divide}
 XOr   DX,DX
 Div   BX
 XChg  AX,CX
 Div   BX
{CX:AX contains the result of division}
{DX contains the rest of division}
 Mov   DX,CX
{DX:AX contains the result of division and is the function's result}
End;

But this method isn't valid to divide two signed number. To divide two signed number:

Function IDiv32Bit(D1:LongInt;D2:Integer):LongInt; Assembler;

Asm
 LEA   SI,D1
 Mov   CX,[SS:SI]
 Mov   AX,[SS:SI+2]
{AX:CX contains number to divide by}
 Cmp   AX,32768
 CmC
 SbB   SI,SI
 XOr   CX,SI
 XOr   AX,SI
 Sub   CX,SI
 SbB   AX,SI
{AX:CX contains the absolute value of the number to divide by}
 Mov   BX,D2
{BX contains number that divide}
 Cmp   BX,32768
 CmC
 SbB   DX,DX
 XOr   BX,DX
 Sub   BX,DX
{BX contains the absolute value of the number that divide}
 XOr   SI,DX
{SI contains the sign of division}
 XOr   DX,DX
 Div   BX
 XChg  AX,CX
 Div   BX
{CX:AX contains the absolute value of the result of division}
{DX contains the absolute value of the rest of division}
 XOr   AX,SI
 XOr   CX,SI
 Sub   AX,SI
 SbB   CX,SI
{CX:AX contains the result of division}
 Mov   DX,CX
{DX:AX contains the result of division and is the function's result}
End;
Share:
15,381
benz
Author by

benz

Updated on June 05, 2022

Comments

  • benz
    benz almost 2 years

    I try to divide 32 bit number in 16 bit number. For example 10000000h divide by 2000h.According the desgin I try to do I divide 4 right digits with the divisor and then the 4 left digit by the divisor.

    This is my code :

    .DATA 
    num dd 10000000h
    divisor dw 2000h 
    
    result dd ? 
    remainder dw ? 
    
    .CODE
    main:
    
    mov ax,@DATA    
    mov ds,ax 
    
    xor dx,dx
    mov cx ,word ptr divisor
    mov bx,offset num
    mov ax,[bx]
    div cx
    
    mov bx,offset result 
    mov [bx],ax 
    mov bx,offset num
    mov ax,[bx+2]
    
    
    mov ax,[bx+2]
    div cx 
    mov bx,offset result 
    mov [bx+2],ax 
    

    I got zero in variable result. Not sure if the problem with the design of the divide or just a little mistake.

  • benz
    benz over 7 years
    Sorry I was not clear I want to get the remainder and the result can be bigger than 16 bit.
  • Cody Gray
    Cody Gray over 7 years
    Without an explanation of what the code does and how it does it, code dumps are not useful answers.
  • rcgldr
    rcgldr over 7 years
    @benz - the remainder is < divisor, so the remainder is limited to 16 bits if the divisor is limited to 16 bits. The quotient can be more than 16 bits (take a look at my answer for how to implement this).
  • rcgldr
    rcgldr over 7 years
    @CodyGray - forum got stuck while I was trying to include the comments. Fixed now.
  • Peter Cordes
    Peter Cordes over 6 years
    If the result doesn't fit, div raises a #DE execption. The manual for div says: "CF, OF, SF, ZF, AF, and PF flags are undefined" after div (whether it raises an exception or not). There is no way to disable the exception and get a wrapping 32b/16b => 16b quotient & remainder. (This is exactly the same behaviour as for divisor = 0.)