const char* p = rhs.digits; //temp pointer to rhs.digits.
char* q = digits; //temp to just digits
_asm {
mov EAX, 0 //clear register for addition
mov ESI, p //point to rhs.digits
mov EDI, q //point to digits
add EDI, 4095 //last position of digits
add ESI, 4095
mov ECX, 4096 //set up loop
L1:
mov AL, [EDI] //setup for addition
add AL, [ESI] //Add
add AL, AH //Add carry
mov AH, 0 //Clear AH register
AAA //Adjust after addition
mov [EDI], AL
dec ESI
dec EDI //move pointers
loop L1
}
This is an inline asm function written in C++. Digits is an array of characters 4096 characters long and rhs.digits is a seperate array. Digits is the destination and rhs.digits is the array being added to digits.
The problem I am having is concerning the carry when the addition results in a number larger than 15. So 8+8, 8+9, 9+9. I'm not 100% sure how AAA works, but I believe it drops the high order bits of the value and places the low order into AH. That would mean that because 16, 17 and 18 cannot be represented with one hexadecimal digit and requires two, the higher order bits are dropped and ignored.
This is reinforced by examining the outputs. if 8+8 0 is placed in that position. If 8+9, 1 and 9+9, 2. This would correspond to their hexadecimal representation. I tried using DAA instead but that didn't work either.
How can I fix this? If there an instruction that accounts for this?
Thanks for the help guys.
For packed BCD values you need to use the DAA
instruction, for example
clc
L1:
mov AL, [EDI]
adc AL, [ESI]
daa
mov [EDI], AL
; etc
For unpacked BCD numbers you need to use the AAA
instruction (ASCII Adjust After Addition), for example
clc
L1:
mov AL, [EDI]
adc AL, [ESI]
aaa ; CF=AF=decimal carry-out from AL. Also added to AH
mov [EDI], AL
; etc
Note that Carry Flag survives the dec
and loop
instructions.