Flylib.com

Books Software

 
 
 

4.4 Division Instructions

 < Day Day Up > 


4.4 Division Instructions

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 multiplier and multiplicand and produce a double-length product. Division instructions start with a double-length dividend and a single-length divisor, and produce a single-length quotient and a single-length remainder. The 80×86 has instructions that can be used to produce a double-length dividend prior to division.

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 size and is assumed to be in the AX register. If source is word length, then the dividend is a doubleword and is assumed to have its low order 16 bits in the AX register and its high order 16 bits in the DX register. If source is doubleword length, then the dividend is a quadword (64 bits) and is assumed to have its low order 32 bits in the EAX register and its high order 32 bits in the EDX register.

The table in Fig. 4.15 summarizes the locations of the dividend, divisor, quotient, and remainder for 80×86 division instructions.

start figure

source (divisor) size

other operand (dividend)

quotient

remainder

byte

AX

AL

AH

word

DX:AX

AX

DX

doubleword

EDX:EAX

EAX

EDX

end figure

Figure 4.15: Operands and results for 80×86 division instructions

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 satisfy the equation

dividend = quotient*divisor + remainder

For unsigned div operations, the dividend, divisor, quotient, and remainder are all treated as non-negative numbers . For signed idiv operations, the sign of the quotient is determined by the signs of the dividend and divisor using the ordinary rules of signs; the sign of the remainder is always the same as the sign of the dividend.

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.

click to expand

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.

click to expand

click to expand

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 illustrate the difference between signed and unsigned division.

click to expand

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 guarantees that the product will fit in the destination location-nothing can go wrong during a single-operand multiplication operation. There can be errors during division. One obvious cause is an attempt to divide by zero. A less obvious reason is a quotient that is too large to fit in the single-length destination; if, say, 00 02 46 8A is divided by 2, the quotient 1 23 45 is too large to fit in the AX register. If an error occurs during the division operation, the 80×86 generates an exception. The routine, or interrupt handler, that services this exception may vary from system to system. Windows 95 on the author's Pentium system pops up a window with the message "This program has performed an illegal operation and will be shut down." When the Details button is pressed, it displays "TEST caused a divide error " The 80×86 leaves the destination registers undefined following a division error.

Figure 4.16 lists the allowable operand types for idiv instructions and Fig. 4.17 lists the allowable operand types for div instructions. The only differences in the two tables are in the number of clock cycles columns ; div operations are slightly faster than idiv operations.

start figure

   

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

end figure

Figure 4.16: idiv instructions

start figure

 

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

end figure

Figure 4.17: div instructions

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.

start figure

{% 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

end figure

Figure 4.18: cbw and cwd instructions

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

click to expand

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.

start figure

   

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

end figure

Figure 4.19: movsx and movzx instructions

Here are a few examples showing how these instructions work.

click to expand

This section concludes with another simple program, this one to convert Celsius (centigrade) temperatures to Fahrenheit. Figure 4.20 gives the source code. The formula implemented is

start figure
; 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 ASCII

characters

output Answer ; output label and result INVOKE ExitProcess, 0 ; exit with return code 0 PUBLIC _start ; make entry point public END
end figure

Figure 4.20: Convert Celsius temperature to Fahrenheit

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 fractional answer would round. It is important to multiply 9 and C before dividing by 5; the integer quotient 9/5 would be simply 1. Dividing C by 5 before multiplying by 9 produces larger errors than if the multiplication is done first. Why? To get a rounded answer, half the divisor is added to the dividend before dividing. Since the divisor in this formula is 5, the number 2 is added for rounding. Notice that the cwd instruction is used to extend the partial result before division.

Exercises 4.4

start example
  1. For each part of this problem, assume the "before" values when the given instruction is executed. Give the requested "after" values. Some of these instructions will cause division errors; identify such instructions.

     

    Before

    Instruction

    After

    (a)

    EDX: 00 00 00 00
    EAX: 00 00 00 9A
    EBX: 00 00 00 0F

    idiv ebx

    EDX, EAX

    (b)

    AX: FF 75
    byte at Count: FC

    idiv Count

    AX

    (c)

    AX: FF 75
    byte at Count: FC

    div Count

    AX

    (d)

    DX: FF FF
    AX: FF 9A
    CX: 00 00

    idiv cx

    DX, AX

    (e)

    DX: FF FF FF FF
    AX: FF FF FF 9A
    CX: FF FF FF C7

    idiv ecx

    EDX, EAX

    (f)

    DX: 00 00
    AX: 05 9A
    CX: FF C7

    idiv cx

    DX, AX

    (g)

    DX: 00 00
    AX: 05 9A
    CX: 00 00

    idiv cx

    DX, AX

    (h)

    EDX: 00 00 00 00
    EAX: 00 00 01 5D
    EBX: 00 00 00 08

    idiv ebx

    EDX, EAX

  2. Give the opcode for each instruction in Exercise 1.

  3. This section mentioned two methods of zeroing EDX prior to unsigned division, using

    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?

  4. The Celsius to Fahrenheit temperature conversion program (Fig. 4.20) works for Celsius temperatures that have fairly large magnitude and are either positive or negative. Suppose that you limit the Celsius temperature to the range 0-100 degrees, yielding Fahrenheit temperatures from 32-212. How can the program be modified to take advantage of these limited numeric ranges?

end example

Programming Exercises 4.4

start example
  1. 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.

  2. 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.

  3. 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).

  4. Write a complete 80×86 assembly language program to prompt for four pairs of grades and weighting factors. Each weighting factor indicates how many times the corresponding grade is to be counted in the sum. The weighted sum is

    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
    
  5. 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).

  6. Write a short program that causes a division by zero to discover how the interrupt handler in your 80×86 system responds.

end example



 < Day Day Up >