181 lines
8.2 KiB
NASM
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
|