flat assembler
Message board for the users of flat assembler.

flat assembler > DOS > X2B -- hex string to binary string

Author
Thread Post new topic Reply to topic
rugxulo



Joined: 09 Aug 2005
Posts: 2279
Location: Usono (aka, USA)
So when working on my (extremely simple) HEX program, it was grabbing hex (supporting uppercase only) using a bunch of comparisons/jumps, which I think is correct but banal and inefficient. (Although I swear jumps aren't nearly as bad as people claim, but minimizing them isn't the worst idea either.)

I had an older (naive, pathetic) number base converter program that had some mini-routine (cryptic) hex conversion that I must've gleaned from someone else ("cmp al,40h", "adc al,69h", "daa"). It does work, but again, uppercase only (so I have to massage input first).

So, in that line of thinking, I built up this simple example to test it. I was trying to find a (slightly) "better" way ... although there is no (obvious to me, yet) "perfect" way.

The validate routine is because it's too annoying having to be precise to avoid invalid chars. (Even avoiding extra blanks is practically mandatory.) Plus, only accepting uppercase is confusing (esp. without errorchecking! any input translated to incorrect output, without warning, isn't helpful!). Building the table at runtime is because it felt braindead to supply 256 bytes of bloat just for this (esp. when the whole program is smaller than that).

The two versions of writebin weren't necessary, but I felt the old, naive way was too ad hoc and sloppy. (Simple testing doesn't show much speed difference, roughly only 2% improvement, so it's not worth worrying. Same with size, it matters little because it's all wasting 512 bytes minimum anyways. But I left it for completeness.)

And no, in the .ASM I didn't bother mashing multiple instructions together (like my shorter hexdump variant) because, although the lines here are criminally short, it's harder to understand the program otherwise.

x2b.asm :
Code:
; X2B.ASM -- hex to binary converter ; ; rugxulo _AT_ gmail ; ; public domain, free for any use, nenies proprajho, "Christus Rex!" VALIDATE=1 ARGV=81h CR=13 LF=10 PUTC=2 WRITESTR=9 DOS equ int 21h GOODBYE equ int 20h b equ byte w equ word ; .text org 100h Komenco: mov di,ARGV cmp b[di],CR jz Fino xor ch,ch mov cl,b[di-1] inc cl .skiplead: mov al,' ' push cx rep scasb pop cx dec di cmp b[di],CR jz Fino mov si,di .skiptrail: mov bx,cx lea di,[bx+ARGV-2] std rep scasb cld mov b[di+2],CR .begin: if defined VALIDATE call validate end if call readhex call writebin Fino: GOODBYE if defined VALIDATE validate: push si xor bh,bh mov ax,CR shl 8 + CR mov cx,256/2 mov di,table rep stosw mov cx,10 mov ax,'00' call fill mov cx,6 mov ax,'AA' call fill mov cx,6 mov ax,'Aa' call fill mov bx,table pop si ret fill: mov bl,ah lea di,[table+bx] .char: stosb inc al loop .char ret end if readhex: mov di,value xor dx,dx .nibble: lodsb if defined VALIDATE xlatb end if cmp al,CR jz .bye cmp al,40h adc al,69h daa cmp al,10 cmc sbb cl,cl and cl,6 sub al,cl repeat 4 rcl w[di],1 rcl w[di+2],1 end repeat xor ah,ah add w[di],ax adc w[di+2],0 inc dx cmp dx,8 jnz .nibble .bye: ret writebin: if defined OLD mov ah,PUTC mov cx,32 .bit: mov dl,'0' shl w[di+2],1 adc dl,0 shl w[di],1 adc w[di+2],0 DOS loop .bit mov dl,CR DOS mov dl,LF DOS ret else mov cx,32 push cx di mov si,binstr mov di,si mov al,'0' rep stosb mov ax,LF shl 8 + CR stosw mov b[di],'$' pop di cx .bit: lodsb shl w[di+2],1 adc b[si-1],0 shl w[di],1 adc w[di+2],0 loop .bit .print: mov ah,WRITESTR mov dx,binstr DOS ret end if ; .data value dd 0 ; .bss binstr rb 32+2+1 table rb 256 ; EOF


