Prev: OctaOS
Next: DIV overflow
From: rhyde on
On Mar 27, 12:28 am, Frank Kotler <fbkot...(a)verizon.net> wrote:
> Guga wrote:
>
> ...
>
> > I can´t understand the logic of using shld
>
> Randy is doing *hex* ascii to integer. The "shld 4" does a multi-dword
> multiply by *16*.
>
> I *completely* misunderstood what you were trying to do. The code from
> Nasm64developer is to convert a "float string" (can contain '.', 'e',
> etc. plus decimal digits) to IEEE???(whatever that number is... 754)
> floating-point format. Still an "interesting" project, perhaps, but not
> what you want, at all!
>
> With my New Improved (mis)Understanding, this looks a lot easier. I'm
> not sure what you'd do with a tbyte/tword integer, but if you can
> multiply a tword by ten, you've got it made. Might be worth developing
> an "arbitrary size" multiply, rather than specifically tword. Lemme
> think on this a little...
>
> Best,
> Frank

Ah!
I missed the atoi part. All the dwords and qwords had me thinking it
was a hexadecimal conversion. Here's a 128-bit decimal unsigned
integer to string conversion routine (You can either shorten it down,
or simply range-check the result to make sure it fits within 80 bits):

procedure _atou128;
@nodisplay;
@noframe;

procedure _accX10;
@nodisplay;
@noframe;
begin _accX10;

// Compute EDX:ECX:EBX:EDI * 10

push( eax );

shl( 1, edi );
rcl( 1, ebx );
rcl( 1, ecx );
rcl( 1, edx );
jc Overflow;

push( edx );
push( ecx );
push( ebx );
push( edi );

shl( 1, edi );
rcl( 1, ebx );
rcl( 1, ecx );
rcl( 1, edx );
jc Overflow;

shl( 1, edi );
rcl( 1, ebx );
rcl( 1, ecx );
rcl( 1, edx );
jc Overflow;

pop( eax );
add( eax, edi );
pop( eax );
adc( eax, ebx );
pop( eax );
adc( eax, ecx );
pop( eax );
adc( eax, edx );
jc Overflow;

pop( eax );
ret();

Overflow:
raise( ex.ValueOutOfRange );

end _accX10;

begin _atou128;

push( edi );
xor( eax, eax ); // Init H.O. three bytes of EAX to zero.
mov( eax, edx ); // Initialize EDX:ECX:EBX:EDI with zero.
mov( eax, ecx );
mov( eax, ebx );
mov( eax, edi );


// For each legal character that ESI points at, repeat
// the following until we encounter a delimiter or
// illegal character.

mov( [esi], al ); // Get the first character (which must be a
digit).
whileDigits:
cmp( al, '0' );
jb convError;
cmp( al, '9' );
ja convError;


// Okay, we've got a digit, so add it into EDX:ECX.

_accX10(); // EDX:ECX:EBX:EDI * 10.
and( $f, al );
add( eax, edi );
adc( 0, ebx );
adc( 0, ecx );
adc( 0, edx );
jc Overflow;

// Move on to the next character:

NextChar;

// Repeat until we hit a delimiter character

cmp( eax, $80 );
jae IllegalChar;
bt( eax, (type dword Delimiters ));
jnc whileDigits;



// Return 128-bit result in EDX:ECX:EBX:EAX

mov( edi, eax );
pop( edi );
ret();

convError:
raise( ex.ConversionError );

Overflow:
raise( ex.ValueOutOfRange );

IllegalChar:
raise( ex.IllegalChar );

end _atou128;

From: Wolfgang Kern on

Hello Guga,
[..]
> Wolfgang...i tested it.. but i couldn�t suceed to make what is
> necessary. I didn�t understood the code you did. And, if possible
> i don�t want to use MMX instructions.

I see, You asked for asciiDEC2HEX conversion :)
My examples cover just bin2HEX_out and bin2DEC_out.

