This one is aimed at converting a 2-digit DWORD numeric value to a string value.
I don't think this is the best way of doing it...However, I need your experience to show me how to better do it



;first contains the DWORD no(max 99), second contains the address of the string

dw2numstr proc uses esi first:DWORD,second:DWORD

local temp1:BYTE
local temp2:BYTE

mov temp1,byte ptr 0
mov temp2,byte ptr 0
mov ecx,first

thisis:
cmp temp1,9
je incsecond
add temp1,1
dec ecx
cmp ecx,0
je endo
jmp thisis

incsecond:
cmp temp2,9
je endo
add temp2,1
mov temp1,byte ptr 0
dec ecx
cmp ecx,0
je endo
jmp thisis

endo:
xor eax,eax
add temp1,48
add temp2,48
mov ah,temp1
mov al,temp2
mov esi,second
mov word ptr[esi],ax
ret

dw2numstr endp
Posted on 2002-10-31 08:07:59 by hosam_shahin


dw2numstr PROC val:BYTE, pStr:DWORD
mov al, val
mov edx, pStr
aam

add ah, 48
add al, 48

mov [edx], ah
mov [edx + 1], al
mov BYTE PTR [edx + 2], 0
ret
dw2numstr ENDP
Posted on 2002-10-31 08:20:35 by Mirno
Thanx Mirno,
I didnt know that bit about 'aam', but inspiring now
Posted on 2002-10-31 09:55:39 by hosam_shahin
AAM is in fact a special division instruction which IIRC divides ax by a constant 8-bit number. It puts the result in ah and the remainder in al. That's why it's encoded as TWO bytes, 0d4h 0ah, the second byte is a '10'. Using this technique I believe limits you to 99.

Anyway to do dw2string conversions properly, you must first learn how division is done using the 'div' instruction. This is the algorithm:

put the number in an accumulator
loop1:
divide by 10
keep the result in the accumulator
keep the remainder in a buffer, add 48 to adjust to ASCII. NOTE: we will extract digits in REVERSE order, so you might want to load the buffer in REVERSE order.
if you're satisfied with the number of digits already processed, stop loop. Otherwise jmp to loop1

After the loop, you might want to strip leading zeros. If you didn't load the buffer in reverse, you also want to reverse it now.
Posted on 2002-10-31 21:27:54 by AmkG
AAM is not limited to 0xA:


AX=0029 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0100 NV UP EI PL NZ NA PO NC
0E9C:0100 D420 AAM 20
-t

AX=0109 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0102 NV UP EI PL NZ NA PE NC
0E9C:0102 D408 AAM 08
-t

AX=0101 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0104 NV UP EI PL NZ NA PO NC
0E9C:0104 EBFA JMP 0100


debug.exe will dissasemble 0xD4 0x08 as AAM 08, but won't assemble it.
Posted on 2002-11-01 01:21:01 by eet_1024
Anyway to do dw2string conversions properly, you must first learn how division is done using the 'div' instruction. This is the algorithm:

put the number in an accumulator
loop1:
divide by 10
keep the result in the accumulator
keep the remainder in a buffer, add 48 to adjust to ASCII. NOTE: we will extract digits in REVERSE order, so you might want to load the buffer in REVERSE order.
if you're satisfied with the number of digits already processed, stop loop. Otherwise jmp to loop1

After the loop, you might want to strip leading zeros. If you didn't load the buffer in reverse, you also want to reverse it now.


Several examples/ideas by chorus and I in this thread:

http://www.asmcommunity.net/board/index.php?topic=8605
Posted on 2002-11-01 03:32:36 by ThoughtCriminal
Mirno,

very clever idea aam :)

eet.1024,
then aam only works in AL, not AX or EAX?

ANd then what's the difference with aad?

(aas and aaa use the carry, are another kind)
Posted on 2002-11-01 07:26:22 by slop
I don't believe that AA and DA have 32bit versions.

The AAM and AAD instructions are very expensive:


AAD AAM
8086 60 83 Clock Cycles
80486 14 15 Clock Cycles


You're better off using shl for multiplies.


AAD: al = ah*Base + al
Note: Flag.AuxillaryCarry will be set if AL overflows (AH will still equal 0).