I also (weakly) tried to verify the correctness with some REXX scripts:

x2btest.rex :
Code:
/* REXX */ parse version v ; say v ; say parse arg num ; if num='' then num=512 say 'Random iterations:' num ; say call time 'r' do num; call binary ; end endtime=format(time(e),,2) md5sum '*.out' say ; say 'Elapsed time:' endtime 'secs.' exit binary: procedure str='' do random(1,8) ; str = str || d2x(random(0,15)) ; end call lineout 'rexx.out',copies('0',32-length(x2b(str)))x2b(str) 'x2b.com' str '>>asm.out' return


x2btest2.rex :
Code:
/* REXX */ say ; parse version v ; say v ; say parse arg list.0 ; if list.0='' then list.0=512 say 'Random iterations:' list.0 ; say do i=1 to list.0;list.i=hexstr();end; say '...done generating...' call timeit 'x2b' ; call timeit 'old' md5sum '*.out' ; say exit timeit: parse arg me ; call time 'r' do i=1 to list.0 ; me'.com' list.i'>>'me'.out' ; end say me'.com = elapsed:' format(time(e),,2) 'secs.' return hexstr: procedure str='' ; do random(1,8) ; str = str || d2x(random(0,15)) ; end return str
Post 20 Sep 2016, 04:24
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2279
Location: Usono (aka, USA)
So the opposite of X2B is B2X (binary to hex). This should be simpler to implement.

N.B. The "perfect" way I was talking about was trying to avoid (too many, unnecessary) jumps. I have no idea if it would really be "faster" (or even smaller), even compared to boring XLATB, but it still seemed wise to attempt (see VALIDHEX.ASM far below).

Even though I didn't really use/need them here, I now have a newfound appreciation for (386+) SETcc, BT, SHLD, etc.