80 bit conversion could be done in three registers,
but for 128 bit I'm afraid you either need a few LOCALs or
use SSE to speed it up.

I have only one 'variable size' conversion in my KESYS,
from signed bytes up to unsigned 512 bit plus 10^x exponent.

I can extract the method for fix-sized conversion and
convert it into readable ASM. Today I'm invited to a party,
so I better start with it tomorrow afternoon :)

__
wolfgang

Are you sure that you cannot renounce on the stack frame? ;)
You check for limits and errors in the ascii-input before ?

> I suceeded to make a variation of atoi64.. but i wanted an atoi80 (or
> also a atoi128).

> The code i did is:
__________________________________________________________
;;
convert a null terminated ascii string to qword
result in edx:eax
;;

Proc atoi64:
Arguments @String

mov ebx D(a)String

xor esi esi ; HiQword
xor ecx ecx ; LowQWord

While B$ebx <> 0

call alldecmul ecx, esi
mov ecx eax
mov esi edx

movsx eax B$ebx
sub eax '0'
cdq
add ecx eax
adc esi edx

inc ebx
End_While

mov eax ecx
mov edx esi

EndP

__________________________________________________________

;;
Multiply a Qword unsigned integer by 10

;;

Proc alldecmul:
Arguments @ValA_Low, @ValA_Hi
uses esi, ebx

mov eax D(a)ValA_Hi
mov ecx 10
mov ebx D(a)ValA_Low

cmp eax 0 | jne @Notzero
mov eax ebx
mul ecx
ExitP

@Notzero:

mul ecx

mov esi eax
mov eax ebx ; ValA_Low

mul ecx
add edx esi

EndP
__________________________________________________________

Note: The alldecmul is a variation of allmul function. Here:

;;
Multiply two 64 bit integers.

;;

Proc allmul:
Arguments @ValA_Low, @ValA_Hi, @ValB_Low, @ValB_Hi
uses esi, ebx

mov eax D(a)ValA_Hi
mov ecx D(a)ValB_Hi

mov esi D(a)ValB_Low
mov ebx D(a)ValA_Low

or ecx eax | jne @NotEqual
mov ecx esi
mov eax ebx
mul ecx
ExitP

@NotEqual:
mov ecx esi

mul ecx

mov esi eax
mov eax ebx ; ValA_Low
mul D(a)ValB_Hi

add esi eax
mov eax ebx ; ValA_Low

mul ecx
add edx esi

EndP



Any idea how to make a atoi80 or atoi128 ?

Best Regards,

Guga



From: Frank Kotler on
Herbert Kleebauer wrote:
> Herbert Kleebauer wrote:
>
>>I also supposed he wants to convert floating point numbers. Here
>>a decimal ascii to binary conversion for multi precision integers
>>(one with and one without "mult" instruction, don't now which
>>one is faster):
>
>
> Sorry, the version with "mul" isn't correct. I let it as an exercise
> for the "dear reader" to insert the one missing instruction.

Jeez, Herbert, I was going to "leave this for later"! :)

Okay, I see what you mean (I think). In case some other examinees (I
mean "dear readers") wish to participate, I won't post my answer yet. In
case some other examinees claim they can't understand your syntax, I'll
post my Nasm "translation" (imperfect, but "close enough", I claim) -
for Linux, but it would be trivial to port to Windoze. The "fix" has
been removed, but the "test_string" illustrates the problem, I think.

Best,
Frank

global _start

size equ 16 ; in dwords

section .data

test_string db "4294967296",0


section .bss
; number buffers
result resd size
tmp resd size

; text buffer for display
text_out resb size * 10 + 10
text_out_end:


section .text
_start:

mov ebx, test_string
call atoi1
call dec_dump

mov ebx, test_string
call atoi2
call dec_dump

exit:
; xor ebx, ebx
; since this code is wrong...
or ebx, byte -1 ; return error!
mov eax, 1 ; __NR_exit
int 80h
;--------------------

