Thursday 24 November 2011

ARITHMETIC INSTRUCTIONS-notes


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