I am looking at the pseudo-code: The Hidden Power of BCD Instructions. Here's a snippet of the contents of the website:
So, let's take a look at what AAA does. Here is the pseudo-code equivalent (from Intel):
IF ((AL AND 0FH) > 9) OR (AF = 1)
THEN
AL = (AL + 6) AND 0FH;
AH = (AH + 1);
AF = 1;
CF = 1;
ELSE
AF = 0;
CF = 0;
FI;enter code here
That's true for a typical Intel documentation compliant use like this one:
mov al,6
add al,9 ;al=15=0Fh
aaa ;al=21=15h => it's in decimal!
The algorithm above doesn't seem to give the result as commented in the code, so I am assuming some steps were omitted here. The comment state the following: "al=21=15h => it's in decimal!".
My interpretion of the code is as follows:
However, there is no mention of the values stored in AH registers prior to running the line "AH = (AH + 1);". If it was initialised to zero, it'll only work for numbers under 20. Now let's assume it was initialised to zero, I'll expect the result to stored as AH=1 and AL=5, but the comment says ";al=21=15h => it's in decimal!". It seems something else was done before and after the execution of this block of code.
Can you explain to me what I am missing here?
Also, how are the CF/AF flags used here?
It would appear the author's understanding of what AAA does is misguided and he may have confused it with DAA (Decimal Adjust AL after Addition), but to make matters worse the Intel documentation over the years has been incorrect2 3 at times, thus adding to the confusion.
I'm not going to answer your question directly, but I want to give you some background that may allow you to figure out the answers to your own question given proper documentation. The documentation that you have quoted in your question only applies to processors earlier than the 80286, and even then it also contains an error regarding the masking of the bottom 4 bits of AL2
The original intent of AAA was to be used after the addition of two valid unpacked BCD numbers (ASCII 0
to 9
or 0x30 to 0x39) to convert the result to a valid 2-digit BCD number. Some people abused AAA outside of what it was designed for. Unfortunately, some of the code that abused AAA broke when the 286 was announced.
The AAA instruction is best defined this way1:
IF ((( AL and 0FH ) > 9 ) or (AF==1) IF CPU<286 THEN AL = AL+6 ELSE AX = AX+6 ENDIF AH = AH+1 CF = 1 AF = 1 ELSE CF = 0 AF = 0 ENDIF AL = AL and 0Fh
When adding two single digit BCD numbers you will want to clear out AH before the AAA. Code that would add two numbers would look like:
xor ah, ah ; Clear AH
mov al, '6' ; AL=0x36 (0x36 = ASCII '6')
add al, '9' ; AL=0x36+0x39 (0x39 = ASCII '9') = 0x6F
aaa ; AH=0x01, AL=0x05 thus AX=0x0105 . AH has upper digit, AL has the lower.
Because this code uses valid values (0x30 to 0x39) it will work the same way for all processors where the instruction is supported1. More generally though as long as the value in AL is 0x00 through 0xF9 (inclusive) the result of AAA will be the same if run on a processor <286 and a 286 or later processor.
If adding three or more BCD numbers you can use the value in AH to help maintain a properly overflowed result.
The AAS instruction is best defined this way1:
IF ((( AL and 0FH ) > 9 ) or (AF==1) IF CPU<286 THEN AL = AL-6 ELSE AX = AX-6 ENDIF AH = AH-1 CF = 1 AF = 1 ELSE CF = 0 AF = 0 ENDIF AL = AL and 0Fh
Notes:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With