

        Contents: BCD-related 8086 CPU instructions
                  BCD-related 80x87 floating-point unit instructions
                  8086 flags


        =============================================================
        BCD-related 8086 CPU instructions


        The instructions DAA and DAS support operations on packed (2
        digits per byte) BCDs. The instructions AAA, AAS, AAM, and 
        AAD support operations on unpacked BCDs (1 digit per byte).

        Before executing DAA, DAS, AAA, or AAS, the state of the 
        adjust and carry flags and the contents of the AL register 
        are important. Since these BCD instructions are normally 
        brought to use in a loop, keep in mind that the INC and DEC 
        instructions change the adjust flag, but not the carry flag.
        Several instructions leave the adjust flag (sometimes called
        the auxiliary carry or the BCD carry) in an undefined state.

        After executing DAA, DAS, AAA, or AAS, the adjust flag (af) 
        is set if there was a carry out of, or a borrow from the 
        lower half of the AL register, cleared otherwise; the carry 
        (cf) is set if the result is outside 0-99 (DAA,DAS) or 0-9 
        (AAA,AAS), cleared otherwise.

        There is no jump instruction that acts on the adjust flag. If
        a program wants to read this flag it can be done by using a
        LAHF or PUSHF instruction.

        AAA, AAS, AAM, and AAD (used for un-packed BCDs) may change 
        the contents of the AH register.


        The DAA, DAS, AAA, AAS, AAM, and AAD instructions take no 
        formal operands; they all use operands implicitly contained 
        in the accumulator.




        -------------------------------------------------------------
        DAA     Decimal Adjust after Addition

        Flags changed: sf,zf,af,pf,cf (of is undefined)

        Execute DAA after executing an ADD or ADC instruction on two
        packed BCD operands. The addition leaves a two-digit byte
        result in the AL register. The DAA instruction adjusts AL to
        contain the correct two-digit packed decimal result.


        Logic:  if (AL AND 0Fh) > 9 or (AF = 1) then
                        AL := AL + 6
                        AF := 1
                        CF := CF or CarryFromLastAddition
                                ; CF or carry from (AL := AL + 6)
                else
                        AF := 0
                endif
                if (AL AND 0F0h) > 90h or (CF = 1) then
                        AL := AL + 60h
                        CF := 1
                else
                        CF := 0
                endif


        Example:
                  49
                + 68  Carry out of bit 3
                 ---
                  B1  Adjust flag set
                + 06  DAA adjustment #1
                 ---
                  B7  High nibble > 9
                + 60  DAA adjustment #2
                 ---
                  17  Carry flag set



        -------------------------------------------------------------
        DAS     Decimal Adjust after Subtraction

        Flags changed: sf,zf,af,pf,cf (of is undefined)

        Execute DAS after executing a SUB or SBB instruction on two
        packed BCD operands. The subtraction leaves a two-digit byte
        result in the AL register. The DAS instruction adjusts AL to
        contain the correct two-digit packed decimal result.


        Logic:  if ((AL AND 0Fh) > 9) or (AF = 1) then
                        AL := AL - 6
                        AF := 1
                        CF := CF or BorrowFromLastSubtraction
                                ; CF or borrow from (AL := AL - 6)
                else
                        AF := 0
                endif
                if (AL > 9Fh) or (CF = 1) then
                        AL := AL - 60h
                        CF := 1
                else
                        CF := 0
                endif


        Example:
                  65
                - 67  Borrow out of bit 3
                 ---
                  FE  Adjust flag set
                - 06  DAS adjustment #1
                 ---
                  F8  AL > 9Fh
                - 60  DAS adjustment #2
                 ---
                  98  Carry flag set


        Example:
                  53
                - 28
                 ---
                  2B  Adjust flag set
                - 06  DAS adjustment
                 ---
                  25

                Since the 10's complement (100 - b) is equal to
                the 9's complement plus one (99 - b + 1) and any
                BCD number subtracted from 99 doesn't require
                adjustment, DAS can be substituted by ADD followed
                by DAA (Intel 8085 had no DAS instruction):

                  53
                + 72  ADD (99 - 28 + 1)
                 ---
                  C5
                + 60  DAA (AL > 9Fh)
                 ---
                  25  (Ignore carry)



        -------------------------------------------------------------
        AAA     ASCII Adjust after Addition

        Flags changed: af,cf (of,sf,zf,pf undefined)

        Execute AAA following an ADD or ADC operation on two unpacked
        BCD digits that leaves a byte result in the AL register. AAA
        converts the number in the lower 4 bits (nibble) of AL to an
        unpacked BCD number (high-order nibble of AL is zeroed). 
        If the addition produced a decimal carry, the AH register is
        incremented, and the carry and adjust flags are set to 1. If 
        the addition produced no decimal carry, the carry and adjust
        flags are set to 0 and AH is unchanged.


        Logic:  if (AL AND 0Fh) > 9 or (AF = 1) then
                        AL := AL + 6
                        AH := AH + 1    [*Note*]
                        AF := 1;  CF := 1
                else
                        AF := 0;  CF := 0
                endif
                AL := AL AND 0Fh


                [*Note*]
                The 8086/88 processors will not add a carry out
                of AL into AH if an invalid operand is in AL. The
                newer processors will, yielding different results
                for the same _invalid_ operand (AH := AH + 2 in
                description above if AL was > 0F9h before AAA).
                Execution is the same when valid operands are
                loaded.



        -------------------------------------------------------------
        AAS     ASCII Adjust after Subtraction

        Flags changed: af,cf (of,sf,zf,pf undefined)

        Execute AAS following a SUB or SBB operation on two unpacked
        BCD digits that leaves a byte result in the AL register. AAS
        converts the number in the lower 4 bits (nibble) of AL to an
        unpacked BCD number (high-order nibble of AL is zeroed).
        If the subtraction produced a decimal carry, the AH register
        is decremented, and the carry and adjust flags are set to 1.
        If the subtraction produced no decimal carry, the carry and
        adjust flags are set to 0 and AH is unchanged.


        Logic:  if (AL AND 0Fh) > 9 or AF = 1 then
                        AL := AL - 6
                        AH := AH - 1    [*Note*]
                        AF := 1;  CF := 1
                else
                        AF := 0;  CF := 0
                endif
                AL := AL AND 0Fh


                [*Note*]
                The 8086/88 processors will not subtract a borrow
                out of AL from AH if an invalid operand is in AL.
                The newer processors will, yielding different
                results for the same _invalid_ operand (AH := AH
                - 2 in description above if AL was < 06h before
                AAS). Execution is the same when valid operands
                are loaded.



        -------------------------------------------------------------
        AAM     ASCII Adjust after Multiply

        Flags changed: sf,zf,pf (of,af,cf undefined)

        Execute AAM after a MUL operation on two unpacked BCD operands
        that leaves the result in the AX register. Because the result
        is less than 100, it is contained entirely in the AL register.
        AAM unpacks the result in AL by dividing AL by 10, leaving the
        quotient in AH and the remainder in AL.


        Logic:  AH := AL / 10
                AL := AL MOD 10



        -------------------------------------------------------------
        AAD     ASCII Adjust before Division

        Flags changed: sf,zf,pf (of,af,cf undefined)

        AAD converts the unpacked two-digit BCD number in AX into
        binary in preparation for a division using the DIV
        instruction, which requires binary rather than BCD numbers.

        The result produced by the subsequent division will be an
        unpacked BCD number.


        Logic:  AL := AH * 10 + AL
                AH := 0



        -------------------------------------------------------------
                            Clock cycles
        Instruction     8086 '286 '386 '486 Pentium  Opcode

        DAA               4    3    4    2    3      27h
        DAS               4    3    4    2    3      2Fh
        AAA               8    3    4    3    3      37h
        AAS               8    3    4    3    3      3Fh
        AAM              83   16   17   15   18      D4h 0Ah
        AAD              60   14   19   14   10      D5h 0Ah

        Note: Clocks are listed for comparison only, the exact timing
              depends on several factors. None of the instructions
              are pairable on the Pentium.

        Note: Reportedly, the constant 0Ah was included in the AAM and
              AAD opcodes because there was insufficient space to hold
              it in the 8086's microcode.
              Intel's Pentium manual documents that both AAM and AAD
              work with other constants (10h, for example); this need
              not be the case for older 8086-'compatible' processors.




        =============================================================
        BCD-related 80x87 floating-point unit instructions

        Note: Bits 72-78 of a packed BCD are ignored by the FPU, i.e.
              only the sign bit of the top byte is significant.
              Under certain circumstances (see Intel documentation
              for details) the FBSTP instruction may store the 'BCD
              indefinite', in which bits 72-79 are all set.


        -------------------------------------------------------------
        FBLD    Load Packed Decimal

        Format: FBLD memory operand
        Exceptions: I

        FBLD converts a memory operand from BCD (packed decimal)
        format to temporary real and loads it into ST. The operand is
        loaded without rounding error. The sign of the operand is
        preserved, including the case where the value is negative
        zero.

        The packed decimal digits are assumed to be in the range 0-9.
        The instruction does not check for invalid digits (A-Fh), and
        the result of attempting to load an invalid encoding is
        undefined.


        Logic:  push stack
                ST := memory operand



        -------------------------------------------------------------
        FBSTP   Store Packed Decimal and Pop

        Format: FBSTP memory location
        Exceptions: I

        FBSTP converts the number in ST to BCD (packed decimal)
        format, stores it at memory location, and pops the FPU stack.
        Non-integral values are first rounded according to the RC
        field of the FPU's control word.


        Logic:     [memory location] := ST
                   pop stack



        -------------------------------------------------------------
                        Clock cycles
        Instruction     8087    '287    '387    '487    Pentium

        FBLD            290-310 290-310 266-275  70-103  48- 58
        FBSTP           520-540 520-540 512-534 172-176 148-154

        Note: Effective addressing not included. Clocks are listed
              for comparison only, the exact timing depends on
              several factors.




        =============================================================
        8086 flags

        of = overflow flag  = bit 11 of flags register
        df = direction flag = bit 10 of flags register
        if = interrupt flag = bit  9 of flags register
        tf = trap flag      = bit  8 of flags register
        sf = sign flag      = bit  7 of flags register
        zf = zero flag      = bit  6 of flags register
        af = adjust flag    = bit  4 of flags register
        pf = parity flag    = bit  2 of flags register
        cf = carry flag     = bit  0 of flags register

        LAHF instruction copies bits 0-7 to the AH register.
        PUSHF instruction copies bits 0-15 to top-of-stack.
        =============================================================