AX=3135 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0100 NV UP EI PL NZ NA PE NC
0E9C:0100 250F0F AND AX,0F0F
-t

AX=0105 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0103 NV UP EI PL NZ NA PE NC
0E9C:0103 D50A AAD
-t

AX=000F BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0105 NV UP EI PL NZ NA PE NC
0E9C:0105 B81001 MOV AX,0110
-t

AX=0110 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=0108 NV UP EI PL NZ NA PE NC
0E9C:0108 D508 AAD 08
-t

AX=0018 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0E9C ES=0E9C SS=0E9C CS=0E9C IP=010A NV UP EI PL NZ NA PE NC
0E9C:010A EBF4 JMP 0100
Posted on 2002-11-02 01:39:54 by eet_1024
eet, sure,

but 'in extremis' it could be done with streming SIMD, 4 or eight at a time, right?
Posted on 2002-11-05 06:56:34 by slop
Hosam,
I have included some code you might find useful in the attachment. It has a lot of bells and whistles, but maybe you can trim it down to the simpler needs you have. Ask, if you have any questions. Ratch
Posted on 2002-11-17 16:11:55 by Ratch
Thank you very much Ratch,:alright:
It is to become known that your code is very helpful as it is developed in great detail.
I used the main idea to write this routine to convert a DWORD value to a string one:



dw2str proc first:DWORD,second:DWORD
local temp:DWORD
MOV EAX,first
MOV temp,EAX
MOV EBX,10
MOV ECX,0
MOV ESI,second

loop1:
MOV EAX,temp
XOR EDX,EDX
DIV EBX ;~~~~~~~~~
MOV temp,EAX ;`````````
ADD EDX,48 ;
push EDX ;thanx Ratch
INC ECX ;
CMP EAX,0 ;`````````
JE endo
JMP loop1

endo:
MOV EDX,0
endo1:
POP EAX
MOV byte ptr [esi+edx],al
INC EDX
DEC ECX
CMP ECX,0
JNE endo1

MOV byte ptr[ESI+EDX],0
ret
dw2numstr endp



It might look bit compliacated, but I am not that professional yet!
Posted on 2002-11-17 18:18:33 by hosam_shahin
Evolving the code you posted:



dw2str proc USES EBX, ESI first:DWORD,second:DWORD
; - DONT NEED -> local temp:DWORD
MOV EAX,first
; - DONT NEED -> MOV temp,EAX
MOV EBX,10 ; Added USES EBX to proc because of this
XOR ECX, ECX ; <-Smaller opcode than -> MOV ECX,0
MOV ESI,second ; Added USES ESI to proc because of this

loop1:
; - DONT NEED -> MOV EAX,temp <- EAX will always be equal to temp
XOR EDX,EDX
DIV EBX
; - DONT NEED -> MOV temp,EAX
ADD EDX,48
push EDX
INC ECX
OR EAX, EAX ; <-Smaller opcode than -> CMP EAX,0
JNE loop1
; JE endo
; JMP loop1

XOR EDX, EDX ; <-Smaller opcode than -> MOV EDX,0
endo1:
POP EAX
MOV byte ptr [esi+edx],al
INC EDX
DEC ECX
; CMP not needed, DEC sets the zero flag CMP ECX,0
JNE endo1

MOV byte ptr[ESI+EDX],0
ret
dw2numstr endp


And then further:


dw2str proc USES ESI first:DWORD,second:DWORD
MOV EAX,first
MOV ECX,10
MOV ESI,second

@@:
XOR EDX,EDX
DIV ECX
ADD EDX,48
MOV byte ptr [ESI], DL
INC ESI
OR EAX, EAX
JNE @B

MOV byte ptr[ESI],0
ret
dw2numstr endp


Mirno
Posted on 2002-11-18 04:14:33 by Mirno
.:grin:
Thnx again Mirno,
I realy enjoyed your contributions.
Posted on 2002-11-18 10:26:13 by hosam_shahin
Wow Mirno, your last example is almost exactly like my code in the Useless optimization thread!! :tongue:


I did add some error checking and negative number support however.


I guess I'm finally starting to get good at this :grin:
Posted on 2002-11-18 12:40:11 by ThoughtCriminal