Packed BCD keeps two decimal digits in one byte, one per four bits: the number 38 is stored as 38h. Adding two such bytes with a plain ADD gives a binary sum, which is often not valid BCD: 38h + 45h = 7Dh. DAA right after the ADD (or ADC) on AL turns it into the correct packed result, here 83h.
Exactly what it does
First, if the low digit of AL is greater than 9 or AF is 1, DAA adds 6 to AL and sets AF. Then, if AL is now greater than 9Fh or CF is 1, it adds 60h to AL and sets CF. A step that is not needed clears its flag. CF = 1 therefore means the decimal sum passed 99 and a 1 carries into the next pair of digits. SF, ZF and PF are set from the final AL; OF is undefined.
| Add | Binary sum | After DAA | CF |
|---|---|---|---|
| 38h + 45h | 7Dh | 83h | 0 |
| 19h + 01h | 1Ah | 20h | 0 |
| 75h + 48h | BDh | 23h | 1 (123) |
| 09h + 09h | 12h (AF = 1) | 18h | 0 |
MOV AL, 38h ; packed BCD 38ADD AL, 45h ; AL = 7Dh, not BCDDAA ; AL = 83h: packed 83MOV AH, ALMOV CL, 4SHR AH, CL ; AH = high digitAND AL, 0Fh ; AL = low digitOR AX, 3030h ; both digits -> charactersMOV BX, AXMOV DL, BHMOV AH, 02h ; DOS: print DLINT 21hMOV DL, BLMOV AH, 02hINT 21h
Longer numbers
A packed number with more digits is a string of such bytes. Add them from the lowest byte up, with ADC so the carry from the previous DAA is included, and DAA after every byte.
Pitfalls
DAA works only on AL and only straight after an addition into AL, since it reads AF and CF from that addition. Both inputs must be valid packed BCD. Use INC AL with care: it does not set CF, so for a decimal counter write ADD AL, 1 then DAA.
Later CPUs
Unchanged in 16- and 32-bit code; not available in 64-bit mode.