jack.math
jack.math

Reputation: 77

overflow in division in assembly(8086)

I don't know what is the exact definition of overflow in the division. can you explain it first and then instruct it by the below example?

for example my book has written that this piece of code results to overflow. I don't know why??

mov dx,0087h
mov ax,6002h
mov bx,10h
div bx

but this piece of code is correct and doesn't result to overflow:

mov dx,0087h
mov ax,6000h
mov bx,100h
div bx

so why the first result into overflow but second not what is the difference?

Upvotes: 1

Views: 5607

Answers (2)

vitsoft
vitsoft

Reputation: 5775

The dividend in registers DX and AX is in fact a 32bit number, in your example it is 00876002h.
It will be divided by the divisor BX and the result (quotient) should fit in register AX. The remainder after unsigned division will be put into register DX.

When you try to divide 00876002h by the contents of BX (10h), the result is 87600h and remainder is 2. Now you should see why it triggers an error: quotient 87600h is too big to fit into 16bit register AX.

Divide overflow (alias division by zero) happens when the divisor is too small. Your example will overflow when BX is below DX.

Upvotes: 8

Peter Cordes
Peter Cordes

Reputation: 364210

0x00876002 / 0x10 = 0x87600, so the quotient of DX:AX / BX doesn't fit in AX, thus you get a #DE exception. Intel's instruction reference manual (x86 SDM vol. 2) has detailed descriptions of every instruction, and the entry for div explains this. There's an HTML extract of the div entry here. See the x86 tag wiki for links to Intel's docs, and other stuff.

Dividing by 10h is a right shift by 1 hex digit, but the high-half of the input, DX, has 2 significant hex digits.

x86 Assembly: Division Floating Point Exception dividing by 11 is mostly a duplicate of this, and @rcgldr's answer has code for extended-precision division (e.g. 32-bit / 16-bit producing a 32-bit quotient and 16-bit remainder) using div that works for an arbitrary 16-bit divisor.


In your specific case you're dividing by a power of 2. This is very inefficient with div.

For these power-of-2 divisions, you should use

; input in DX:AX

shrd ax, dx, 4      ; right shift AX, shifting in bits from DX
shr  dx, 4          ; separately right shift DX

; DX:AX = 0008:7600 = 0x87600 = 32-bit quotient

If you want the remainder, it's the low 4 bits of the original AX, which you should get with mov cl, al / and cl, 0Fh.

SHRD only modifies its destination, not the source, so you need that 2nd shr on DX. This makes sense for larger extended-precision shifts: you want to use a chain of SHRD instructions to shift bits into the top of each element in turn, and don't want to shift in zeros.

Or if you can't use 386 instructions like shrd, you can emulate SHRD with a left and right shift and an OR. Original 8086 doesn't have immediate-count shifts either, so you'd need a count in CL.

; 8086-compatible version of 32-bit division by 10h, i.e. right shift by 4.
; input in DX:AX

mov  bx, dx
mov  cl, 16-4
shl  bx, cl       ; bx = the bits shifted across the 16-bit boundary into low half

mov  cl, 4
shr  ax, cl
shr  dx, cl       ; discards the bits shifted out

or   ax, bx       ; replace the 4 zeros at the top of AX with the bits from DX

; quotient in DX:AX

Or if you know that the result won't overflow, like in the divide-by 100h (right shift by 8) case, you can use just one SHRD.

Upvotes: 3

Related Questions