;--------------------
atoi1:
mov edi, result
mov ecx, size
xor eax, eax
rep stosd

mov edi, 10
..20:
movzx ecx, byte [ebx]
inc ebx
cmp cl, '9'
ja .done
sub cl, '0'
jc .done

mov esi, result
xor ebp, ebp
..10:
mov eax, [esi + ebp * 4]
mul edi
add eax, ecx
mov [esi + ebp * 4], eax
mov ecx, edx
inc ebp
cmp ebp, size - 1
jna .10

jmp short .20
..done:
ret
;--------------------

;--------------------
atoi2:
mov edi, result
mov ecx, size
xor eax, eax
rep stosd
..20:
movzx edx, byte [ebx]
inc ebx
cmp dl, '9'
ja .done
sub dl, '0'
jc .done

mov esi, result
mov ebp, size - 2
..30:
mov eax, [esi + ebp * 4]
shld [esi + ebp * 4 + 4], eax, 1
dec ebp
jns .30

shl dword [esi], 1
mov edi, tmp
mov ecx, size
rep movsd

mov esi, result
mov ebp, size - 2
..40:
mov eax, [esi + ebp * 4]
shld [esi + ebp * 4 + 4], eax, 2
dec ebp
jns .40
shl dword [esi], 2

xor ebp, ebp
mov ecx, size
mov edi, tmp

cmp dl, 7
jna .50
add dword [esi], byte 7
add dword [edi], byte 1

add dl, 256 - 9
jmp short .10

..50:
add [esi], edx
..10:
mov eax, [edi + ebp * 4]
adc [esi + ebp * 4],eax
inc ebp
loop .10

jmp .20
..done
ret
;----------------------

;----------------------
dec_dump:
mov ebx, 10
mov edi, text_out_end
..20:
mov esi, result
mov ebp, size - 1
xor edx, edx
xor ecx, ecx
..10:
mov eax, [esi + ebp * 4]
div ebx
mov [esi + ebp * 4], eax
or ecx, eax
dec ebp
jns .10

add dl, '0'
dec edi
mov [edi], dl
test ecx, ecx
jnz .20

sub edi, byte 4
mov dword [edi], 0xa0d0a0d

mov eax, 4
mov ebx, 1
mov ecx, edi
mov edx, text_out_end
sub edx, ecx
int 80h