Code:
; B2X.ASM -- binary string to hex string converter ; ; rugxulo _AT_ gmail ; ; public domain, free for any use, nenies proprajho, "Christus Rex!" ARGV=81h CR=13 LF=10 PUTC=2 DOS equ int 21h GOODBYE equ int 20h b equ byte w equ word org 100h Komenco: mov di,ARGV cmp b[di],CR jz Fino xor ch,ch mov cl,b[di-1] inc cx .skiplead: mov al,' ' push cx rep scasb pop cx dec di cmp b[di],CR jz Fino mov si,di .skiptrail: mov bx,cx lea di,[bx+ARGV-2] std rep scasb cld mov b[di+2],CR .begin: call readbin call writehex Fino: GOODBYE readbin: mov cx,32 xor dx,dx xor bx,bx .bit: lodsb if defined USE_QUOTE cmp al,'''' jz .bit end if cmp al,'1'+1 cmc sbb di,di cmp al,'0' push si sbb si,si or di,si pop si test di,di jnz .bye shr al,1 rcl bx,1 rcl dx,1 loop .bit .bye: ret writehex: mov ax,dx or ax,bx test ax,ax jz .bye xchg ax,dx call hexword xchg ax,bx call hexword mov al,CR call putchar mov al,LF call putchar .bye: ret hexword: mov cx,404h .nibble: rol ax,cl push ax and al,0Fh cmp al,10 sbb al,69h das call putchar pop ax dec ch jnz .nibble ret putchar: push ax mov ah,PUTC mov dl,al DOS pop ax ret ; EOF


validhex.asm :
Code:
PUTC=2 DOS equ int 21h GOODBYE equ int 20h macro AAM16 { mov ah,al and al,15 mov cl,4 shr ah,cl } macro NIB2ASC { cmp al,10 sbb al,105 das } org 100h Komenco: mov cx,256 ; max chars (0-255) xor ax,ax ; start at '\0' (NUL) .isvalid: push ax cx call validate pop cx ax inc ax loop .isvalid Fino: GOODBYE validate: ; IF (k IN ['0'..'9']) AND (k IN ['a'..'f']) AND (k IN ['A'..'F']) ; mov cx,('9' shl 8) + '0' mov cx,'09' push cx call rangecheck sbb bx,bx push bx mov cx,'af' push cx call rangecheck sbb bx,bx push bx mov cx,'AF' push cx call rangecheck sbb bx,bx .combine: pop cx and bx,cx pop cx and bx,cx test bx,bx jz outhex ret rangecheck: ; in: (upper_limit shl 8) + lower_limit pop bp pop bx ; mov bx,[sp+2] push bp .check: ; int3 cmp al,bl sbb ch,ch inc bh cmp al,bh cmc sbb bl,bl or bl,ch cmp bl,1 ; set CF if BL == 0 cmc ; return NC if AL within valid range ret outhex: ; int3 mov cx,'!~' ; also don't print space, aka isgraph() push cx call rangecheck jnc .show .split: ; int3 AAM16 .showhex: xchg ah,al NIB2ASC call putchar mov al,ah NIB2ASC .show: call putchar mov al,' ' call putchar .bye: ret putchar: push ax mov ah,PUTC mov dl,al DOS pop ax ret


b2xtest.rex :
Code:
/* REXX */ maxhexstr=8 ; maxbinstr=32 parse version v ; say v ; say parse arg num ; if num='' then num=512 say 'Random iterations:' num ; say call time 'r' do i=1 to num if /* (i // 1000)=0 */ right(i,3) == '000' then call charout ,'.' call binary end endtime=format(time(e),,2) md5sum '*.out' say ; say 'Elapsed time:' endtime 'secs.' exit binary: procedure expose maxhexstr maxbinstr do until str \= 0 str='' ; do random(1,maxbinstr) ; str = str || random(0,1) ; end end call lineout 'rexx.out',copies('0',maxhexstr-length(b2x(str)))b2x(str) 'b2x.com' str '>>asm.out' return
Post 23 Sep 2016, 00:01
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2279
Location: Usono (aka, USA)
Code:
; X2D.ASM -- hex string to decimal string converter ; ; rugxulo _AT_ gmail ; ; public domain, free for any use, nenies proprajho, "Christus Rex!" ;COMMAS=1 VALIDATE=1 ARGV=81h CR=13 LF=10 PUTC=2 DOS equ int 21h GOODBYE equ int 20h b equ byte w equ word ; .text org 100h Komenco: mov di,ARGV cmp b[di],CR jz Fino xor ch,ch mov cl,b[di-1] inc cx .skiplead: mov al,' ' push cx rep scasb pop cx dec di cmp b[di],CR jz Fino mov si,di .skiptrail: mov bx,cx lea di,[bx+ARGV-2] std rep scasb cld mov b[di+2],CR .begin: if defined VALIDATE call validate end if call readhex call writedec Fino: GOODBYE if defined VALIDATE validate: push si xor bh,bh mov ax,CR shl 8 + CR mov cx,256/2 mov di,table push di rep stosw mov cl,10 mov ax,'00' call fill mov cl,6 mov ax,'AA' call fill mov cl,6 mov ax,'Aa' call fill pop bx ; table pop si ret fill: mov bl,ah lea di,[table+bx] .char: stosb inc al loop .char ret end if readhex: mov di,value xor dx,dx .nibble: lodsb if defined VALIDATE xlatb end if cmp al,CR jz .bye cmp al,40h adc al,69h daa cmp al,10 cmc sbb cl,cl and cl,6 sub al,cl repeat 4 rcl w[di],1 rcl w[di+2],1 end repeat xor ah,ah add w[di],ax adc w[di+2],0 inc dx cmp dx,8 jnz .nibble .bye: ret bin2dec: mov cx,10 mov si,decstr xor di,di .start: xchg ax,dx push dx xor dx,dx div cx xchg ax,bx pop ax div cx xchg dx,bx or bl,'0' mov b[si],bl inc di cmp di,3 jb .no_comma if defined COMMAS inc si mov b[si],',' xor di,di end if .no_comma: inc si test dx,dx jnz .start test ax,ax jnz .start dec si cmp b[si],',' jz .bye inc si .bye: mov b[si],al dec si ret writedec: mov dx,w[di+2] mov ax,w[di] call bin2dec lea cx,[si-decstr+1] std .load: lodsb xchg ax,dx mov ah,PUTC DOS loop .load cld mov dl,CR DOS mov dl,LF DOS ret ; .data value dd 0 ; .bss decstr rb 10+3 table rb 256 ; EOF


x2dtest.rex :
Code:
/* REXX */ maxhexstr=8 ; maxdecstr=10 ; numeric digits maxdecstr parse version v ; say v ; say parse arg num ; if num='' then num=512 say 'Random iterations:' num ; say call time 'r' do i=1 to num if /* (i // 1000)=0 */ right(i,3)=='000' then call charout ,'.' call decimal end endtime=format(time(e),,2) md5sum '*.out' say ; say 'Elapsed time:' endtime 'secs.' exit decimal: procedure expose maxhexstr maxdecstr str='';do random(1,maxhexstr);str=str || d2x(random(0,15));end call lineout 'rexx.out',x2d(str) 'x2d.com' str '>>asm.out' return
Post 24 Sep 2016, 22:11
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2279
Location: Usono (aka, USA)
Code:
; D2X.ASM -- decimal string to hex string converter ; ; rugxulo _AT_ gmail ; ; public domain, free for any use, nenies proprajho, "Christus Rex!" ;COMMA=1 ARGV=81h CR=13 LF=10 PUTC=2 DOS equ int 21h GOODBYE equ int 20h b equ byte w equ word macro MUL10 { repeat 2 ; x4 shl ax,1 rcl dx,1 end repeat add ax,[di] ; add original x1 (= x5) adc dx,[di+2] shl ax,1 ; x2 rcl dx,1 ; = x10 } org 100h Komenco: mov di,ARGV cmp b[di],CR jz Fino xor ch,ch mov cl,b[di-1] inc cx .skiplead: mov al,' ' push cx rep scasb pop cx dec di cmp b[di],CR jz Fino mov si,di .skiptrail: mov bx,cx lea di,[bx+ARGV-2] std rep scasb cld mov b[di+2],CR .begin: call readdec call writehex Fino: GOODBYE readdec: mov cx,10 xor dx,dx .bit: lodsb if defined COMMA cmp al,',' jz .bit end if cmp al,'0' sbb di,di cmp al,'9'+1 cmc push si sbb si,si or di,si pop si test di,di jnz .bye xor ah,ah mov di,value aaa xchg ax,bx mov ax,[di] mov dx,[di+2] MUL10 add ax,bx adc dx,0 stosw xchg ax,dx stosw loop .bit .bye: ret writehex: mov ax,w[value+2] call hexword mov ax,w[value] call hexword mov al,CR call putchar mov al,LF jmp putchar .bye: ret hexword: mov cx,404h .nibble: rol ax,cl push ax and al,0Fh cmp al,10 sbb al,105 das call putchar pop ax dec ch jnz .nibble ret putchar: push ax mov ah,PUTC mov dl,al DOS pop ax ret value dd 0 ; EOF


d2xtest.rex :
Code:
/* REXX */ maxhexstr=8 ; maxdecstr=10 ; numeric digits maxdecstr parse version v ; say v ; say parse arg num ; if num='' then num=512 say 'Random iterations:' num ; say call time 'r' do i=1 to num if /* (i // 1000)=0 */ right(i,3) == '000' then call charout ,'.' call number end endtime=format(time(e),,2) md5sum '*.out' say ; say 'Elapsed time:' endtime 'secs.' exit number: procedure expose maxhexstr maxdecstr do until str <= 2**32-1 str='';do random(1,maxdecstr);str=str || random(0,maxdecstr-1);end end call lineout 'rexx.out',copies('0',maxhexstr-length(d2x(str)))d2x(str) 'd2x.com' str '>>asm.out' return
Post 25 Sep 2016, 21:07
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 2004-2018, Tomasz Grysztar.

Powered by rwasa.