Prev: OctaOS
Next: DIV overflow
From: rhyde on 27 Mar 2007 09:45 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 27 Mar 2007 10:56 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 27 Mar 2007 11:33 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 27 Mar 2007 12:32 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 27 Mar 2007 12:34
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 |