I needed an algo of subj recently. Examining of a2dw proc in masm package I found it pretty slow and inconvinient (it is don't handle such combination as "AbCd1234"). I decide to write my own algo (inspired by simple algo of Hex2str with sbb and das). Idea was to avoid branching as possible, but maybe someone have less branching :)


.data
String db "AbCd1234",0
.code
start:
mov esi, offset String
mov ecx, 8
xor ebx, ebx
@@next:
shl ebx, 4
mov al, [esi]
cmp al, 61h
jl @@big_symbol
sub al, 20h
@@big_symbol:
cmp al, 40h
je @@fine
sbb al, 0C9h
das
cmp al, 10h
jc @@exit
sub al, 8
@@exit:
cmp al, 10h
jge @@fine
or ebx, eax
inc esi
dec ecx
jcxz @@finish
jmp @@next
@@fine:
xor eax, eax
dec eax
@@finish:
mov eax, ebx
Posted on 2002-03-22 02:08:56 by masquer


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

htodw proc FORCENOFRAME

ptHexString equ [esp+4]
mov ecx,ptHexString
xor eax,eax
ALIGN 4
htodw_loop:
mov dl,[ecx]
inc ecx
sub dl,"0"
js htodw_endloop
shl eax,4
cmp dl,9
jbe htodw_addnumber
sub dl,"a" - "0" - 10
jns htodw_addnumber
add dl,20h
htodw_addnumber:
xor al,dl
jmp htodw_loop

htodw_endloop:
ret 4
htodw endp

OPTION PROLOGUE:DEFAULTOPTION
OPTION EPILOGUE:DEFAULTOPTION
Posted on 2002-03-22 03:28:15 by The Svin
Thanks Svin (I mean "Spasibo" :))

Your algo is simpler to follow. As I see less than 4 JXX is impossible to implement.
What's mean FORCENOFRAME
Posted on 2002-03-22 03:44:12 by masquer
As I see less than 4 JXX is impossible to implement

Possible if only capital (ABCDEF) allowed whole algo maybe done with just one jcc.
FORCENOFRAME - force masm not to make stack frame after proc statement.
Posted on 2002-03-22 04:09:04 by The Svin
The same but shorter and faster..


mov ecx,lpString
xor eax,eax
jmp L_3
L_1:
and dl,1Fh
add dl,9
L_2:
shl eax,4
or al,dl
L_3:
mov dl,[ecx]
inc ecx
sub dl,40h
jnc L_1
add dl,10h
jns L_2
ret
Posted on 2002-03-22 13:49:09 by buliaNaza
I like it. Especially size.
Posted on 2002-03-22 14:09:50 by The Svin
Thanks The_Svin but I don't like it..So..
	mov  ecx, lpString