ret
;-------------------------------
From: Guga on
On Mar 27, 1:56 am, Herbert Kleebauer <k...(a)unibwm.de> wrote:
> Frank Kotler wrote:>
> > Guga wrote:
>
> > ...
> > > I can´t understand the logic of using shld
>
> > Randy is doing *hex* ascii to integer. The "shld 4" does a multi-dword
> > multiply by *16*.
>
> > I *completely* misunderstood what you were trying to do. The code from
> > Nasm64developer is to convert a "float string" (can contain '.', 'e',
> > etc. plus decimal digits) to IEEE???(whatever that number is... 754)
> > floating-point format. Still an "interesting" project, perhaps, but not
> > what you want, at all!
>
> > With my New Improved (mis)Understanding, this looks a lot easier. I'm
> > not sure what you'd do with a tbyte/tword integer, but if you can
> > multiply a tword by ten, you've got it made. Might be worth developing
> > an "arbitrary size" multiply, rather than specifically tword. Lemme
> > think on this a little...
>
> I also supposed he wants to convert floating point numbers. Here
> a decimal ascii to binary conversion for multi precision integers
> (one with and one without "mult" instruction, don't now which
> one is faster):
>
> @=$100
> size=16 ; size in 32 bit words
>
> move.l #dec_ascii,r3
> bsr.l atoi1 ; convert with div
> bsr.l dec_dump
>
> move.l #dec_ascii,r3
> bsr.l atoi2 ; concert with shift+add
> bsr.l dec_dump
>
> rts.w
>
> atoi1: move.l #result,r6
> move.l #size,r2
> eor.l r0,r0
> rep_r2 move.l r0,(r6)+-{s1}
>
> move.l #10,r6
> _20: movu.bl (r3),r2
> inc.l r3
> cmp.b #'9',r2
> bhi.l _done
> sub.b #'0',r2
> bcs.l _done
>
> move.l #result,r5
> eor.l r4,r4
> _10: move.l (r5,r4*4),r0
> mulu.l r6,r0,r1|r0
> add.l r2,r0
> move.l r0,(r5,r4*4)
> move.l r1,r2
> inc.l r4
> cmp.l #size-1,r4
> bls.b _10
> br.b _20
> _done: rts.l
>
> atoi2: move.l #result,r6
> move.l #size,r2
> eor.l r0,r0
> rep_r2 move.l r0,(r6)+-{s1}
>
> _20: movu.bl (r3),r1
> inc.l r3
> cmp.b #'9',r1
> bhi.l _done
> sub.b #'0',r1
> bcs.l _done
>
> move.l #result,r5
> move.l #size-2,r4
> _30: move.l (r5,r4*4),r0
> dsl.l #1,4.b(r5,r4*4)<r0
> dec.l r4
> bpl.b _30
> lsl.l #1,(r5)
>
> move.l #tmp,r6
> move.l #size,r2
> rep_r2 move.l (r5)+-,(r6)+-{s1}
>
> move.l #result,r5
> move.l #size-2,r4
> _40: move.l (r5,r4*4),r0
> dsl.l #2,4.b(r5,r4*4)<r0
> dec.l r4
> bpl.b _40
> lsl.l #2,(r5)
>
> eor.l r4,r4
> move.l #size,r2
> move.l #tmp,r6
>
> cmp.b #7,r1
> bls.b _50
> addq.l #7,(r5)
> addq.l #1,(r6)
> add.b #256-9,r1
> br.b _10
> _50: add.l r1,(r5)
>
> _10: move.l (r6,r4*4),r0
> addc.l r0,(r5,r4*4)
> inc.l r4
> dbf.l r2,_10
> br.l _20
> _done: rts.l
>
> dec_ascii: dc.b "1234567890123456789011223344556677889900111222333444555",0
>
> dec_dump:
> move.l #10,r3
> move.l #text_out_end,r6
>
> _20: move.l #result,r5
> move.l #size-1,r4
> eor.l r1,r1
> eor.l r2,r2
> _10: move.l (r5,r4*4),r0
> divu.l r3,r1|r0
> move.l r0,(r5,r4*4)
> or.l r0,r2
> dec.l r4
> bpl.b _10
> add.b #'0',r1
> dec.l r6
> move.b r1,(r6)
> tst.l r2,r2
> bne.b _20
>
> subq.l #4,r6
> move.l #$0a0d0a0d,(r6)
> move.b #$40,m0
> move.w r6,r1
> move.l #text_out_end,r2
> sub.w r1,r2
> move.w #1,r3
> trap #$21
>
> rts.l
>
> even 4
> result: blk.l size
> tmp: blk.l size
>
> text_out: blk.b size*10+10
> text_out_end:- Hide quoted text -
>
> - Show quoted text -


Hi herbert. tks. but for Floating point i´ll use anothe routines. (i
have them btw.. just need a review)

Abnout your code... there are several things i don´t understand.. What
is this ????

A type of nline assembly ? Or is it HLA ? If it is HLA.. sorry, but, i
failed to read it.. Even if Randall´s example is in HLA, i can read
them.

On your´s what is trap, bne, dbf, eor, rts ? They are macros ?

And what is a mult ?

Best Regards,

Guga

