kolibrios-fun/programs/develop/open watcom/trunk/clib/cgsupp/fprem386.asm
Sergey Semyonov (Serge) 836c97f0ac Clib string & memory functions
git-svn-id: svn://kolibrios.org@553 a494cfbc-eb01-0410-851d-a64ba20cac60
2007-06-26 00:54:22 +00:00

181 lines
8.2 KiB
NASM

;*****************************************************************************
;*
;* 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 fprem386
xdefp __fprem_
;
; EDX:EAX ECX:EBX
; void fprem( double x, double modulus, int *quot, double *rem )
;
defpe __fprem_
push EBP ; save BP
mov EBP,ESP ; get access to parms
push EDX ; save registers
push ECX ; ...
push EBX ; ...
push EAX ; ...
mov EAX,8[EBP] ; get argument x
mov EDX,12[EBP] ; ...
mov EBX,16[EBP] ; get modulus
mov ECX,20[EBP] ; ...
or ECX,ECX ; if modulus is zero
_if e ; then
sub EAX,EAX ; - set result to 0
mov EBX,24[EBP] ; - quot = 0
mov [EBX],EAX ; - ...
mov EBX,28[EBP] ; - remainder = 0
mov [EBX],EAX ; - ...
mov 4[EBX],EAX ; - ...
pop EAX ; - restore registers
pop EBX ; - ...
pop ECX ; - ...
pop EDX ; - ...
pop EBP ; - restore EBP
ret ; - return
_endif ; endif
push ESI ; save ESI
push EDI ; save EDI
push EDX ; save sign of operand
push ECX ; save high part of modulus
mov ESI,EDX ; get most sig word of op1
mov EDI,ECX ; get most sig word of op2
and ESI,7FF00000h ; isolate exponent
and EDI,7FF00000h ; isolate exponent of modulus
and EDX,000FFFFFh ; isolate mantissa of op1
and ECX,000FFFFFh ; isolate mantissa of modulus
or EDX,00100000h ; set implied 1 bit
or ECX,00100000h ; ...
sub ESI,EDI ; calculate difference in exponents
_if ge ; if operand >= modulus
sub EDI,EDI ; - set quotient to 0
_loop ; - loop
_guess ; - - guess
cmp ECX,EDX ; - - - The purpose of this guess is to
_quif ne ; - - - determine if the divisor will subtract
cmp EBX,EAX ; - - -
je try ; - - -
_endguess ; - - endguess
_if c ; - - if the carry is set (ie the modulus will
; - - - definitely subtract from the dividend
; - - - without a borrow
try:
sub EAX,EBX ; - - - subtract divisor from dividend
sbb EDX,ECX ; - - - . . .
stc ; - - - set carry to indicate that modulus was
; - - - successfully subtracted from dividend
_endif ; - - endif
didnt_go: _rcl EDI,1 ; - - rotate 1 (if carry set) into quotient word
sub ESI,00100000h ; - - adjust difference in exponents
jl _done ; - - quit if done
_shl EAX,1 ; - - shift dividend left
_rcl EDX,1 ; - - . . .
cmp EDX,00200000h
jae try
; If bit 5 of dividend is set here, we didnt subtract the modulus from the
; dividend (recall that the divisor has a 1 in the msb -- if we subtracted
; it from the dividend without a borrow, the dividend would not have a one
; in its msb to be shifted into bit 5 tested for in the condition above. If
; we are rotating a bit into bit 5, the dividend is now big enough that we
; can be sure of subtracting out the divisor without a borrow, as we have
; shifted it left one digit.
cmp EDX,00100000h
_until b ; - until
cmc ; - flip the carry bit
jmp short didnt_go ; - continue
_done: sub ESI,ESI ; - set SI to 0
; normalize the remainder in AL:BX:CX:DX
_guess ; - guess: number is zero
or EAX,EAX ; - - quit if not zero
_quif ne ; - - ...
or EDX,EDX ; - - ...
_quif ne ; - - ...
_admit ; - admit: not zero
_loop ; - - loop
test EDX,00200000h; - - - quit if number is normalized
_quif ne ; - - - . . .
_rcl EAX,1 ; - - - shift result left
_rcl EDX,1
sub ESI,00100000h; - - - decrement exponent
_endloop ; - - endloop
shr EDX,1 ; - - put in correct position
rcr EAX,1 ; - - . . .
add ESI,00100000h ; - - increment exponent
pop ECX ; - - get high part of modulus
push ECX ; - - save it again
and ECX,7FF00000h ; - - isolate exponent of modulus
add ESI,ECX ; - - adjust exponent of result
_endguess ; - endguess
_else ; else
add ESI,EDI ; - restore exponent
sub EDI,EDI ; - set quotient to 0
_endif ; endif
and EDX,000FFFFFh ; keep just the fraction
add EDX,ESI ; update high order word
pop ECX ; restore high part of modulus
pop ESI ; restore sign
and ESI,080000000h ; isolate sign bit
or EDX,EDX ; test high word of remainder
_if ne ; if remainder is non-zero
or EDX,ESI ; - make remainder same sign as original opnd
_endif ; endif
xor ESI,ECX ; calc sign of quotient
_if s ; if quotient should be negative
neg EDI ; - negate quotient
_endif ; endif
mov ESI,24[EBP] ; get address of quotient
mov [ESI],EDI ; store quotient
mov ESI,28[EBP] ; get address of remainder
mov [ESI],EAX ; store remainder
mov 4[ESI],EDX ; ...
pop EDI ; restore EDI
pop ESI ; restore ESI
pop EAX ; restore registers
pop EBX ; ...
pop ECX ; ...
pop EDX ; ...
pop EBP ; restore EBP
ret ; return
endproc __fprem_
endmod
end