xor eax,eax
L_1:
mov dl, [ecx]
inc ecx
shl eax,4
cmp dl, 40h
sbb ebx, ebx
and ebx, 7
lea edx,[edx+ebx-37h]
and edx, 1Fh
add al, dl
jnc L_1
shr eax, 4
ret
Posted on 2002-03-22 21:48:59 by buliaNaza
Very well done, Naza!
I add your code to my collection.
To exchange ideas.
IMHO when not capital letters used in HEX strings they look ugly,
for example 1abcF4c6h instead of 1ABCF4C6h,
so I use (and allow user to use) only capital ones.
The following code is another way to do the convertion
but it expect only capital letters:
(btw I would call your code perfect if not one needless
iteration, please find way out to remove this one needless
iteration, i'm sure you can do it)


mov ebx,lpString
xor edx,edx
xor eax,eax

@@: mov dl,[ebx] ;1
shl eax,4 ;0
cmp dl,41h ;1
inc ebx ;0
sbb cl,cl ;1
sub dl,'A'-0Ah ;0
and cl,7 ;1
add dl,cl ;1
cmp byte ptr [ebx],dh ;0
lea eax,[eax][edx] ;1
jne @B ;1
Posted on 2002-03-23 02:13:27 by The Svin
Naza, you code doesn't work.
I check it with db 'A1B2C3F0',0
your proc never end it's loop.
And of course shr eax,4 wouldn't ever allow highest digit
even if it your find a way to end loop in better way.
Posted on 2002-03-23 03:21:20 by The Svin
Naza,
I made m32lib format proc from your code,
it's now exit loop right way and doesn't waste one iteration and
allow high digit in eax,
Let me know, please, if you figure out how to it better way:


;#########################################
; --------------------------------------
; This procedure was written by buliaNaza
; --------------------------------------

.386
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive

.code

;#########################################

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

htodw proc FORCENOFRAME

ptHexString equ [esp+4]
mov ecx, ptHexString
xor eax,eax
push ebx
L_1:
mov dl, [ecx]
inc ecx
shl eax,4
cmp dl, 40h
sbb ebx, ebx
and ebx, 7
lea edx,[edx+ebx-37h]
and edx, 1Fh
add al, dl
cmp byte ptr [ecx],dh
jne L_1
; shr eax, 4
pop ebx
ret 4
htodw endp

OPTION PROLOGUE:DEFAULTOPTION
OPTION EPILOGUE:DEFAULTOPTION

; #########################################
end
Posted on 2002-03-23 03:46:27 by The Svin
Thanks The_Svin for replay but I NEVER:
- preserve registers in my programs without a need
- use stupid calling "conventions".. Why push,push,push and then pop,pop,pop?
- HLL crap (INVOKE, PROC, ENDP, LOCAL) etc.
- "standard" constructions as:


invoke GetModuleHandle, NULL
mov hInstance, eax
invoke WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,eax ; Why 3 additional calls?

- in my import table I have only one entry (W2k/XP needs it) and my programs are loaded faster..
- ...
Sorry but haven't time for more..


My_htodw:
mov ecx, lpString
xor eax, eax
xor edx, edx
;jmp L_2
L_1:
shl eax,4
and edx, 0Fh
add eax,edx
;L_2:
mov dl,[ecx]
;movzx edx,byte ptr [ecx]
inc ecx
cmp edx,40h
sbb ebx,ebx
sub edx,37h
and ebx,7
add edx, ebx
jns L_1
ret

U can compare my code against a Jens Duttke's algo here:
Posted on 2002-03-23 09:58:39 by buliaNaza
Is a non-branching version possible with MMX?
Posted on 2002-03-23 11:24:22 by bitRAKE
Thanks The_Svin for replay but I NEVER:

It's fine with me,Naza :)
The only important things were:
1. How to exit loop
2. Allow high digit in eax
3. Eliminate one needless iteration.
That what I asked you to figure out better then in my temporary
solution.
The rest is just format you are free to change.

U can compare my code against a Jens Duttke's algo


I always study carefully any code you post :)
- "standard" constructions as:

I hate such a code too.
Written by people who just don't know what and why they write.
Posted on 2002-03-23 12:36:30 by The Svin
buliaNaza,
Your code looks much better now, less dependences and
no bugs.
I have just couple simple questions.
Could you explain, please:
Why add ecx,1 instead of inc ecx (3 bytes instead of 1?)
and why and edx,1Fh? (and edx,0Fh?)
Posted on 2002-03-23 13:17:21 by The Svin
Is a non-branching version possible with MMX?

I think it is possible, and not only with MMX,
but in one condition:
Number of symbols is known by strick format, for example 8 symbols.
so never 012 0 or F0F123
always 00000012 00000000 00F0F123
then IMHO mask algo can be worked out.
Posted on 2002-03-23 13:23:10 by The Svin

Is a non-branching version possible with MMX?


Neat mask apeals for carefull numeric work with bright and free head and free time wich I don't have now :)
But here is some akward ideas for starter.
Assume that hex string is in 8 bytes strick format and only capital (ABCDEF) allowed:


.data
lpString db 'A1B2C3F0',0
notdec dq 4040404040404040h
subdec dq 3030303030303030h
sublet dq 3737373737373737h
.code
start:
movq mm(3),qword ptr lpString
movq mm(1),notdec
movq mm(2),mm(3);mm2 string
pxor mm(0),mm(0)
psubusb mm(3),mm(1)
movq mm(4),subdec
pcmpeqb mm(3),mm(0);mm3 zero letters
movq mm(5),sublet
pcmpeqb mm(0),mm(3);mm0 zero figures
movq mm(1),mm(2);mm1 string
psubusb mm(2),mm(4);sub for figures
psubusb mm(1),mm(5);sub for letters
pand mm(2),mm(3)
pand mm(1),mm(0)
por mm(2),mm(1)


