| < Day Day Up > |
The Intel 80×86 instructions for division parallel those of the single-operand multiplication instructions;
idiv
is for division of signed 2's complement integers and
div
is for division of unsigned integers. Recall that the single-operand multiplication instructions start with a
The division instructions have formats
idiv source
and
div source
The source operand identifies the divisor. The divisor can be in a register or memory, but not immediate. Both
div
and
idiv
use an implicit dividend (the operand you are dividing into). If
source
is byte length, then the double-length dividend is word
The table in Fig. 4.15 summarizes the locations of the dividend, divisor, quotient, and remainder for 80×86 division instructions.
|
|
|
source (divisor) size |
other operand (dividend) |
quotient |
remainder |
|---|---|---|---|
|
byte |
AX |
AL |
AH |
|
word |
DX:AX |
AX |
DX |
|
doubleword |
EDX:EAX |
EAX |
EDX |
|
|
The source operand (the divisor) is not changed by a division instruction. After a word in AX is divided by a byte length divisor, the quotient will be in the AL register half and the remainder will be in the AH register half. After a doubleword in DX and AX is divided by a word length divisor, the quotient will be in the AX register and the remainder will be in the DX register. After a quadword in EDX and EAX is divided by a doubleword length divisor, the quotient will be in the EAX register and the remainder will be in the EDX register.
For all division operations, the dividend, divisor, quotient, and remainder must
dividend = quotient*divisor + remainder
For unsigned
div
operations, the dividend, divisor, quotient, and remainder are all treated as non-negative
The division instructions do not set flags to any significant values. They may destroy previously set values of AF, CF, OF, PF, SF, and ZF flags.
Some examples show how the division instructions work.
In each of these examples, the decimal number 100 is divided by 13. Since
100 = 7 * 13 + 9
the quotient is 7 and the remainder is 9. For the doubleword length divisor, the quotient is in EAX and the remainder is in EDX. For the word length divisor, the quotient is in AX and the remainder is in DX. For the byte length divisor, the quotient is in AL and the remainder is in AH.
For operations where the dividend or divisor is negative, equations analogous to the one above are
100 = (-7) * (-13) + 9 -100 = (-7) * 13 + (-9) -100 = 7* (-13) + (-9)
Note that in each case the sign of the remainder is the same as the sign of the dividend. The following examples reflect these equations for word size divisors of 13 or − 13.
In the second and third examples, the dividend − 100 is represented as the 32 bit number FF FF FF 9C in the DX and AX registers.
Finally, here are two examples to help
With the signed division, − 511 is divided by − 32, giving a quotient of 15 and a remainder of − 31. With the unsigned division, 65025 is divided by 255, giving a quotient of 255 and a remainder of 0.
With multiplication, the double length destination in each single-operand format
Figure 4.16 lists the
|
|
|
Clock Cycles |
|||||
|---|---|---|---|---|---|
|
Operand |
386 |
486 |
Pentium |
Number of Bytes |
Opcode |
|
register 8 |
19 |
19 |
22 |
2 |
F6 |
|
register 16 |
27 |
27 |
30 |
2 |
F7 |
|
register 32 |
43 |
43 |
48 |
2 |
F7 |
|
memory byte |
22 |
20 |
22 |
2 + |
F6 |
|
memory word |
30 |
28 |
30 |
2 + |
F7 |
|
memory doubleword |
46 |
44 |
48 |
2 + |
F7 |
|
|
|
|
|
Clock Cycles |
|||||
|---|---|---|---|---|---|
|
Operand |
386 |
486 |
Pentium |
Number of Bytes |
Opcode |
|
register 8 |
14 |
16 |
17 |
2 |
F6 |
|
register 16 |
22 |
24 |
25 |
2 |
F7 |
|
register 32 |
38 |
40 |
41 |
2 |
F7 |
|
memory byte |
17 |
16 |
17 |
2 + |
F6 |
|
memory word |
25 |
24 |
25 |
2 + |
F7 |
|
memory doubleword |
41 |
40 |
41 |
2 + |
F7 |
|
|
When arithmetic is being done with operands of a given length, the dividend must be converted to double length before a division operation is executed. For unsigned division, a doubleword-size dividend must be converted to quadword size with leading zero bits in the EDX register. This can be accomplished many ways, two of which are
mov edx, 0
and
sub edx, edx
Similar instructions can be used to put a zero in DX prior to unsigned division by a word operand or to put a zero in AH prior to unsigned division by a byte operand.
The situation is more complicated for signed division. A positive dividend must be extended with leading 0 bits, but a negative dividend must be extended with leading 1 bits. The 80×86 has three instructions for this task. The cbw , cwd , and cdq instructions are different from the instructions covered before in that these instructions have no operands. The cbw instruction always has AL as its source and AX as its destination, cwd always has AX as its source and DX and AX as its destination, and cdq always has EAX as its source and EDX and EAX as its destination. The source register is not changed, but is extended as a signed number into AH, DX, or EDX. These instructions are summarized together in Fig. 4.18, which also includes the cwde instruction that extends the word in AX to its signed equivalent in EAX, paralleling the job that cbw does.
|
|
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
|
Clock Cycles |
|||||
|---|---|---|---|---|---|
|
Instruction |
386 |
486 |
Pentium |
Number of Bytes |
Opcode |
|
cbw |
3 |
3 |
3 |
1 |
98 |
|
cwd |
2 |
3 |
2 |
1 |
99 |
|
cdq |
2 |
3 |
2 |
1 |
99 |
|
cwde |
3 |
3 |
3 |
1 |
98 |
|
|
The cbw (convert byte to word) instruction extends the 2's complement number in the AL register half to word length in AX. The cwd (convert word to double) instruction extends the word in AX to a doubleword in DX and AX. The cdq (convert double to quadword) instruction extends the word in EAX to a quadword in EDX and EAX. The cwde (convert word to double extended) instruction extends the word in AX to a doubleword in EAX; this is not an instruction that would normally be used to prepare for division. Each instruction copies the sign bit of the original number to each bit of the high order half of the result. None of these instructions affect flags. Some examples are
Two "move" instructions are somewhat similar to the above "convert" instructions. These instructions copy an 8-bit or 16-bit source operand to a 16-bit or 32-bit destination, extending the source value. The movzx instruction always extends the source value with zero bits. It has the format
movzx register, source
The movsx instruction extends the source value with copies of the sign bit. It has a similar format
movsx register, source
Data about these instructions is in Fig. 4.19. With either instruction the source operand can be in a register or in memory. Neither instruction changes any flag value.
|
|
|
Clock Cycles |
Opcode |
||||||
|---|---|---|---|---|---|---|---|
|
Destination |
Source |
386 |
486 |
Pentium |
Number of Bytes |
movsx |
movzx |
|
register 16 |
register 8 |
3 |
3 |
3 |
3 |
0F BE |
0F B6 |
|
register 32 |
register 8 |
3 |
3 |
3 |
3 |
0F BE |
0F B6 |
|
register 32 |
register 16 |
3 |
3 |
3 |
3 |
0F BF |
0F B7 |
|
register 16 |
memory byte |
6 |
3 |
3 |
3+ |
0F BE |
0F B6 |
|
register 32 |
memory byte |
6 |
3 |
3 |
3+ |
0F BE |
0F B6 |
|
register 32 |
memory word |
6 |
3 |
3 |
3+ |
0F BF |
0F B7 |
|
|
Here are a few examples showing how these instructions work.
This section concludes with another simple program, this one to convert Celsius (centigrade)
|
|
; program to convert Celsius temperature to Fahrenheit ; uses formula F = (9/5)*C + 32 ; author: R. Detmer ; date: revised 9/97 .386 .MODEL FLAT ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD INCLUDE io.h cr EQU 0dh ;carriage return character Lf EQU 0ah ;linefeed character .STACK 4096 ; reserve 4096-byte stack .DATA ; reserve storage for data Prompt1 BYTE CR,LF,"This program will convert a Celsius " BYTE "temperature to the Fahrenheit scale",cr,Lf,Lf BYTE "Enter Celsius temperature: ",0 Value BYTE 10 DUP (?) Answer BYTE CR,LF,"The temperature is" Temperature BYTE 6 DUP (?) BYTE " Fahrenheit",cr,Lf,0 .CODE ; start of main program code _start: Prompt: output Prompt1 ; prompt for Celsius temperature input Value,10 ; read ASCII characters atoi Value ; convert to integer imul ax,9 ; C*9 add ax,2 ; rounding factor for division mov bx,5 ; divisor cwd ; prepare for division idiv bx ; C*9/5 add ax,32 ; C*9/5 + 32 itoa Temperature,ax ; convert to ASCIIcharacters output Answer ; output label and result INVOKE ExitProcess, 0 ; exit with return code 0 PUBLIC _start ; make entry point public END
|
|
F = (9/5)* C + 32
where F is the Fahrenheit temperature and C is the Celsius temperature. Since the arithmetic instructions covered so far perform only integer arithmetic, the program gives the integer to which the
Exercises 4.4
|
|
For each part of this problem, assume the "before" values when the given instruction is executed. Give the
|
Before |
Instruction |
After |
|
|---|---|---|---|
|
(a) |
EDX: 00 00 00 00
|
idiv ebx |
EDX, EAX |
|
(b) |
AX: FF 75
|
idiv Count |
AX |
|
(c) |
AX: FF 75
|
div Count |
AX |
|
(d) |
DX: FF FF
|
idiv cx |
DX, AX |
|
(e) |
DX: FF FF FF FF
|
idiv ecx |
EDX, EAX |
|
(f) |
DX: 00 00
|
idiv cx |
DX, AX |
|
(g) |
DX: 00 00
|
idiv cx |
DX, AX |
|
(h) |
EDX: 00 00 00 00
|
idiv ebx |
EDX, EAX |
Give the opcode for each instruction in Exercise 1.
This section mentioned two
mov edx,0
or
sub edx,edx
Which instruction would give more compact code? Which instruction would execute in fewer clock cycles on a Pentium?
The Celsius to Fahrenheit temperature conversion program (Fig. 4.20) works for Celsius temperatures that have
|
|
Programming Exercises 4.4
|
|
The formula for converting a Fahrenheit to a Celsius temperature is
C = (5/9) * (F -32)
Write a complete 80×86 assembly language program to prompt for a Fahrenheit temperature and display the corresponding Celsius temperature.
Write a complete 80×86 assembly language program to prompt for four grades and then display the sum and the average (sum/4) of the grades.
Write a complete 80×86 assembly language program to prompt for four grades. Suppose that the last grade is a final exam grade that counts twice as much as the other three. Display the sum (adding the last grade twice) and the average (sum/5).
Write a complete 80×86 assembly language program to prompt for four pairs of grades and weighting factors. Each
WeightedSum = Grade1 * Weight1 + Grade2 * Weight2 + Grade3 * Weight3 + Grade4 * Weight4
and the sum of the weights is
SumOfWeights = Weight1 + Weight2 + Weight3 + Weight4
Display the weighted sum, the sum of the weights, and the weighted average (WeightedSum/SumOfWeights).
A sample run might look like
grade 1? 88 weight 1? 1 grade 2? 77 weight 2? 2 grade 3? 94 weight 3? 1 grade 4? 85 weight 4? 3 weighted sum: 591 sum of weights: 7 weighted average: 84
Write a complete 80×86 assembly language program to prompt for four grades, and then display the sum and the average (sum/4) of the grades in ddd.dd format (exactly three digits before and two digits after a decimal point).
Write a short program that causes a division by zero to discover how the interrupt handler in your 80×86 system responds.
|
|
| < Day Day Up > |