binary to ascii & ascii to binary cvt of # =< '999999999999'

Started by brookebree, August 24, 2010, 06:55:13 PM

Previous topic - Next topic

brookebree


I have a 16-bit assembly 'binary to ascii' routine and a 'ascii to binary' routine that both do conversions of max size
double-word  numbers (i.e, convert binary input =< 0ffffh 0ffffh passed in ax/dx registers to get ascii output returned
in buffer =< '4294967295',  OR  convert ascii input passed in buffer =< '4294967295' to get binary output =< 0ffffh 0ffffh
returned in ax/dx LSW/MSW).

I now need routines be able to handle ascii numbers =< '999999999999' or 00e8h d4a5h 0fffh in binary, or basicly
3 words iin size (althought I'll really only need to use the lower order byte of the additional 3rd word).  With this size number
I obviously would need to use the lower order byte of some other register,  say bx for the  binary convertion output
to registers, i.e. if passed ascii input of  '999999999999', output would be returned as ax=0fffh, dx=0d4a5h, bx=00e8h. 
And the reverse in other routijne, if passed binary input =< ax=0fffh, dx=0d4a5h, bx=00e8h,  outut returned would be =< '999999999999'

Anybody got any .asm routines that will accomplish these 3-word binary/asciii conversions that they want to share
with me?

Thanks in advance - Dale






dedndave

well - offhand, i don't have a 16-bit version
but, as a suggestion, you might like "Horner's Rule" (or Ling Long Kai Fang, as i prefer to call it)
you should be able to find references with google

as you read each byte, AND it with 0Fh to convert it from ASCII to binary, then....
basically, you grab the first byte in the string, multiply it by 10 (provided it isn't the last byte), then store that as the accumlator
then grab the next byte and repeat
when you grab the last byte and add it to the accumulator, do not multiply by 10 - you are done
the trouble you will have with such large numbers in 16-bit is multiplying by 10
you can use multiple precision multiplication, or shift and add
for this size, i would think shift and add might be fastest

shift the entire accumulator left by 1 bit (this is accum X 2)
make a copy of the entire accumulator
shift one of the 2 copies left by 2 more bits (this is accum X 8)
add the 2 copies together and the total represents the accumulator X 10
as you can see, you need 5 16-bit registers, one of which is split in half

you might use BL:DX:AX for one
and BH:SI:DI for the other

multiply the contents of BL:DX:AX by 10
;multiply the accumulator by 2

        shl     ax,1
        rcl     dx,1
        rcl     bl,1

;make a copy of 2X accumulator in BH:SI:DI

        mov     di,ax
        mov     si,dx
        mov     bh,bl

;multiply the copy by 2 (4X accumulator)

        shl     di,1
        rcl     si,1
        rcl     bh,1

;multiply the copy by 2 again (8X accumulator)

        shl     di,1
        rcl     si,1
        rcl     bh,1

;add the two together (8X + 2X = 10X)

        add     ax,di
        adc     dx,si
        adc     bl,bh

dedndave


FORTRANS


brookebree

ascii number can be terminated with a null in the new ascii to binary routine, doesn't matter to me which.
The ascii number passed to existing double word routine I use assumes a left-justified, 20h terminated ascii
number, but can easily be changed to expect null terminated instead, just trying to keep new 3 word routine
pass/return parameters as close as possible to my existing double word routines.

My current double word ascii to binary: pass [si] = buf addr of max 10-digit =< 4294967295, L J, blank terminated ascii number
                                                     returns ax/dx = (lsw/msw) binary value

My current double word binary to ascii: pass ax/dx = (lsw/msw) binary value
                                                               [di] = 10 byte destination buf
                                                          returns  nothing (destination buf passed above is populated with ascii number)

dedndave

well - you can use TEST AL,0DFh - that way, either a space or a null will detect the end
after my nap, i'll write up a little code for you
i need to stay in practice with 16-bit code - lol

brookebree

Dedndave,

Thanks so much for your segment of code I used in my 'ascbin12'  subroutine below to accomplish my
ascii to binary conversion of a 12 digit number into 3 words.  I debugged it and it seems to be converting
large ascii strings to the correct binary values.  I checked my program with several  large numbers returning
register with > than double word values using asciii input numbers '999999999999' to '4500999999'

My only question is on the line where I put the '????' comment in the subroutiine,  when adding the current
binary digit to my accumlative totals I'm keeping in ax/dx/bl:

add    ax,cx   ;   these two lines are keeping total in ax,dx registers
adc    dx,0   

but that NEXT line: '  adc    bl,0  '      I don't know if this is the correct way to take overflow from Dx register
and carry over to my Most Significant byte bl register once ax,dx are maxed out, (for example:) at some time at
this point in the code, say  ax=0ffffh, dx=0fffeh and I'm adding a value in cx which = 6?  Is this correct.
See code below.

Also, any ideas you want to share with me on the other routine I need to go from 3-word binary number input
and convert to a max 12 ascii digit '999999999999' output?

Thanks  again - Dale


; <<<< var's declared in my .asm data segment >>>>

numb     db  '999999999999',20h     ;asciii input number to convert to binary

digadr   dw    0     ;var used to track address of each asciii digit
cnt12    db    0     ;digit counter var

; <<<<< my main routine in .asm code segment  >>>>>>

         .....
         -----
         lea     si,numb         ;pass addr of ascii number
         call    ascbin12         ;call ascii to binary routine below
                ;>> upon return here ax,dx/bl contain coverted binary value
         .....
         .....
;------------------------------------------------- sub-routine follows ----------------
public    ascbin12      ;>> Convert ascii num =< '999999999999' to binary <<
ascbin12 proc    near   ;   CALL: [si] = addr of L J ascii Max 12-digit buf, 20h-term'd buffer
                             ;RETURNS: ax/dx/bx = binary number (bh always = 0)

         mov     digadr,si     ;save off calling addr of ascii number buffer
         sub      ax,ax     
         mov     dx,ax     
         mov     bx,ax
         mov     cx,ax
         mov     cnt12,0            ;zero total #digits counter   

nxdg2: mov   si,digadr          ;move to cl ascii digit from buf
         mov    cl,byte ptr [si]                 
         inc      digadr             ;inc to next ascii digit in buf
         and     cl,0fH             ;remove 30h to cvt digit to binary
         add     ax,cx              ;add binary digit value to ax/dx/bl
         adc     dx,0
         adc     bl,0     ;????         
         inc      cnt12              ;inc total #digit processed count
         cmp    cnt12,12         ;exit if processed max 12 digits
         jz        fn12
         mov    si,digadr       
         cmp    byte ptr [si],20h  ;exit if just processed/added last digit
         jz        fn12

;<< now multiply by 10
;multiply the accumulator by 2
         shl      ax,1
         rcl       dx,1
         rcl       bl,1

;make a copy of 2X accumulator in BH:SI:DI
         mov     di,ax
         mov     si,dx
         mov     bh,bl

;multiply the copy by 2 (4X accumulator)
         shl       di,1
         rcl       si,1
         rcl       bh,1

;multiply the copy by 2 again (8X accumulator)
         shl      di,1
         rcl       si,1
         rcl       bh,1

;add the two together (8X + 2X = 10X)
         add     ax,di
         adc     dx,si
         adc     bl,bh
         jmp     nxdg2        ;go get next ascii digit

fn12:  mov    bh,0  ;return binary value in ax/dx/bl (init bh=0 on exit so can save entire BX register contents)
         ret             
ascbin12 endp                                                     
;******************************************************


dedndave

yes - that's right
you want a carry bit to "ripple" all the way through
although - you might want to make sure CH is also zero before the add
i didn't read all the way through to see if that is true
if not, change AND CL,0Fh to AND CX,0Fh and that will insure that CH is 0
if it is, then you can use....
add ax,cx
adc dx,0
adc bl,ch

it saves a clock cycle or 2   :bg
(CH is a 0)

there are a few other little things i would change
let me wake up and have a look   :P

dedndave

here you go, Dale
give this a try...

brookebree

Thanks a lot dedndave, you were obviously a big help to me
on this little convertion routine.  see ya later - Dale