6.4.2 Calculating with BCDs

When you use the processor to calculate with BCDs, the result is not correct unless you use the ASCII-adjust instructions to convert the result into the valid BCD integer.

6.4.2.1 Unpacked BCD Numbers

Summary: Instructions for unpacked BCDs allow accurate BCD calculations.

To do processor arithmetic on unpacked BCD numbers, you must do the eight-bit arithmetic calculations on each digit separately and assign the result to the AL register. After each operation, use the corresponding BCD instruction to adjust the result. The ASCII-adjust instructions do not take an operand. They always work on the value in the AL register.

When a calculation using two one-digit values produces a two-digit result, the AAA, AAS, AAM, and AAD instructions put the first digit in AL and the second in AH. If the digit in AL needs to carry to or borrow from the digit in AH, the instructions set the carry and auxiliary carry flags.

These instructions get their names from Intel mnemonics that use the term “ASCII” to refer to unpacked BCD numbers and “decimal” to refer to packed BCD numbers. The four ASCII-adjust instructions for unpacked BCDs are described below:

Instruction Description

AAA Adjusts after an addition operation.
AAS Adjusts after a subtraction operation.
AAM Adjusts after a multiplication operation. Always use with MUL, not with IMUL.
AAD Adjusts before a division operation. Unlike other BCD instructions, AAD converts a BCD value to a binary value before the operation. After the operation, use AAM to adjust the quotient. The remainder is lost. If you need the remainder, save it in another register before adjusting the quotient. Then move it back to AL and adjust if necessary.

The following examples show how to use each of these instructions in BCD addition, subtraction, multiplication, and division.

; To add 9 and 3 as BCDs:

mov ax, 9 ; Load 9

mov bx, 3 ; and 3 as unpacked BCDs

add al, bl ; Add 09h and 03h to get 0Ch

aaa ; Adjust 0Ch in AL to 02h,

; increment AH to 01h, set carry

; Result 12 (unpacked BCD in AX)

; To subtract 4 from 13:

mov ax, 103h ; Load 13

mov bx, 4 ; and 4 as unpacked BCDs

sub al, bl ; Subtract 4 from 3 to get FFh (-1)

aas ; Adjust 0FFh in AL to 9,

; decrement AH to 0, set carry

; Result 9 (unpacked BCD in AX)

; To multiply 9 times 3:

mov ax, 903h ; Load 9 and 3 as unpacked BCDs

mul ah ; Multiply 9 and 3 to get 1Bh

aam ; Adjust 1Bh in AL

; to get 27 (unpacked BCD in AX)

; To divide 25 by 2:

mov ax, 205h ; Load 25

mov bl, 2 ; and 2 as unpacked BCDs

aad ; Adjust 0205h in AX

; to get 19h in AX

div bl ; Divide by 2 to get

; quotient 0Ch in AL

; remainder 1 in AH

aam ; Adjust 0Ch in AL

; to 12 (unpacked BCD in AX)

; (remainder destroyed)

If you process multidigit BCD numbers in loops, each digit is processed and adjusted in turn.

6.4.2.2 Packed BCD Numbers

Packed BCD numbers are made up of bytes containing two decimal digits: one in the upper four bits and one in the lower four bits. The 8086-family processors provide instructions for adjusting packed BCD numbers after addition and subtraction. You must write your own routines to adjust for multiplication and division.

To do processor calculations on packed BCD numbers, you must do the eight-bit arithmetic calculations on each byte separately. The result should always be in the AL register. After each operation, use the corresponding BCD instruction to adjust the result. The decimal-adjust instructions do not take an operand. They always work on the value in the AL register.

The 8086-family processors provide DAA (Decimal Adjust after Addition) and DAS (Decimal Adjust after Subtraction) for adjusting packed BCD numbers after addition and subtraction.

These examples show DAA and DAS used for adding and subtracting BCDs.

;To add 88 and 33:

mov ax, 8833h ; Load 88 and 33 as packed BCDs

add al, ah ; Add 88 and 33 to get 0BBh

daa ; Adjust 0BBh to 121 (packed BCD:)

; 1 in carry and 21 in AL

;To subtract 38 from 83:

mov ax, 3883h ; Load 83 and 38 as packed BCDs

sub al, ah ; Subtract 38 from 83 to get 04Bh

das ; Adjust 04Bh to 45 (packed BCD:)

; 0 in carry and 45 in AL

Unlike the ASCII-adjust instructions, the decimal-adjust instructions never affect AH. The assembler sets the auxiliary carry flag if the digit in the lower four bits carries to or borrows from the digit in the upper four bits, and it sets the carry flag if the digit in the upper four bits needs to carry to or borrow from another byte.

Multidigit BCD numbers are usually processed in loops. Each byte is processed and adjusted in turn.