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: 2341
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 bdi,CR
  jz Fino
  xor ch,ch
  mov cl,bdi-1
  inc cl
.skiplead
  mov al,' '
  push cx
  rep scasb
  pop cx
  dec di
  cmp bdi,CR
  jz Fino
  mov si,di
.skiptrail
  mov bx,cx
  lea di,bx+ARGV-2
  std
  rep scasb
  cld
  mov bdi+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 wdi,1
  rcl wdi+2,1
end repeat

  xor ah,ah
  add wdi,ax
  adc wdi+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 wdi+2,1
  adc dl,0
  shl wdi,1
  adc wdi+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 bdi,'$'
  pop di cx
.bit
  lodsb
  shl wdi+2,1
  adc bsi-1,0
  shl wdi,1
  adc wdi+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=formattimee,,2
md5sum '*.out'
say ; say 'Elapsed time' endtime 'secs.'
exit

binary procedure
  str=''
  do random1,8 ; str = str || d2xrandom0,15 ; end
  call lineout 'rexx.out',copies'0',32-lengthx2bstrx2bstr
  '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' formattimee,,2 'secs.'
  return

hexstr procedure
  str='' ; do random1,8 ; str = str || d2xrandom0,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: 2341
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 bdi,CR
  jz Fino
  xor ch,ch
  mov cl,bdi-1
  inc cx
.skiplead
  mov al,' '
  push cx
  rep scasb
  pop cx
  dec di
  cmp bdi,CR
  jz Fino
  mov si,di
.skiptrail
  mov bx,cx
  lea di,bx+ARGV-2
  std
  rep scasb
  cld
  mov bdi+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 */ righti,3 == '000' then call charout ,'.'
  call binary
end
endtime=formattimee,,2
md5sum '*.out'
say ; say 'Elapsed time' endtime 'secs.'
exit

binary procedure expose maxhexstr maxbinstr
  do until str \= 0
    str='' ; do random1,maxbinstr ; str = str || random0,1 ; end
  end
  call lineout 'rexx.out',copies'0',maxhexstr-lengthb2xstrb2xstr
  '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: 2341
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 bdi,CR
  jz Fino
  xor ch,ch
  mov cl,bdi-1
  inc cx
.skiplead
  mov al,' '
  push cx
  rep scasb
  pop cx
  dec di
  cmp bdi,CR
  jz Fino
  mov si,di
.skiptrail
  mov bx,cx
  lea di,bx+ARGV-2
  std
  rep scasb
  cld
  mov bdi+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 wdi,1
  rcl wdi+2,1
end repeat

  xor ah,ah
  add wdi,ax
  adc wdi+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 bsi,bl
  inc di
  cmp di,3
  jb .no_comma
if defined COMMAS
  inc si
  mov bsi,','
  xor di,di
end if
.no_comma
  inc si
  test dx,dx
  jnz .start
  test ax,ax
  jnz .start
  dec si
  cmp bsi,','
  jz .bye
  inc si
.bye
  mov bsi,al
  dec si
  ret

writedec
  mov dx,wdi+2
  mov ax,wdi
  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 */ righti,3=='000' then call charout ,'.'
  call decimal
end
endtime=formattimee,,2
md5sum '*.out'
say ; say 'Elapsed time' endtime 'secs.'
exit

decimal procedure expose maxhexstr maxdecstr
  str='';do random1,maxhexstr;str=str || d2xrandom0,15;end
  call lineout 'rexx.out',x2dstr
  '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: 2341
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 bdi,CR
  jz Fino
  xor ch,ch
  mov cl,bdi-1
  inc cx
.skiplead
  mov al,' '
  push cx
  rep scasb
  pop cx
  dec di
  cmp bdi,CR
  jz Fino
  mov si,di
.skiptrail
  mov bx,cx
  lea di,bx+ARGV-2
  std
  rep scasb
  cld
  mov bdi+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,wvalue+2
  call hexword
  mov ax,wvalue
  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 */ righti,3 == '000' then call charout ,'.'
  call number
end
endtime=formattimee,,2
md5sum '*.out'
say ; say 'Elapsed time' endtime 'secs.'
exit

number procedure expose maxhexstr maxdecstr
  do until str <= 2**32-1
    str='';do random1,maxdecstr;str=str || random0,maxdecstr-1;end
  end
  call lineout 'rexx.out',copies'0',maxhexstr-lengthd2xstrd2xstr
  '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 © 1999-2019, Tomasz Grysztar.

Powered by rwasa.