From: Guga on
On Mar 27, 5:45 am, "r...(a)cs.ucr.edu" <r...(a)cs.ucr.edu> wrote:
> On Mar 27, 12:28 am, Frank Kotler <fbkot...(a)verizon.net> wrote:
>
>
>
>
>
> > Guga wrote:
>
> > ...
>
> > > I can´t understand the logic of using shld
>
> > Randy is doing *hex* ascii to integer. The "shld 4" does a multi-dword
> > multiply by *16*.
>
> > I *completely* misunderstood what you were trying to do. The code from
> > Nasm64developer is to convert a "float string" (can contain '.', 'e',
> > etc. plus decimal digits) to IEEE???(whatever that number is... 754)
> > floating-point format. Still an "interesting" project, perhaps, but not
> > what you want, at all!
>
> > With my New Improved (mis)Understanding, this looks a lot easier. I'm
> > not sure what you'd do with a tbyte/tword integer, but if you can
> > multiply a tword by ten, you've got it made. Might be worth developing
> > an "arbitrary size" multiply, rather than specifically tword. Lemme
> > think on this a little...
>
> > Best,
> > Frank
>
> Ah!
> I missed the atoi part. All the dwords and qwords had me thinking it
> was a hexadecimal conversion. Here's a 128-bit decimal unsigned
> integer to string conversion routine (You can either shorten it down,
> or simply range-check the result to make sure it fits within 80 bits):
>
> procedure _atou128;
> @nodisplay;
> @noframe;
>
> procedure _accX10;
> @nodisplay;
> @noframe;
> begin _accX10;
>
> // Compute EDX:ECX:EBX:EDI * 10
>
> push( eax );
>
> shl( 1, edi );
> rcl( 1, ebx );
> rcl( 1, ecx );
> rcl( 1, edx );
> jc Overflow;
>
> push( edx );
> push( ecx );
> push( ebx );
> push( edi );
>
> shl( 1, edi );
> rcl( 1, ebx );
> rcl( 1, ecx );
> rcl( 1, edx );
> jc Overflow;
>
> shl( 1, edi );
> rcl( 1, ebx );
> rcl( 1, ecx );
> rcl( 1, edx );
> jc Overflow;
>
> pop( eax );
> add( eax, edi );
> pop( eax );
> adc( eax, ebx );
> pop( eax );
> adc( eax, ecx );
> pop( eax );
> adc( eax, edx );
> jc Overflow;
>
> pop( eax );
> ret();
>
> Overflow:
> raise( ex.ValueOutOfRange );
>
> end _accX10;
>
> begin _atou128;
>
> push( edi );
> xor( eax, eax ); // Init H.O. three bytes of EAX to zero.
> mov( eax, edx ); // Initialize EDX:ECX:EBX:EDI with zero.
> mov( eax, ecx );
> mov( eax, ebx );
> mov( eax, edi );
>
> // For each legal character that ESI points at, repeat
> // the following until we encounter a delimiter or
> // illegal character.
>
> mov( [esi], al ); // Get the first character (which must be a
> digit).
> whileDigits:
> cmp( al, '0' );
> jb convError;
> cmp( al, '9' );
> ja convError;
>
> // Okay, we've got a digit, so add it into EDX:ECX.
>
> _accX10(); // EDX:ECX:EBX:EDI * 10.
> and( $f, al );
> add( eax, edi );
> adc( 0, ebx );
> adc( 0, ecx );
> adc( 0, edx );
> jc Overflow;
>
> // Move on to the next character:
>
> NextChar;
>
> // Repeat until we hit a delimiter character
>
> cmp( eax, $80 );
> jae IllegalChar;
> bt( eax, (type dword Delimiters ));
> jnc whileDigits;
>
> // Return 128-bit result in EDX:ECX:EBX:EAX
>
> mov( edi, eax );
> pop( edi );
> ret();
>
> convError:
> raise( ex.ConversionError );
>
> Overflow:
> raise( ex.ValueOutOfRange );
>
> IllegalChar:
> raise( ex.IllegalChar );
>
> end _atou128;- Hide quoted text -
>
> - Show quoted text -

ok.. tks Randall... i´ll read it and see if i can follow

Best Regards,

Guga

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Prev: OctaOS
Next: DIV overflow