The aaa instruction is used to adjust the content of the AL register after that register has been used to perform the addition of two unpacked BCDs. The CPU uses the following logic:
IF (al AND 0Fh > 9) or (the Auxilliary Flag is set) al = al+6 ah = ah+1 CF set AF set ENDIF al = al AND 0Fh(The Auxilliary Flag is set whenever there is an overflow of the lower 4 bits after an addition.)
Although this instruction should be used immediately after the addition instruction, it could be used later as long as no other intervening instruction would have changed the AF flag (such as a mov instruction).
Example1: mov al,7 add al,2 ;al = 9, AF clear, CF clear aaa ;al = 9, ah is unchanged, CF clear
Example2: mov al,7 add al,6 ;al = 13 = 0Dh, al AND 0Fh = 0Dh > 9, AF clear, CF clear aaa ;al = al+6 = 19 = 13h AND 0Fh = 3, ah=ah+1, CF set
Example3: mov al,7 add al,9 ;al = 16 = 10h, al AND 0Fh = 0 <= 9, AF set, CF clear aaa ;al = al+6 = 22 = 16h AND 0Fh = 6, ah=ah+1, CF setNote: Because only the lower 4 bits of AL are retained, it is thus possible to add the ASCII values of numerical digits directly without the need to convert them to their binary values beforehand.
Example4: mov al,"7" ;37h add al,"2" ;al = 37h+32h = 69h AND 0Fh = 9, AF clear, CF clear aaa ;al = 69h AND 0Fh = 9, ah is unchanged, CF clear
.data num1 db "491756380472816275825",11 dup(0) num2 db "8387562019932850157",13 dup(0) size1 dd 21 size2 dd 19 answer db 32 dup(0) .code ; ECX will be used to hold the count of digits in the longer string ; EDX will be used to hold the count of digits in the shorter string ; ESI will be used to point to the current digit of the longer string ; EDI will be used to point to the current digit of the shorter string ; EBX will be used to point to the current digit of the answer mov eax,size1 .if eax >= size2 mov ecx,size1 mov edx,size2 mov esi,offset num1 add esi,ecx ;points to the byte after the last digit dec esi ;now points to last digit mov edi,offset num2 add edi,edx ;points to the byte after the last digit dec edi ;now points to last digit .else mov ecx,size2 mov edx,size1 mov esi,offset num2 add esi,ecx ;points to the byte after the last digit dec esi ;now points to last digit mov edi,offset num1 add edi,edx ;points to the byte after the last digit dec edi ;now points to last digit .endif ; The above could also include code to allocate a memory block of proper ; size for the answer and then load EBX with its address. mov ebx,offset answer ;the answer will be stored in reverse order clc ;clear the CF before starting the addition ; The inc and dec instructions don't affect the CF. ; The CF would be affected if you change those for add reg,1 and sub reg,1 ; and you would then need to save and restore that flag within the loops. shortloop: mov al,[esi] adc al,[edi] ;add the two digits and ;include CF from previous addition aaa ;adjust the resulting digit of the addition mov [ebx],al ;store it inc ebx dec esi dec edi dec ecx dec edx jnz shortloop ;continue until short number completed ; At this point, all the digits of the shorter number have been added. ; The remaining digits of the longer number must still be processed ; with any carry from previous additions. inc ecx dec ecx ;check if long number also terminated jnz longloop jnc finish ;no overflow from last addition mov byte ptr[ebx],1 ;last addition would have overflow inc ebx jmp finish longloop: mov al,[esi] adc al,0 aaa mov [ebx],al inc ebx dec esi dec ecx jnz longloop jnc finish ;no overflow from last addition mov byte ptr[ebx],1 inc ebx finish: ; At this point the answer is in reverse order and in binary format. ; The digits will now be reversed and converted to a null-terminated ; ASCII string ready for display. ; ESI will be used to point from the start of the answer ; EBX will be used to point from the end of the answer mov byte ptr[ebx],0 ;to terminate ASCII string mov esi,offset answer dec ebx ;point to last digit @@: mov al,[esi] mov ah,[ebx] add ax,3030h ;convert both to ASCII mov [esi],ah mov [ebx],al ;switch the two digits inc esi dec ebx cmp esi,ebx jbe @B ; The answer is now ready for display
There could be many variations to the above code.
For instance, you could add code to shift the shorter number in its buffer and pad it in front with 0's to have the same length for both numbers; the code for the "longloop" could then be eliminated.
Another option to improve execution speed when one number is much shorter than the other one could be to exit the "longloop" as soon as there is no carry and then simply copy the remaining digits of the longer number to the answer.
And, if one of the numbers being added is not to be used again, its buffer could be used to store the answer of the addition. Be sure, however, that its buffer size is large enough for the answer and that you don't overwrite the original digits before they are used.