Today I needed a function to convert a decimal string (8 bit ascii) into a binary value with 64-bit precision.
OA32 didn't have one, so I threw this together.
If anyone feels like writing a better version, I'll replace it... but it seems to work ok for what I needed.
OA32 didn't have one, so I threw this together.
If anyone feels like writing a better version, I'll replace it... but it seems to work ok for what I needed.
;Cheap and nasty proc to convert decimal string to QWORD in EDX::EAX
.data
multipliers qword 1, 10, 100, 1000, 10000, 100000,1000000,10000000,100000000,1000000000,10000000000
qword 100000000000,1000000000000,10000000000000,100000000000000,1000000000000000
qword 10000000000000000, 100000000000000000, 1000000000000000000, 10000000000000000000
.code
dec2qword proc uses esi ebx pString
LOCAL Accum:qword
LOCAL sign, cnt
qdmov Accum,0
mov sign,+1
mov esi, pString
.if byte ptr=="-"
mov sign,-1
inc esi
.elseif byte ptr=="+"
inc esi
.endif
invoke lstrlen,esi
add esi,eax
dec esi
mov cnt,eax
xor ebx,ebx
.while ebx<cnt
push ebx
mov eax,ebx
shl eax,3 ;*sizeof qword
lea edx, multipliers
add eax,edx
mov edx,.QuadWord.HiDWord
mov eax,.QuadWord.LoDWord
push eax
movzx eax,byte ptr
sub al,30h
mov ebx,eax
pop eax
qdmul
qqadd Accum, edx::eax
dec esi
pop ebx
inc ebx
.endw
.if sign==-1
mov eax,Accum.QuadWord.LoDWord
mov edx,Accum.QuadWord.HiDWord
mov Accum.QuadWord.LoDWord,0
mov Accum.QuadWord.HiDWord,0
qqsub Accum, edx::eax
.endif
mov eax,Accum.QuadWord.LoDWord
mov edx,Accum.QuadWord.HiDWord
ret
dec2qword endp
Not claiming that mine is better, but I wrote these a few years ago. I'll just link them here for comparison's sake:
http://srcvault.scali.eu.org/cgi-bin/Syntax/Syntax.cgi?ParseRadix.asm
http://srcvault.scali.eu.org/cgi-bin/Syntax/Syntax.cgi?PrintRadix.asm
Edit: one idea that may be useful is that my routines try to use 32-bit operations where possible, and only use full 64-bit arithmetic when required.
They can also be used for any radix, so you can use this routine for binary, octal, decimal, hexadecimal etc, by simply specifying 2, 8, 10 or 16 as radix.
http://srcvault.scali.eu.org/cgi-bin/Syntax/Syntax.cgi?ParseRadix.asm
http://srcvault.scali.eu.org/cgi-bin/Syntax/Syntax.cgi?PrintRadix.asm
Edit: one idea that may be useful is that my routines try to use 32-bit operations where possible, and only use full 64-bit arithmetic when required.
They can also be used for any radix, so you can use this routine for binary, octal, decimal, hexadecimal etc, by simply specifying 2, 8, 10 or 16 as radix.
A quick attempt:
The eax:edx negation needs improvement, I don't remember any ideas on how to do it.
The code is simply
Edit: correction "add eax,esi" -> "adc eax,esi".
correction 2: fixed the 64-bit negation as baldr noted.
udec2qword proc uses ebx ecx esi edi pString
xor eax,eax ; result LOW
xor edx,edx ; result HIGH
mov ebx,pString
movzx ecx,byte ptr
cmp ecx,'-'
je _negative
align 16 ; actually, better align the proc itself, and then tune the _again2 with _negative
_again:
sub ecx,'0'
mov esi,eax
mov edi,edx
cmp ecx,9
ja _done
add eax,eax
adc edx,edx
inc ebx
shld edi,esi,3
shl esi,3
add esi,ecx
movzx ecx,byte ptr
adc eax,esi ; ** correction, was ADD
adc edx,edi
jmp _again
_done:
ret
_negative:
inc ebx
movzx ecx,byte ptr
align 16
_again2:
sub ecx,'0'
mov esi,eax
mov edi,edx
cmp ecx,9
ja _done2
add eax,eax
adc edx,edx
inc ebx
shld edi,esi,3
shl esi,3
add esi,ecx
movzx ecx,byte ptr
adc eax,esi ; **** correction. Was ADD
adc edx,edi
jmp _again2
_done2:
printh edx
printh eax
;dec eax
;sbb edx,0
;xor eax,-1
;xor edx,-1
neg edx ; correction 2
neg eax
sbb edx, 0
ret
udec2qword endp
The eax:edx negation needs improvement, I don't remember any ideas on how to do it.
The code is simply
int64 result=0;
while(ecx=digit){
result = result*10 + ecx; // = result+result + (result*8) + ecx;
}
Edit: correction "add eax,esi" -> "adc eax,esi".
correction 2: fixed the 64-bit negation as baldr noted.
The eax:edx negation needs improvement
Definitely, because dec eax leaves CF intact. ;-)
Scali's functions contain right code for 64-bit neg; my multiple-precision (i.e. additional adc/negs can follow) variant is
neg eax
adc edx, 0
neg edx
Thanks :) . Fixed it.