aaa
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.
