;***************************************************************************** ;* ;* 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: REAL*8 math library. ;* ;***************************************************************************** ; ; inputs: EDX,EAX - operand 1 (high word, low word resp. ) (op1) ; ECX,EBX - operand 2 (op2) ; ; operations are performed as op1 (*) op2 where (*) is the selected ; operation ; ; output: EDX,EAX - result (high word, low word resp. ) ; ; include mdef.inc include struct.inc .8087 modstart fdmth386 xref __8087 ; indicate that NDP instructions are present datasegment extrn __real87 : byte ; 8087.asm enddata xref F8DivZero ; Fstatus xref F8OverFlow ; Fstatus xref F8UnderFlow ; Fstatus xdefp __FDA ; add real*8 to real*8 xdefp __FDS ; subtract real*8 from real*8 xdefp __FDM ; 8-byte real multiply defpe __FDS xor ECX,80000000h ; flip the sign of op2 and add defpe __FDA or EBX,EBX ; if low word of op2 is 0 _if e ; then _shl ECX,1 ; - place sign in carry je ret_op1 ; - if op2 is 0 then return operand 1 rcr ECX,1 ; - put sign back _endif ; endif or EAX,EAX ; if op1 is 0 _if e ; then _shl EDX,1 ; - place sign in carry _if e ; - if op1 really is 0 mov EDX,ECX ; - - return operand 2 mov EAX,EBX ; - - . . . ret_op1: ret ; - - return _endif ; - endif rcr EDX,1 ; - put sign back _endif ; endif cmp byte ptr __real87,0; if 8087 not to be used je short __FDAemu ; then emulate __FDA87: push EDX ; push operand 1 push EAX ; . . . fld qword ptr [ESP] ; load operand 1 push ECX ; push operand 2 push EBX ; . . . fadd qword ptr [ESP] ; add operand 2 to operand 1 _ret87: fstp qword ptr 8[ESP]; store result add ESP,8 ; clean up stack fwait ; wait pop EAX ; load result into EDX:EAX pop EDX ; . . . cmp EDX,80000000H ; is it a negative zero? _if e ; if it is then sub EDX,EDX ; - make it positive 0.0 mov EAX,EDX ; - ... _endif ; endif ret ; return __FDAemu: push EBP ; save EBP push EDI ; save EDI push ESI ; save EDI mov EDI,EDX ; get high part of op1 mov ESI,ECX ; get high part of op2 sar EDI,20 ; shift exponent to bottom, duplicating sign sar ECX,20 ; shift exponent to bottom, duplicating sign and EDI,0800007FFh ; isolate signs and exponent and ECX,0800007FFh ; ... mov EBP,ECX ; assume op1 < op2 rol EDI,16 ; rotate signs to bottom rol ECX,16 ; ... add CX,DI ; calc sign of result rol EDI,16 ; rotate signs to top rol ECX,16 ; ... and EDX,000FFFFFh ; isolate fraction and ESI,000FFFFFh ; isolate fraction or DI,DI ; if op1 is not a denormal _if ne ; then or EDX,00100000h ; - turn on implied 1 bit _endif ; endif or CX,CX ; if op2 is not a denormal _if ne ; then or ESI,00100000h ; - turn on implied 1 bit _endif ; endif _shl EAX,1 ; shift left 1 to make room for guard bit _rcl EDX,1 ; ... _shl EBX,1 ; ... _rcl ESI,1 ; ... sub CX,DI ; calculate difference in exponents _if ne ; if different _if b ; - if op1 < op2 mov EBP,EDI ; - - get larger exponent for result neg CX ; - - negate the shift count xchg EAX,EBX ; - - flip operands xchg EDX,ESI ; - - . . . _endif ; - endif cmp CX,53+1 ; - if shift count too big _if a ; - then, return operand 1 mov EDX,ESI ; - - get value in correct registers mov EAX,EBX ; - - . . . _shl EBP,1 ; - - get sign rcr EDX,1 ; - - rebuild operand 1 rcr EAX,1 ; - - ... and EDX,800FFFFFh ; - - ... ror EBP,13 ; - - rotate exponent into position and EBP,7FF00000h ; - - ... or EDX,EBP ; - - put in exponent pop ESI ; - - restore ESI pop EDI ; - - restore EDI pop EBP ; - - restore EBP ret ; - - return _endif ; - endif _endif ; endif or ECX,ECX ; get bit 0 of sign word - value is 0 if ; both operands have same sign, 1 if not _if s ; if signs are different neg ESI ; - negate the fraction of op2 neg EBX ; - . . . sbb ESI,0 ; - . . . xor EBP,80000000h ; - flip sign _endif ; endif sub EDI,EDI ; get a zero for sticky bits cmp CL,0 ; if shifting required _if ne ; then push EBX ; - save EBX sub EBX,EBX ; - for zero fill cmp CL,32 ; - if shift count >= 32 _if ae ; - then or EAX,EAX ; - - check low order word for 1 bits setne BL ; - - BL=1 if EAX non zero mov EDI,EBX ; - - save sticky bits sub EBX,EBX ; - - for zero fill mov EAX,EDX ; - - shift right 32 sub EDX,EDX ; - - zero high word ;;; sub CL,32 ; - - adjust shift count _endif ; - endif shrd EBX,EAX,CL ; - get the extra sticky bits or EDI,EBX ; - save them sub EBX,EBX ; - for zero fill shrd EAX,EDX,CL ; - align the fractions shrd EDX,EBX,CL ; - ... pop EBX ; - restore EBX _endif ; endif add EAX,EBX ; add the fractions adc EDX,ESI ; . . . _if s ; if answer is negative cmp CL,53 ; - if shift count >= 53 _if ae ; - then test EDI,7FFFFFFFh ; - - check the sticky bits setne BL ; - - make single sticky bit shr EBX,1 ; - - carry set if sticky=1 adc EAX,0 ; - - round up fraction if required adc EDX,0 ; - - . . . _endif ; - endif neg EDX ; - negate the fraction neg EAX ; - . . . sbb EDX,0 ; - . . . xor EBP,80000000h ; - flip the sign _endif ; endif mov EBX,EAX ; get result or EBX,EDX ; if not zero _if ne ; then or BP,BP ; - if exponent is 0 je short denormal ; - denormal when exponent hits 0 _loop ; - loop (normalize) test EDX,7FE00000h ; - - stop when bit slides into exponent field _quif ne ; - - ... dec BP ; - - decrement exponent je short denormal; - - denormal when exponent hits 0 _shl EAX,1 ; - - shift fraction left one bit _rcl EDX,1 ; - - ... _endloop ; - endloop test EDX,00400000h ; - if we got a carry _if ne ; - then shr EDX,1 ; - - shift fraction right 1 rcr EAX,1 ; - - ... adc EDI,0 ; - - keep sticky bit inc BP ; - - increment exponent cmp BP,07FFh ; - - quit if overflow je add_oflow ; - - . . . _endif ; - endif ; normalize the fraction shr EDX,1 ; - get guard bit rcr EAX,1 ; - ... _if c ; - if guard bit is on or EDI,EDI ; - - check the sticky bits setne BL ; - - make single sticky bit or EBX,EAX ; - - or sticky bit with bottom bit shr EBX,1 ; - - carry set if sticky=1 or bottom=1 adc EAX,0 ; - - round up fraction if required adc EDX,0 ; - - . . . test EDX,00200000h ; - - if we got a carry (02-nov-90) _if ne ; - - then shr EDX,1 ; - - - shift fraction right 1 rcr EAX,1 ; - - - ... inc BP ; - - - increment exponent cmp BP,07FFh ; - - - quit if overflow je add_oflow ; - - - . . . _endif ; - - endif _endif ; - endif and EDX,000FFFFFh ; - get rid of implied 1 bit mov ECX,EBP ; - get sign shl EBP,21 ; - shift exponent to top _shl ECX,1 ; - get sign rcr EBP,1 ; - put it in or EDX,EBP ; - put exponent and sign into result _endif ; endif pop ESI ; restore ESI pop EDI ; restore EDI pop EBP ; restore EBP ret ; return denormal: ; handle denormal _shl EBP,1 ; get sign rcr EDX,1 ; put it in result rcr EAX,1 ; ... pop ESI ; restore ESI pop EDI ; restore EDI pop EBP ; restore EBP ret ; return add_oflow: ; handle overflow mov EAX,EBP ; get proper sign for infinity pop ESI ; restore ESI pop EDI ; restore EDI pop EBP ; restore EBP jmp F8OverFlow ; handle overflow endproc __FDA endproc __FDS ;===================================================================== ;<> multiplies X by Y and places result in C. ;<> X2 and X1 represent the high and low words of X. Similarly for Y and C ;<> Special care is taken to use only six registers, so the code is a bit ;<> obscure defpe __FDM _guess ; guess: one of the operands is 0 or EAX,EAX ; - see if first arg is zero _quif ne ; - quit if op1 is not 0 _shl EDX,1 ; - place sign in carry _if e ; - if operand one is 0 ret ; - - return _endif ; - endif rcr EDX,1 ; - restore sign _endguess ; endguess _guess ; guess: op2 is 0 or EBX,EBX ; - quit if op2 is not 0 _quif ne ; - . . . _shl ECX,1 ; - place sign in carry _if e ; - if operand 2 is 0 sub EAX,EAX ; - - set result to 0 sub EDX,EDX ; - - . . . ret ; - - return _endif ; - endif rcr ECX,1 ; - restore sign of op2 _endguess ; endguess cmp byte ptr __real87,0; if 8087 not to be used je short __FDMemu ; then emulate __FDM87: push EDX ; push operand 1 push EAX ; . . . fld qword ptr [ESP] ; load operand 1 push ECX ; push operand 2 push EBX ; . . . fmul qword ptr [ESP] ; multiply operand 1 by operand 2 jmp _ret87 ; goto common epilogue __FDMemu: push EBP ; save EBP push EDI ; save EDI push ESI ; save EDI mov EDI,EDX ; get high part of op1 mov ESI,ECX ; get high part of op2 sar EDI,20 ; shift exponent to bottom, duplicating sign sar ECX,20 ; shift exponent to bottom, duplicating sign and EDI,0800007FFh ; isolate signs and exponent and ECX,0800007FFh ; ... rol EDI,16 ; rotate signs to bottom rol ECX,16 ; ... add CX,DI ; calc sign of result rol EDI,16 ; rotate signs to top rol ECX,16 ; ... and EDX,000FFFFFh ; isolate fraction and ESI,000FFFFFh ; isolate fraction or DI,DI ; if op1 is a denormal _if e ; then inc DI ; - adjust exponent by 1 _loop ; - loop (normalize it) 27-jul-90 dec DI ; - - decrement exponent _shl EAX,1 ; - - shift left 1 _rcl EDX,1 ; - - ... test EDX,00100000h ; - - check for implied 1 bit _until ne ; - until normalized _endif ; endif or EDX,00100000h ; turn on implied 1 bit or CX,CX ; if op2 is a denormal _if e ; then inc CX ; - adjust exponent by 1 _loop ; - loop (normalize it) 27-jul-90 dec CX ; - - decrement exponent _shl EBX,1 ; - - shift left 1 _rcl ESI,1 ; - - ... test ESI,00100000h ; - - check for implied 1 bit _until ne ; - until normalized _endif ; endif or ESI,00100000h ; turn on implied 1 bit _guess ; guess: overflow add CX,DI ; - determine exponent of result sub CX,03ffh ; - remove extra bias _quif s ; - quit if exponent is negative cmp CX,07FFh ; - quit if not overflow _quif b ; - . . . mov EAX,ECX ; - put sign into EAX pop ESI ; - restore ESI pop EDI ; - restore EDI pop EBP ; - restore EBP jmp F8OverFlow ; - handle overflow _endguess ; endguess cmp CX,-53 ; if exponent is too small _if l ; then underflow pop ESI ; - restore ESI pop EDI ; - restore EDI pop EBP ; - restore EBP jmp F8UnderFlow ; - handle underflow _endif ; endif push ECX ; save sign and exponent mov CL,11 ; shift fractions to top of registers shld EDX,EAX,CL ; ... shld EAX,EBP,CL ; ... and EAX,0FFFFF800h ; ... shld ESI,EBX,CL ; ... shld EBX,EBP,CL ; ... and EBX,0FFFFF800h ; ... sub EBP,EBP ; zero EBP push ESI ; save high part of op2 push EDX ; save high part of op1 push EAX ; save low part of op1 mul EBX ; low part of op1 * low part of op2 xchg EAX,ESI ; ESI becomes start of the sticky bits mov ECX,EDX ; save high part of result pop EDX ; restore low part of op1 mul EDX ; low part of op1 * high part of op2 mov EDI,EDX ; save high part of product add ECX,EAX ; add partial product adc EDI,EBP ; ... adc EBP,EBP ; ... pop EAX ; restore high part of op1 xchg EAX,EBX ; flip with low part of op2 mul EBX ; high part of op1 * low part of op2 add ECX,EAX ; add partial product adc EDI,EDX ; ... adc EBP,0 ; ... mov EAX,EBX ; get high part of op1 pop EDX ; restore high part of op2 mul EDX ; high part of op1 * high part of op2 add EAX,EDI ; add partial product adc EDX,EBP ; ... sub EBX,EBX ; get zero for zero fill mov CL,10 ; shift result over shrd EBX,EAX,CL ; ... get sticky bits 18-feb-91 shrd EAX,EDX,CL ; ... shrd EDX,EBX,CL ; ... pop ECX ; restore sign and exponent _loop ; loop test EDX,00200000h ; - test to see if bit in exponent field _quif e ; - quit if not shr EDX,1 ; - shift result right rcr EAX,1 ; - . . . rcr EBX,1 ; - save carry inc CX ; - inc exponent for every shift cmp CX,07FFh ; - quit if overflow je mul_oflow ; - . . . _endloop ; endloop _shl EBX,1 ; get guard bit _if c ; if set _if e ; - if rest of sticky bits are 0 or ESI,ESI ; - - check the bottom sticky bits setne BL ; - - ... shr EBX,1 ; - - if all sticky bits are zero _if nc ; - - then mov ESI,EAX ; - - - get bottom bit of result shr ESI,1 ; - - - as rounding bit _endif ; - - endif _endif ; - endif adc EAX,0 ; - round up adc EDX,0 ; - ... test EDX,00200000h ; - test to see if bit in exponent field _if ne ; - if fraction overflowed shr EDX,1 ; - - shift right rcr EAX,1 ; - - ... inc CX ; - - increment exponent cmp CX,07FFh ; - - quit if overflow je mul_oflow ; - - . . . _endif ; - endif _endif ; endif or CX,CX ; if exponent <= 0 _if le ; then (denormal result) _if e ; - if exponent = 0 mov CL,1 ; - - set shift count to 1 _else ; - else neg CX ; - - negate to get shift count dec CX ; - - adjust _endif ; - endif sub EBX,EBX ; - for zero fill shrd EAX,EDX,CL ; - align the fraction shrd EDX,EBX,CL ; - ... sub CX,CX ; - set exponent to 0 _endif ; endif and EDX,000FFFFFh ; isolate fraction mov ESI,ECX ; get copy of sign ror ECX,11 ; get exponent _shl ESI,1 ; get sign rcr ECX,1 ; put it in and ECX,0FFF00000h ; isolate sign and exponent or EDX,ECX ; place it in result pop ESI ; restore ESI pop EDI ; restore EDI pop EBP ; restore EBP ret ; return mul_oflow: ; overflow mov EAX,ECX ; get sign of infinity pop ESI ; restore ESI pop EDI ; restore EDI pop EBP ; restore EBP jmp F8OverFlow ; handle overflow endproc __FDM endmod end