Reputation: 2599
I am trying write a simple Assembly program that divide 1000 by 5, but my program freezes the system.
The program is as follows,
include pcmac.inc
.model Small
.586
.stack 100h
.data
const db 5
Main PROC
_Begin
mov AX, 1000
idiv const // Problem line
_Exit 0
Main ENDP
End Main
The problem goes away if I use unsigned division div
instead of signed division idiv
.
Can anyone explain why?
The only condition I know for division is the dividend has to be double the size of divisor. Is there something else I am missing?
Upvotes: 1
Views: 2504
Reputation: 58507
const
is a byte. When you do IDIV byte_divisor
the quotient will be placed in AL
, and has a range of -128 to 127. 1000 / 5 is 200, which isn't within the allowed range. If you use DIV
, the range of the quotient is 0 to 255, which is why your example works in that case.
If you want to IDIV
1000 by 5 you should be using a 16-bit divisor instead. But you'll need to keep in mind that when using IDIV r/m16
, what you're actually is dividing is the 32-bit doubleword made up of DX
and AX
(DX
holding the most significant bits, and AX
the least significant bits).
From Intel's manual:
IDIV r/m16 Signed divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder.
IF OperandSize = 16 (* Doubleword/word operation *)
THEN
temp ← DX:AX / SRC; (* Signed division *)
IF (temp > 7FFFH) or (temp < 8000H)
(* If a positive result is greater than 7FFFH
or a negative result is less than 8000H *)
THEN
#DE; (* Divide error *)
ELSE
AX ← temp;
DX ← DX:AX SignedModulus SRC;
So before IDIV
you should create a signed doubleword in DX:AX
from the value in AX
. There's an instruction named CWD
that does exactly that:
The
CWD
instruction copies the sign (bit 15) of the value in theAX
register into every bit position in theDX
register.
I.e.:
.data
const dw 5 ; now a word
.code
mov ax,1000
cwd ; sign-extend ax into dx
idiv const
; quotient is in ax, remainder in dx
Upvotes: 5