kolibrios-gitea/programs/develop/open watcom/trunk/clib/intel/i64ts386.asm

266 lines
12 KiB
NASM
Raw Normal View History

;*****************************************************************************
;*
;* Open Watcom Project
;*
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;* ========================================================================
;*
;* This file contains Original Code and/or Modifications of Original
;* Code as defined in and that are subject to the Sybase Open Watcom
;* Public License version 1.0 (the 'License'). You may not use this file
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;* provided with the Original Code and Modifications, and is also
;* available at www.sybase.com/developer/opensource.
;*
;* The Original Code and all software distributed under the License are
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;* NON-INFRINGEMENT. Please see the License for the specific language
;* governing rights and limitations under the License.
;*
;* ========================================================================
;*
;* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
;* DESCRIBE IT HERE!
;*
;*****************************************************************************
include mdef.inc
include struct.inc
modstart i64tos
;
;
; int _CmpBigInt( int sigdigits, int near *bigint )
; EAX EDX
;
xdefp __CmpBigInt
xdefp __Rnd2Int
xdefp __Bin2String
defpe __CmpBigInt
push EDI ; save EDI
push ECX ; save ECX
call getpow10 ; get address of Power of 10 table
inc EAX ; ++sigdigits
lea EDI,[EDI+EAX*8] ; point to Pow10Table[sigdigits+1]
mov ECX,[EDX] ; get 64-bit integer
mov EDX,4[EDX] ; ...(high part)
sub EAX,EAX ; set adjustment to 0
_loop ; loop
cmp EDX,cs:[EDI] ; - check against 10**k
_if e ; - if high parts equal
cmp ECX,cs:4[EDI] ; - - compare low part
_endif ; - endif
_quif b ; - quit if num < 10**k
add EDI,8 ; - set pointer to 10**(k+1)
inc EAX ; - increment adjustment word
_endloop ; endloop
sub EDI,8 ; point at 10**(k-1)
_loop ; loop
cmp EDX,cs:[EDI] ; - check against 10**k
_if e ; - if high parts equal
cmp ECX,cs:4[EDI] ; - - compare low part
_endif ; - endif
_quif nb ; - quit if num >= 10**(k-1)
sub EDI,8 ; - set pointer to 10**(k-2)
dec EAX ; - increment adjustment word
_endloop ; endloop
pop ECX ; restore ECX
pop EDI ; restore EDI
ret ; return to caller
endproc __CmpBigInt
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] Rnd2int rounds the real pointed to by EAX to a 64 bit integer.
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
; void _Rnd2Int( double near *realnum, int near *bigint )
; EAX EDX
;
defpe __Rnd2Int
push EBX ; save registers
push ECX ; save ECX
push EDX ; save EDX
push EBP ; save EBP
push ESI ; save ESI
push EDX ; save address of bigint array
mov EBP,EAX ; get address of realnum
mov ECX,[EBP] ; load the number
mov EBX,4[EBP] ; . . .
mov EBP,EBX ; save high word
and EBP,0FFF00000h ; isolate exponent in EBP
xor EBX,EBP ; isolate mantissa in EDX
xor EBX,00100000h ; turn on implied '1' bit in mantissa
shr EBP,20 ; move exponent to bottom part of word
sub EBP,0433h ; calculate difference from 2**53
_if ne ; if not already the right size
_if a ; - if too big
_loop ; - - loop
shl ECX,1 ; - - - shift real left by one
rcl EBX,1 ; - - - . . .
dec EBP ; - - - decrement count
_until e ; - - until count = 0
_else ; - else
sub EAX,EAX ; - - clear remainder
sub ESI,ESI ; - - clear remainder bit bucket
_loop ; - - loop
shr EBX,1 ; - - - shift real right by one
rcr ECX,1 ; - - - . . .
rcr EAX,1 ; - - - save remainder
adc ESI,ESI ; - - - remember if any bits fell off end
inc EBP ; - - - increment count
_until e ; - - until e
_guess rup ; - - do we have to round up?
cmp EAX,80000000h;- - - compare remainder with .5000000
_quif b,rup ; - - - kick out if less than .5
_if e ; - - - magical stuff if looks like a .5
or ESI,ESI ; - - - any bits dropped off the bottom
_if e ; - - - if not
test ECX,1 ; - - - - - is bottom digit even?
_quif e,rup ; - - - - - kick out if it is
_endif ; - - - - endif
_endif ; - - - endif
add ECX,01 ; - - - round up the number
adc EBX,00 ; - - - . . .
_endguess ; - - endguess
_endif ; - endif
_endif ; endif
pop EBP ; get address of bigint array
mov [EBP],ECX ; store 64-bit integer
mov 4[EBP],EBX ; . . .
pop ESI ; restore ESI
pop EBP ; restore EBP
pop EDX ; restore EDX
pop ECX ; restore ECX
pop EBX ; restore EBX
ret ; return
endproc __Rnd2Int
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] Bin2string converts a binary integer into a string
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
; void _Bin2String(
; int near *bigint, /* EAX */
; char near *bufptr, /* EDX */
; int sigdigits ) /* EBX */
;
defpe __Bin2String
push EBP ; save EBP
push EDI ; save EDI
push ECX ; save ECX
push EBX ; save EBX
mov EBP,EAX ; get address of bigint array
mov ECX,[EBP] ; get 64-bit integer
mov EAX,4[EBP] ; . . .
mov EBP,EDX ; get buffer pointer
add EBP,EBX ; point to end of buffer
mov byte ptr [EBP],0; put in null character
;
; input:
; EAX:ECX - 64-bit integer
; EBP - pointer to buffer for digits
; EBX - digit count
push EAX ; save high word of quotient
_loop ; loop
pop EAX ; - restore high word of quotient
mov EDI,10000 ; - divisor is 10000
sub EDX,EDX ; - zero high word
or EAX,EAX ; - check high word
jne div1 ; - do all divides
or ECX,ECX ; - check low order word
jne div2 ; - skip first divide
push EAX ; - save high word of quotient
jmp short div5 ; - result is 0
div1: div EDI ; - divide EAX:ECX by 10000
div2: xchg ECX,EAX ; - ...
div EDI ; - ...
; quotient is in ECX:EAX
; remainder is in EDX
xchg ECX,EAX ; - move quotient to EAX:ECX
push EAX ; - save high word of quotient
mov EAX,EDX ; - get remainder
mov DL,100 ; - get divisor
div DL ; - split remainder into 2 parts
mov DL,AH ; - save low order part
mov AH,0 ; - zero
aam ; - split top part into 2 digits
xchg EDX,EAX ; - DH, DL gets top 2 digits, AX gets low part
mov AH,0 ; - zero
aam ; - split low part into 2 digits
div5: add AX,3030h ; - make ASCII digits
add DX,3030h ; - ...
sub EBP,4 ; - move back 4
mov 3[EBP],AL ; - put low order digit in buffer
dec EBX ; - decrement digit count
_quif e ; - quit if done
mov 2[EBP],AH ; - ...
dec EBX ; - decrement digit count
_quif e ; - quit if done
mov 1[EBP],DL ; - ...
dec EBX ; - decrement digit count
_quif e ; - quit if done
mov [EBP],DH ; - put high order digit in buffer
dec EBX ; - decrement digit count
_until e ; until done
pop EAX ; remove high word of quotient
pop EBX ; restore EBX
pop ECX ; restore ECX
pop EDI ; restore EDI
pop EBP ; restore EBP
ret ; return
endproc __Bin2String
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<> <>
;<> 64-bit integer powers of 10 table <>
;<> <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
getpow10 proc near ; get address of powers of 10 table
call pow10end ; call around the table
pow10table: ; powers of 10 table
dd 000000000h,000000000h ; 0
dd 000000000h,000000001h ; 10**00
dd 000000000h,00000000ah ; 10**01
dd 000000000h,000000064h ; 10**02
dd 000000000h,0000003e8h ; 10**03
dd 000000000h,000002710h ; 10**04
dd 000000000h,0000186a0h ; 10**05
dd 000000000h,0000f4240h ; 10**06
dd 000000000h,000989680h ; 10**07
dd 000000000h,005f5e100h ; 10**08
dd 000000000h,03b9aca00h ; 10**09
dd 000000002h,0540be400h ; 10**10
dd 000000017h,04876e800h ; 10**11
dd 0000000e8h,0d4a51000h ; 10**12
dd 000000918h,04e72a000h ; 10**13
dd 000005af3h,0107a4000h ; 10**14
dd 000038d7eh,0a4c68000h ; 10**15
dd 0002386f2h,06fc10000h ; 10**16
dd 001634578h,05d8a0000h ; 10**17
dd 00de0b6b3h,0a7640000h ; 10**18
dd 08ac72304h,089e80000h ; 10**19
dd 0ffffffffh,0ffffffffh ; MAX
pow10end proc near
pop EDI ; get address of table
ret ; return
endproc pow10end
endproc getpow10
endmod
end