ARITHMETIC INSTRUCTIONS
Pentium provides arithmetic instructions for: Addition (ADD, ADC), incrementation (INC), subtraction (SUB, SBB), decrementation (DEC), comparison (CMP ), negation (NEG), multiplication (MUL, IMUL), and division (DIV, IDIV).
Each arithmetic instruction modifies one or more processor status flags.
Zero Flag (ZF): Tests the result of a flag modifying instruction whether zero or not. The Zero Flag is set if the result is zero; otherwise it is cleared.
The following conditional jump instructions may be used to react to the value of the zero flag: JZ, JE, JNZ, JNE
Carry Flag (CF): Tests for unsigned overflow. The carry flag is set if there is unsigned overflow; otherwise it is cleared.
The following conditional jump instructions may be used to react to the value of the carry flag: JC, JNC
Overflow Flag (OF): Tests for signed overflow. The overflow flag is set if there is signed overflow; otherwise it is cleared.
The following conditional jump instructions may be used to react to the value of the overflow flag: JO, JNO
Sign Flag (SF): This flag is useful only when dealing with signed numbers. The flag is set if the result is negative; otherwise it is cleared.
The following conditional jump instructions may be used to react to the value of the sign flag: JS (Jump if SF=1), JNS (Jump if no sign, i.e., SF=0)
Note: The processor does not know whether a given bit pattern represents a signed or unsigned number. It is up to the program logic to interpret a given bit pattern correctly, by using appropriate conditional jump instruction.
Auxiliary Flag (AF): The Auxiliary flag indicates whether an operation has produced a result that has generated a carry out of, or a borrow into, the low-order four bits of 8-, 16-, or 32-bit operands. The Auxiliary flag is set if there is such a carry or borrow; otherwise it is cleared.
Example:
MOV AL, 43 ; 00101011B
ADD AL, 94 ; 01011110B
1 Carry out of 4 low order bits
00101011B
01011110B
10001001B
Thus the Auxiliary flag is set.
Note: There is no conditional jump instruction to test the value of the Auxiliary flag.
Parity Flag (PF): Only the low-order 8 bits of an 8-, 16-, or 32-bit operand are considered to set or clear the Parity flag. The parity flag is set if the low-order 8-bits contain an even number of 1 bits; otherwise it is cleared.
The following conditional jump instructions may be used to react to the value of the parity flag: JP, JPE (Jump if Parity Even, i.e., if PF=1), JNP, JPO (Jump if Parity Odd, i.e., if PF=0).
ADD - Arithmetic Addition
Syntax: ADD destination, source
Effect: destination ß destination + source
Modifies flags: AF CF OF PF SF ZF
Examples:
ADD EBP, EAX
ADD BYTE PTR [DI], 3
ADD BX, [EAX + 2*ECX]
ADC - Add With Carry
Syntax: ADC destination, source
Effect: destination ß destination + source + CF
Modifies flags: AF CF OF SF PF ZF
ADC is used to add numbers that are wider than 16-bits in 8086 – 80286 processors, or wider than 32-bits in the 80386-80686 processors.
Example: Suppose we want to perform the following 32-bit addition in an 8086 – 80286 processor:
DX, CX ß DX, CX + BX, AX
Then the addition can be performed as:
ADD CX, AX
ADC DX, BX
Example: Suppose we want to perform the following 64-bit addition in 80386 – 80686 processor:
EDX, ECX ß EDX, ECX + EBX, EAX
The addition can be performed as:
ADD ECX, EAX
ADC EDX, EBX
INC - Increment
Syntax: INC destination
Effect: destination ß destination + 1
Modifies flags: AF OF PF SF ZF
This instruction is often used to increment indexes and therefore does not affect the carry flag.
Thus the following instructions will not set the carry flag:
MOV AL, 255
INC AL ; value in AL is now 0
SUB - Subtract
Syntax: SUB destination, source
Effect: destination ß destination - source
Modifies flags: AF CF OF PF SF ZF
SBB - Subtract with Borrow/Carry
Syntax: SBB destination, source
Effect: destination ß destination – source - CF
Modifies flags: AF CF OF PF SF ZF
The most common use for this instruction is for subtractions that are wider than 16-bits in 8086 – 80286 microprocessors, or wider than 32-bits in 80386 – 80586 microprocessors. Wide subtractions require that borrows propagate through the subtraction.
Example: Perform the following 32-bit subtraction in an 8086 processor:
DX, CX ß DX, CX – BX, AX
The subtraction can be performed as:
SUB CX, AX
SBB DX, BX
DEC - Decrement
Syntax: DEC destination
Effect: destination ß destination - 1
Modifies flags: AF OF PF SF ZF
This instruction is often used to decrement indexes and therefore does not affect the carry flag.
NEG - Two's Complement Negation
Syntax: NEG destination
Effect: destination ß 0 - destination
Modifies flags: AF CF OF PF SF ZF
This instruction is meaningful only with signed operands. The carry flag is always set, except when the destination is 0, in which case it is cleared.
Example:
; compute the absolute value of EAX
CMP EAX, 0
JGE DONE
NEG EAX
DONE:
Note: The instructions:
MOV AL, -128 ; minimum 8-bit signed value
NEG AL
will set the Overflow flag; but will not modify AL
Similarly, the instructions:
MOV AX, -32768 ; minimum 16-bit signed value
NEG AX
will set the Overflow flag; but will not modify AX
CMP - Compare
Syntax: CMP destination, source
Modifies flags: AF CF OF PF SF ZF
Effect: Subtracts source from destination and updates the flags but does
not save result. Flags can subsequently be checked for conditions.
If the destination is a 16-bit or 32-bit operand and source is a 8-bit immediate value, source is sign-extended to match the size of destination.
MULTIPLICATION INSTRUCTIONS (MUL AND IMUL)
Signed and unsigned multiplication lead to different results. Example, consider: 10000000B * 11111111B. Interpreted as unsigned numbers, the product is: 128 * 255 = 32640 = 0111 1111 1000 0000B. Interpreted as signed numbers, the product is: -128 * -1 = 128 = 0000 0000 1000 0000B.
Because signed and unsigned multiplication lead to different results, there are two multiplication instructions: MUL for unsigned multiplication and IMUL for signed multiplication:
| Instruction syntax | Effect |
8-bit multiplication | MUL Source8 | AX ß AL * Source8 |
IMUL Source8 | ||
16-bit multiplication | MUL Source16 | DX:AX ß AX * Source16 |
IMUL Source16 | ||
32-bit multiplication | MUL Source32 | EDX:EAX ß EAX * Source32 |
IMUL Source32 |
Where: (i) Source8 is either an 8-bit register or an 8-bit memory operand.
(ii) Source16 is either a 16-bit general-purpose register or a 16-bit memory operand.
(iii) Source32 is either a 32-bit general-purpose register or a 32-bit memory operand.
Two- and three-operand forms of IMUL
Instruction Syntax | Effect |
IMUL register1, register2 | register1 ß register1 * register2 |
IMUL register, memory | register ß register * memory |
IMUL register, immediate | register ß register * immediate |
IMUL register1, register2, immediate | register1 ß register2 * immediate |
IMUL register, memory, immediate | register ß memory * immediate |
In these forms of IMUL, the register and memory operands must all be of the same size. The registers are general-purpose registers. The immediate operand is treated as signed, if it sign-extended to the size of the destination operand, if its size is smaller.
Examples:
IMUL ECX ; EDX:EAX ß EAX * ECX
IMUL BL, CH, 7 ; BL ß CH * 7
Note:
(i) For multiplication of positive numbers, MUL and IMUL give the same results.
(ii) For IMUL, if the result of an 8-bit multiplication is 8-bits, it is sign-extended into the AH register. If the result of a 16-bit multiplication is 16-bits, it is sign-extended into the DX register. Similarly, if the result of a 32-bit multiplication is 32-bit, it is sign-extended into the EDX register.
Both MUL and IMUL leave all status flags undefined, except the Carry flag and the Overflow flag.
Multiplication overflow
1. Effect of MUL on the Carry Flag (CF) and the Overflow Flag (OF)
Both the Carry Flag and the Overflow Flag are cleared if the upper half of the result (AH for 8-bit MUL, DX for 16-bit MUL, and EDX for 32-bit MUL) is zero; otherwise they are set.
2. Effect of IMUL on the Carry Flag (CF) and the Overflow Flag (OF)
Both the Carry Flag and the Overflow Flag are cleared if the upper half of the result (AH for 8-bit IMUL, DX for 16-bit IMUL, and EDX for 32-bit IMUL) is the sign-extension of the lower half (AL for 8-bit IMUL, and DX for 16-bit IMUL); otherwise they are set.
For two- or three-operand IMUL, the CF and OF are cleared if the multiplication result is within the range, of signed numbers, of the destination operand; otherwise they are set
Thus, for both MUL and one-operand IMUL, if CF and OF are set it means that the product is too big to fit in the lower half of the destination (AL for 8-bit multiplication, AX for 16-bit multiplication, and EAX for 32-bit multiplication).
Note: Unlike an overflow condition resulting from ADD, SUB, NEG, SHL, or SAL, (which indicate an error in computation) an overflow condition resulting from MUL or IMUL may or may not indicate an error in computation. The interpretation of an error condition or otherwise depends on the application program being developed. For example, in the 16-bit decimal input algorithms developed latter in this chapter, a multiplication overflow indicates an error, because in those algorithms, the number input must fit in 16-bits.
Detection of Multiplication overflow in a program
Both signed and unsigned multiplication overflow can be detected by constructs of the form:
. . .
Multiplication instruction
JC MULTIPLICATION_OVERFLOW
. . .
JMP DONE
MULTIPLICATION_OVERFLOW:
. . .
DONE:
or . . .
Multiplication instruction
JO MULTIPLICATION_OVERFLOW
. . .
JMP DONE
MULTIPLICATION_OVERFLOW:
. . .
DONE:
Example:
. . .
MOV AX , 50
MUL BX
JC MULTIPLICATION_OVERFLOW
. . .
JMP DONE
MULTIPLICATION_OVERFLOW:
. . .
DONE:
Example: In each of the program fragments below, determine whether multiplication overflow will occur or not. Find also the result in the destination operand(s):
(a) MOV AL , 05H
MOV BL , 10H
MUL BL ; AX := AL * BL = 0050H , CF := 0 , OF := 0 , there is no overflow
(b) .DATA
VAR1 DW 2000H
VAR2 DW 0010H
. . .
MOV AX , VAR1
MUL VAR2 ; DX:AX := AX * VAR2 = 0002 0000H , CF := 1 , OF := 1 , there is overflow
(c) MOV AL , 1
MOV BL , -1
IMUL BL ; AX := -1 = 11111111 11111111B , CF := 0 , OF := 0 , there is no overflow
; the 8-bit result 11111111B is sign-extended into the AH register.
(d) MOV AX , 10
MOV CX , -48
IMUL CX ; DX:AX := -480 = FFFF FE20H , CF := 0 , OF := 0 , there is no overflow
; the 16-bit result FE20H is sign-extended into the DX register.
Example: Assuming that W and Y are word variables holding signed values, translate W := 5 * W - 12 * Y into an 8086 program fragment. The fragment must test for signed overflow.
MOV AX , 5
IMUL W ; AX := 5 * W
JO OVERFLOW
MOV W , AX ; W := 5 * W
MOV AX , 12
IMUL Y ; AX := 12 * Y
JO OVERFLOW
SUB W , AX ; W := 5 * W - 12 * Y
JO OVERFLOW
. . .
JMP DONE
OVERFLOW:
. . .
DONE:
Example: Perform an unsigned multiplication on a byte variable VAR1 and a word variable VAR2, and store the result in a double-word variable VAR3 :
.DATA
VAR1 DB 20H
VAR2 DW 1234H
VAR3 DD ?
. . .
MOV AX , VAR2
MOV BH , 0
MOV BL , VAR1
MUL BX
MOV WORD PTR VAR3 , AX
MOV WORD PTR VAR3 + 2 , DX
. . .
Example: Let N be a word variable holding an unsigned value. Assuming no multiplication overflow, write a program fragment to leave the factorial of N in the AX register.
MOV AX , 1
MOV CX , N
JCXZ EXIT
TOP: MUL CX
LOOP TOP
EXIT:
DIVISION INSTRUCTIONS (DIV AND IDIV)
DIV is used for unsigned division, and IDIV for signed division.
| Instruction syntax | Effect |
8-bit division | DIV Divisor8 | AL Divisor8 AX - Divisor8 * AL AH |
IDIV Divisor8 | ||
16-bit division | DIV Divisor16 | AX Divisor16 DX:AX - Divisor16 * AX DX |
IDIV Divisor16 | ||
32-bit division | DIV Divisor32 | EAX Divisor32 EDX:EAX - Divisor32 * EAX EDX |
IDIV Divisor32 |
Where: (i) Divisor8 is either an 8-bit register or an 8-bit memory operand.
(ii) Divisor16 is either a 16-bit general-purpose register or a 16-bit memory operand.
(iii) Divisor32 is either a 32-bit general-purpose register or a 32-bit memory operand.
Note:
(i) If both dividend and divisor are positive, DIV and IDIV give the same result.
(ii) For a signed division, the remainder, if not zero, has the same sign as the dividend.
(iii) The division instructions do not set flags to any useful values. They may destroy previously set values of CF, OF, SF and ZF flags.
Initialisation of the AH register before an 8-bit division
1. For a DIV instruction, the AH register must be initialised to 0 if the actual dividend is a byte; however if the actual dividend is a word then no initialisation is required.
Example: MOV AL , BYTE_VAR
MOV AH , 0 ; AH must be initialised to 0
MOV BL , 5
DIV BL
Example: MOV AX , 20 ; no initialisation of AH required
MOV CL , 4
DIV CL
Example: Read an ASCII digit, convert it to a numeric value, and then divide it by 3:
MOV AH , 01H
INT 21H
SUB AL , 30H
MOV AH , 0 ; initialise AH to 0
MOV BL , 3
DIV BL
Note: The instruction MOVZX (Move with Zero Extension) may also be used to initialise AH to zero:
MOVZX AX, BYTE_VAR
MOV BL, 5
DIV BL
2. For IDIV instruction, the sign-bit of AL must be extended throughout the AH register. This is done by the instruction:
CBW ; Convert Byte to Word
Example: MOV AL , VAR1
CBW
MOV BL , -7
IDIV BL
Note: If CBW instruction is not used to initialise AH before an 8-bit, signed division, the result of the division may be wrong. Consider:
MOV AX , -48
MOV BL , 5
IDIV BL
48d = 30H = 00110000B
2's complement
-48d = 11010000B
Thus AX will contain 0000000011010000B , which is +208 and not -48. However, if the division is performed as:
MOV AX , -48
CBW
MOV BL , 5
IDIV BL
Then the instruction CBW extends the sign bit of AL into AH. Hence, AX will contain 1111111111010000B i.e., FFD0H which is the 16-bit representation of -48.
The instruction MOVSX (Move with Sign Extension) may also be used to initialise AH:
MOVSX AX, -48
MOV BL, 5
IDIV BL
Initialisation of the DX register before a 16-bit division
1. For a 16-bit DIV instruction, the DX register must be initialised to 0.
Example: .DATA
DIVIDEND DW 8003H
DIVISOR DW 100H
. . .
MOV DX , 0
MOV AX , DIVIDEND
DIV DIVISOR
. . .
2. For a 16-bit IDIV instruction, the sign-bit of AX must be extended throughout the DX register. This is done by the instruction:
CWD ; Convert Word to Double-word
Example: MOV AX , -12 ; AX := FFF4H
CWD ; DX:AX := FFFF FFF4H
MOV BX , 7
IDIV BX ; AX := -1 = FFFFH , DX := -5 = FFFBH
Initialisation of the EDX register before a 32-bit division
3. For a 32-bit DIV instruction, the EDX register must be initialised to 0.
Example: .DATA
DIVIDEND DWORD 8003FFBCH
DIVISOR DWORD 10000000H
. . .
MOV EDX , 0
MOV EAX , DIVIDEND
DIV DIVISOR
. . .
4. For a 32-bit IDIV instruction, the sign-bit of EAX must be extended throughout the EDX register. This is done by the instruction:
CDQ ; Convert Double-Word to Quad-word
Example: MOV EAX , 8FBA2FECh
CDQ
MOV EBX , 2FFFFFFFh
IDIV EBX
Division overflow
If the quotient of either an 8-bit or a 16-bit division is too big to fit in an8-bit or a 16-bit register, respectively, then division overflow occurs. The CPU then automatically invokes software interrupt 00H and the program terminates or the system hangs.
1. Unsigned division overflow
Unsigned division overflow will only occur if the divisor is below or equal to the high-order register in the dividend (AH for 8-bit division, DX for 16-bit division, and EDX for 32-bit division).
Example: The sequence: MOV AX , 0200H
MOV BL , 02H
DIV BL
Causes division overflow, because BL £ AH. Note that the quotient in this case is 100H i.e., 256 which is above 255, the maximum 8-bit unsigned value.
Note: If AH is initialised to 0 before an unsigned division, overflow can only occur if the divisor has the value zero.
To avoid an 8-bit, unsigned, division-overflow in a program, a sequence like the one below can be used:
CMP Divisor8 , AH
JBE DIV_OVERFLOW
DIV Divisor8
. . .
JMP DONE
DIV_OVERFLOW:
. . .
DONE:
To avoid a 16-bit, unsigned, division-overflow in a program, a sequence like the one below can be used:
CMP Divisor16 , DX
JBE DIV_OVERFLOW
DIV Divisor16
. . .
JMP DONE
DIV_OVERFLOW:
. . .
DONE:
2. Signed division overflow
For an 8-bit signed division in which the AH register is initialised by the instruction CBW, overflow can only occur if either the divisor has the value zero or if the divisor has the value -1 and the dividend in AL is –128 (i.e., 80H, the minimum 8-bit signed value). For a 16-bit signed division in which the DX register is initialised by the instruction CWD, overflow can only occur if either the divisor has the value zero or if the divisor has the value -1 and the dividend in AX is –32768 (i.e., 8000H, the minimum 16-bit signed value). For a 32-bit signed division in which the EDX register is initialised by the instruction CDQ, overflow can only occur if either the divisor has the value zero or if the divisor has the value –1 and the dividend in EAX is –2147483648 (i.e., 80000000H, the minimum 32-bit signed value).
To avoid an 8-bit, signed, division-overflow in a program, a sequence like the one below can be used:
MOV AL , Dividend
CBW
CMP Divisor8 , 0
JE IDIV_OVERFLOW
CMP Divisor8 , -1
JNE L1
CMP AL , -128
JNE L1
JMP IDIV_OVERFLOW
L1: IDIV Divisor8
. . .
JMP DONE
IDIV_OVERFLOW:
. . .
DONE:
To avoid a 16-bit, signed, division-overflow in a program, a sequence like the one below can be used:
MOV AX , Dividend
CWD
CMP Divisor16 , 0
JE IDIV_OVERFLOW
CMP Divisor16 , -1
JNE L1
CMP AX , -32768
JNE L1
JMP IDIV_OVERFLOW
L1: IDIV Divisor16
. . .
JMP DONE
IDIV_OVERFLOW:
. . .
DONE:
DECIMAL I/O ROUTINES
1. Unsigned Decimal Output (Algorithm#1)
Write a procedure to display the unsigned contents of AX in decimal.
Assuming that num is the unsigned number to be displayed in decimal, the pseudo-code algorithm is:
count := 0 ;
do
{
quotient := num / 10 ;
remainder := num % 10 ;
PUSH the remainder in the stack ;
num := quotient ;
count := count + 1 ;
}while( quotient > 0 ) ;
for (count times )do
{
POP remainder from the stack ;
Convert remainder to ASCII ;
Display: remainder ;
} ;
STOP ;
This pseudo-code algorithm can be refined to the following pseudo-code algorithm:
count := 0 ;
do
{
clear DX to zero ;
divide AX by 10 ;
PUSH the remainder DX in the stack ;
count := count + 1 ;
}while( AX > 0 ) ;
for (count times )do
{
POP remainder DX from the stack ;
DL := DL + 30H ; Note, in this case DH is always zero
Display: DL ;
}
STOP ;
The required procedure is then:
WRITE_UNSIGNED_DECIMAL16 PROC uses AX BX CX DX
; Displays the contents of AX as an unsigned decimal value.
MOV CX , 0 ; counter
MOV BX , 10 ; divisor
@1: MOV DX , 0 ; initialise the high-order register of the dividend DX:AX
DIV BX ; AX := quotient , DX := remainder
PUSH DX ; save the remainder
INC CX
CMP AX , 0 ; compare the quotient with zero
JA @1
; Display
MOV AH , 02H
@2: POP DX ; pop a remainder
ADD DL , 30H ; convert to ASCII
INT 21H
LOOP @2
RET
WRITE_UNSIGNED_DECIMAL16 ENDP
Note:
(a) The above procedure will display the unsigned contents of AX in binary if the divisor is 2.
(b) The XLAT instruction can be used in conjunction with the above procedure to display an unsigned number in any base in the range 2 to 16. This is done in procedure WRITE_UNSIGNED on the next page.
2. Unsigned Output.
WRITE_UNSIGNED PROC uses AX BX CX DX DS
; Displays the unsigned contents of AX using the base in SI. The base must be in the range 2 to 16.
MOV DX , CS
MOV DS , DX
MOV CX , 0
CMP SI , 2
JB INVALID_BASE
CMP SI , 16
JA INVALID_BASE
@1: MOV DX , 0
DIV SI
PUSH DX
INC CX
CMP AX , 0
JA @1
LEA BX , HEXDIGITS
@2: POP AX
XLAT
MOV DL , AL
MOV AH , 02H
INT 21H
LOOP @2
CMP SI , 2
JE BINARY
CMP SI , 8
JE OCTAL
CMP SI , 10
JE DECIMAL
CMP SI , 16
JE HEXADECIMAL
JMP EXIT
INVALID_BASE: MOV AH , 09H
LEA DX , ERROR_MSG
INT 21H
JMP EXIT1
BINARY: MOV DL , 'B'
JMP EXIT2
OCTAL: MOV DL , 'o'
JMP EXIT2
DECIMAL: MOV DL , 'd'
JMP EXIT2
HEXADECIMAL: MOV DL , 'H'
EXIT2: MOV AH , 02H
INT 21H
EXIT1:
RET
HEXDIGITS DB '0123456789ABCDEF'
ERROR_MSG DB 0DH, 0AH, 'ERROR - INVALID BASE', '$'
WRITE_UNSIGNED ENDP
3. Signed Decimal Output.
Write a procedure to output the signed contents of AX.
The pseudo-code algorithm is:
if( AX < 0 )then
{
if( AX = -32678 )then
{
display: "-32678" ;
STOP ;
}
else
{
display: '-' ;
NEG AX ;
}
endif ;
}
endif ;
count := 0 ;
do
{
clear DX to zero ;
divide AX by 10 ;
PUSH the remainder DX in the stack ;
count := count + 1 ;
}while( AX > 0 ) ;
for (count times )do
{
POP remainder DX from the stack ;
DL := DL + 30H ; Note, in this case DH is always zero
Display: DL ;
}
STOP ;
Note: In this algorithm, the case of AX having the value -32678 is special in that we cannot perform the operation NEG AX without causing unsigned overflow.
The required procedure is:
WRITE_SIGNED_DECIMAL16 PROC uses AX BX CX DX
; Displays the contents of AX as a signed decimal value.
CMP AX , 0
JGE @2
CMP AX , -32768 ; minimum 16-bit unsigned value
JNE @1
PUSH DS
MOV DX , CS
MOV DS , DX
MOV AH , 09H
LEA DX , MINVALUE
INT 21H
POP DS
JMP EXIT1
@1: PUSH AX
MOV AH , 02H
MOV DL , '-'
INT 21H
POP AX
NEG AX
@2: MOV CX , 0 ; counter
MOV BX , 10 ; divisor
@3: CWD ; sign-extend AX into DX
IDIV BX
PUSH DX ; save the remainder
INC CX
CMP AX , 0
JG @3
; Display
MOV AH , 02H
@4: POP DX ; pop a remainder
ADD DL , 30H ; convert to ASCII
INT 21H
LOOP @4
EXIT1:
RET
MINVALUE DB '-32768', '$'
WRITE_SIGNED_DECIMAL16 ENDP
4. Unsigned Decimal Input
Write a procedure to read an unsigned 16-bit decimal number in the BX register. The procedure should set the Carry Flag if there is overflow or if no value is entered. For an invalid input the procedure should beep and give the user the chance of entering another value.
A number such as 53248 is read as a sequence of ASCII digits '5', '3', '2', '4', '8'. Each ASCII digit in the sequence must then be converted to a numeric value, multiplied by an appropriate factor 10i ( i Î {0, 1, 2, 3, 4}), and finally summed up:
'5' '3' '2' '4' '8'
-30H -30H -30H -30H -30H
( 5 * 10000) + ( 3 * 1000) + ( 2 * 100) + ( 4 * 10) + 8
Assuming valid input, the pseudo-code algorithm to do the reading is:
sum := 0 ;
multiplier := 10000 ;
for( 5 times )do ; a 16-bit decimal value has a maximum of 5 digits
{
Read: ch ;
ch := ch - 30H ; convert to numeric value
sum := sum + ch * multiplier ;
multiplier := multiplier / 10 ;
};
STOP ;
The disadvantage with this algorithm is that 5 digits must be input for each number read. So, for example, the number 6 must be input as 00006. However, using Horner's factorisation, an expression of the form:
( 5 * 10000) + ( 3 * 1000) + ( 2 * 100) + ( 4 * 10) + 8
can be factorised to:
10 * ( 10 * ( 10 * ( 5 * 10 + 3) + 2 ) + 4 ) + 8
Assuming no invalid input, the pseudo-code algorithm to read an unsigned decimal number using this factorised form is:
count := 0 ;
sum := 0 ;
do
{
Read: ch ;
if( ch = 0DH)then
break ;
endif ;
ch := ch - 30H ;
sum := 10 * sum ;
sum := sum + ch ;
count := count + 1 ;
}while( count < 5 ) ;
STOP ;
Refining the previous algorithm to incorporate input validity checking we have:
count := 0 ;
sum := 0 ;
do
{
Read: ch ;
if( ch = 0DH)then
goto exit ;
endif ;
if( ch ³ '0' and ch £ '9' )then
{
count := count + 1 ;
ch := ch - 30H ;
sum := 10 * sum ;
if( UnsignedMultiplicationOverflow )then
goto errorLabel ;
endif ;
sum := sum + ch ;
if( UnsignedAdditionOverflow )then
goto errorLabel ;
endif ;
}
else
{
Beep ;
Move the cursor back ;
}
endif ;
}while( count < 5 ) ;
exit: if( count = 0 )then
Display: “ERROR – NO VALUE OR NO VALID VALUE ENTERED”
STC ; set Carry flag (No input)
else
CLC ; clear Carry flag
endif
goto done ;
errorLabel: Display: “ERROR - UNSIGNED OVERFLOW”
STC ;
done:
STOP ;
The previous algorithm is translated into the following procedure:
READ_UNSIGNED_DECIMAL16 PROC uses AX CX DX
comment @
Reads an unsigned decimal number in the range 0 - 65535 in BX. The procedure rejects invalid input by beeping and backspacing the cursor. If there is unsigned overflow or if no value or no valid value is entered before the enter key is pressed, an appropriate error message is displayed and the Carry flag is set.
@
MOV BX , 0
MOV CX , 0
L1: MOV AH , 01H
INT 21H
CMP AL , 0DH
JE END_DO_WHILE
CMP AL , '0'
JB INVALID
CMP AL , '9'
JA INVALID
INC CX
SUB AL , 30H
MOV AH , 0
PUSH AX
MOV AX , 10
MUL BX
POP BX
JC OVERFLOW
ADD BX , AX
JC OVERFLOW
JMP NEXT
INVALID: MOV AH , 02H ; beep
MOV DL , 07H ;
INT 21H ;
MOV DL , 08H ; backspace
INT 21H ;
NEXT: CMP CX , 5
JB L1
END_DO_WHILE:
CMP CX , 0
JE L2
CLC
JMP DONE
L2: PUSH DS
MOV AX , CS
MOV DS , AX
MOV AH , 09H
LEA DX , NO_VALUE_MSG
INT 21H
POP DS
STC
JMP DONE
OVERFLOW:
PUSH DS
MOV AX , CS
MOV DS , AX
MOV AH , 09H
LEA DX , OVERFLOW_MSG
INT 21H
POP DS
STC
DONE: RET
OVERFLOW_MSG DB 0DH, 0AH, 'ERROR - UNSIGNED OVERFLOW','$'
NO_VALUE_MSG DB 0DH, 0AH, 'ERROR - NO VALUE OR NO VALID VALUE ENTERED','$'
READ_UNSIGNED_DECIMAL16 ENDP
5. Signed Decimal Input
Write a procedure to read a signed 16-bit decimal number in the BX register. The procedure should set the Carry Flag if there is overflow or if no value is entered. For an invalid input the procedure should beep and give the user the chance of entering another value.
Assuming:
(a) the signed number to be read is preceded by a +ve or -ve sign,
(b) no invalid input,
(c) the minimum 16-bit, signed value, i.e., -32768, is not read,
the pseudo-code algorithm is:
count := 0 ;
sum := 0 ;
negative := 0 ;
Read: ch ;
if( ch = '-' )then
negative := 1 ;
endif ;
do
{
Read: ch ;
if( ch = 0DH)then
break ;
endif ;
ch := ch - 30H ;
sum := 10 * sum ;
sum := sum + ch ;
count := count + 1 ;
}while( count < 5 ) ;
if( negative = 1)then
sum = -sum ;
endif ;
STOP ;
The above algorithm cannot be used to read the value -32768; because the line:
sum := sum + ch ;
in the algorithm, will translate to:
sum := 32760 + 8
This addition causes signed addition overflow, because the maximum 16-bit, signed value is 32767. To take care of this special case, the algorithm is modified as shown in the next page:
count := 0 ;
sum1 := 0 ;
sum2 := 0 ;
negative := 0 ;
Read: ch ;
if( ch = '-' )then
negative := 1 ;
endif ;
do
{
Read: ch ;
if( ch = 0DH)then
break ;
endif ;
ch := ch - 30H ;
sum1 := 10 * sum2 ;
if( (sum1 = 32760) and (ch = 8) and (negative = 1))then
{
sum2 := (-32760) + (-8) ;
goto done ;
}
endif ;
sum2 := sum1 + ch ;
count := count + 1 ;
}while( count < 5 ) ;
if( negative = 1)then
sum2 = -sum2 ;
endif ;
done:
STOP ;
Refining the previous algorithm to incorporate input validity checking and to take care of the fact that a positive value may be entered without being preceded by a positive sign we have:
count := 0 ;
sum1 := 0 ;
sum2 := 0 ;
negative := 0 ; assume the value to be read is not negative
Read: ch ;
if( ch = '-' )then
{
negative := 1 ;
Read: ch ;
}
else if( ch = '+' )then
Read: ch ;
endif ;
while( ch ¹ 0DH)do
{
if( ch ³ '0' and ch £ '9' )then
{
count := count + 1 ;
ch := ch - 30H ;
sum1 := 10 * sum2 ;
if( SignedMultiplicationOverflow )then
goto errorLabel ;
endif ;
if( (sum1 = 32760) and (ch = 8) and (negative = 1) )then
{ sum2 = -sum1 + -ch ;
CLC ;
goto done ;
} ;
sum2 := sum1 + ch ;
if( SignedAdditionOverflow )then
goto errorLabel ;
endif ;
}
else
{
Beep ;
Move the cursor back ;
}
endif ;
if( count = 5)then
goto exit ;
endif ;
Read: ch ;
}
endwhile ;
exit: if( count = 0 )then
Display: “ERROR – NO VALUE OR NO VALID VALUE ENTERED”
STC ; set Carry flag (No input)
else
if( negative = 1)then
sum2 = -sum2 ;
endif ;
CLC ; clear Carry flag
endif
goto done ;
errorLabel: Display: “ERROR - SIGNED OVERFLOW”
STC ;
done: STOP ;
The previous algorithm is translated into the following procedure:
READ_SIGNED_DECIMAL16 PROC uses AX CX DX SI
comment @
Reads a signed decimal number in the range -32768 to +32757 in BX. The procedure rejects invalid input by beeping and backspacing the cursor. If there is signed overflow or if no value or no valid value is entered before the enter key is pressed, an appropriate error message is displayed and the Carry flag is set.
@
MOV BX , 0
MOV SI , 0
MOV CL , 0
MOV AH , 01H
INT 21H
CMP AL , '-'
JE MINUS
CMP AL , '+'
JE PLUS
JMP L1
MINUS:
MOV CL , 1
PLUS:
MOV AH , 01H
INT 21H
L1: CMP AL , 0DH
JE EXIT
CMP AL , '0'
JB INVALID
CMP AL , '9'
JA INVALID
INC SI
SUB AL , 30H
MOV AH , 0
PUSH AX
MOV AX , 10
IMUL BX
POP BX
JO OVERFLOW
CMP AX , 32760
JE L2
JMP L3
L2: CMP BL , 8
JNE L3
CMP CL , 0
JE L3
NEG AX
NEG BX
ADD BX , AX
CLC
JMP DONE
L3: ADD BX , AX
JO OVERFLOW
JMP NEXT
INVALID: MOV AH , 02H ; beep
MOV DL , 07H ;
INT 21H ;
MOV DL , 08H ; backspace
INT 21H ;
NEXT: CMP SI , 5
JE EXIT
MOV AH , 01H
INT 21H
JMP L1
EXIT:
CMP SI , 0
JE NO_VALUE_ENTERED
JA L4
STC
JMP DONE
L4: CMP CL , 1
JE L5
CLC
JMP DONE
L5: NEG BX
CLC
JMP DONE
OVERFLOW:
PUSH DS
MOV DX , CS
MOV DS , DX
MOV AH , 09H
LEA DX , OVERFLOW_MSG
INT 21H
POP DS
STC
JMP DONE
NO_VALUE_ENTERED:
PUSH DS
MOV DX , CS
MOV DS , DX
MOV AH , 09H
LEA DX , NO_VALUE_MSG
INT 21H
POP DS
STC
DONE:
RET
OVERFLOW_MSG DB 0DH, 0AH, 'ERROR - SIGNED OVERFLOW','$'
NO_VALUE_MSG DB 0DH, 0AH, 'ERROR - NO VALUE OR NO VALID VALUE ENTERED','$'
READ_SIGNED_DECIMAL16 ENDP
No comments:
Post a Comment