Up tp this end we have all digits one per byte in mm2
Now we need bright idea how to pack them into dword
one digit per each tetrada :)
Any interesting ideas?
Posted on 2002-03-23 16:22:04 by The Svin
movq mm0,mm2          ; 08090A0B0C0D0E0F

movq mm1,mm2 ; 08090A0B0C0D0E0F
pand mm0,mxc(<0F00>[b][/b]) ; 08000A000C000E00
pand mm1,mxc(<000F>[b][/b]) ; 0009000B000D000F
psrlq mm0,8 ; 0008000A000C000E
; could double up here and do two dwords at once :)
packuswb mm0,mm0 ; 080A0C0E
packuswb mm1,mm1 ; 090B0D0F
psllq mm0,4 ; 80A0C0E0
por mm0,mm1 ; 89ABCDEF
movd eax,mm0
Now we just need to mask off the characters before the hex digits that aren't valid, but I quickly see we are going to have problems like "Temp4,0x1234" - if there is a digit in the preceeding bytes we have a problem.
Posted on 2002-03-23 17:20:00 by bitRAKE
It works! We are close to magic birth :)
Two minor things:
1. We need bswap eax at the end
2. We don't need copy mm2 into two mmx reg since we can use mm2 itself.
And I think it's easy to add end up code so the proc can be used with var size of hex string
something like:
mov edx,lpString
mov ecx,-4
@@: add ecx,4
cmp byte ptr ,1
inc edx
jnc @B
shr eax,cl
Posted on 2002-03-23 17:58:06 by The Svin
found I more error


lpString db 'A1B2C3F0',0
notdec dq 4040404040404040h
subdec dq 3030303030303030h
sublet dq 3737373737373737h
.code
start:
movq mm(3),qword ptr lpString
movq mm(1),notdec
movq mm(2),mm(3);mm2 string
pxor mm(0),mm(0)
psubusb mm(3),mm(1)
movq mm(4),subdec
pcmpeqb mm(3),mm(0);mm3 zero letters
movq mm(5),sublet
pcmpeqb mm(0),mm(3);mm0 zero figures
movq mm(1),mm(2);mm1 string
psubusb mm(2),mm(4);sub for figures
psubusb mm(1),mm(5);sub for letters
pand mm(2),mm(3)
pand mm(1),mm(0)
por mm(2),mm(1)
movq mm0,mm2 ; 08090A0B0C0D0E0F
; movq mm1,mm2 ; 08090A0B0C0D0E0F
pand mm2,mxc(<000F> ) ; 0009000B000D000F
pand mm0,mxc(<0F00> ) ; 08000A000C000E00
packuswb mm2,mm2 ; 090B0D0F
psrlq mm0,8 ; 0008000A000C000E
psllq mm2,4
packuswb mm0,mm0 ; 080A0C0E

; psllq mm0,4 ; 80A0C0E0

por mm0,mm2 ; 89ABCDEF
movd eax,mm0
bswap eax
Posted on 2002-03-23 18:23:10 by The Svin
StrHex2bin PROC

_CONST SEGMENT
lpString db "89aBcDeF"
_CONST ENDS

movq mm0,QWORD PTR [lpString]

psubusb mm0,mxc(<30>[b][/b]) ; "0" = 0
movq mm1,mm0

pcmpgtb mm1,mxc(<09>[b][/b]) ; letter?
pand mm1,mxc(<07>[b][/b])

psubusb mm0,mm1 ; fix letters

movq mm1,mm0 ; .F.E.D.C.B.A.9.8
psrlq mm0,8 ; ...F.E.D.C.B.A.9
pand mm1,mxc(<000F>[b][/b]) ; ...E...C...A...8
pand mm0,mxc(<000F>[b][/b]) ; ...F...D...B...9

packuswb mm1,mm1 ; .E.C.A.8
packuswb mm0,mm0 ; .F.D.B.9
psllq mm1,4 ; E.C.A.8.
por mm0,mm1 ; EFCDAB89
movd eax,mm0 ; EFCDAB89

bswap eax ; 89ABCDEF
ret
StrHex2bin ENDP
What was the other error?
What do you think of my mxc macro? :)
http://www.asmcommunity.net/board/index.php?topic=3801

Edit: I've fixed the error, and the comments to better understand what is happening, and rearranged a couple instructions for less data usage. Of course, all the constants could be in registers. :)
Posted on 2002-03-23 18:40:08 by bitRAKE