;***************************************************************************** ;* ;* 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 .8087 modstart div386 xref __8087 ; indicate that NDP instructions are present datasegment extrn __real87 : byte ; 8087.asm extrn __chipbug: byte enddata xref F8DivZero ; Fstatus xref F8OverFlow ; Fstatus xref F8UnderFlow ; Fstatus xref __fdiv_m64 xdefp __FDD ; double __FDD( double , double ) sign equ -12 den equ sign-8 quot equ den-12 lo equ 0 hi equ 4 defpe __FDD or EBX,EBX ; if low word of divisor is 0 _if e ; then _shl ECX,1 ; - shift sign of divisor into carry _if e ; - if divisor is zero jmp F8DivZero ; - - handle divide by zero _endif ; - endif rcr ECX,1 ; - restore sign of divisor _endif ; endif or EAX,EAX ; check dividend for zero _if e ; if so then _shl EDX,1 ; - save sign of dividend _if e ; - if dividend is 0 ret ; - - return _endif ; - endif rcr EDX,1 ; - restore sign of dividend _endif ; endif cmp byte ptr __real87,0 ; if no 80x87 is present je short __FDDemu ; then emulate __FDD87: push EDX ; push operand 1 push EAX ; . . . fld qword ptr [ESP] ; load operand 1 push ECX ; push operand 2 push EBX ; . . . test byte ptr __chipbug,1 ; have we got a bad divider? _if ne ; then call __fdiv_m64 ; - call support rtn for divide _else ; else fdiv qword ptr [ESP] ; - divide operand 1 by operand 2 add ESP,8 ; - clean up stack _endif ; endif fstp qword ptr [ESP] ; store result fwait ; wait pop EAX ; load result into DX:AX 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 __FDDemu: push EBP ; save EBP mov EBP,ESP ; get access to stack push EDI ; save EDI push ESI ; and ESI 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 DI,CX ; 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 _else ; else (denormal) _loop ; - loop (normalize it) _shl EAX,1 ; - - shift fraction left _rcl EDX,1 ; - - . . . dec DI ; - - decrement exponent test EDX,00100000h ; - - until implied 1 bit is on _until ne ; - until implied 1 bit is on _endif ; endif or CX,CX ; if op2 is not a denormal _if ne ; then or ESI,00100000h ; - turn on implied 1 bit _else ; else (denormal) _loop ; - loop (normalize it) _shl EBX,1 ; - - shift fraction left _rcl ESI,1 ; - - . . . dec CX ; - - decrement exponent test ESI,00100000h ; - - until implied 1 bit is on _until ne ; - until implied 1 bit is on _endif ; endif sub DI,CX ; calculate exponent of result add DI,03ffh ; add in removed bias _guess ; guess: overflow _quif s ; - quit if exponent is negative cmp DI,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 DI,-52 ; 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 EDI ; 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 ; ... push ESI ; save divisor push EBX ; ... mov ECX,ESI ; get top part of divisor mov EDI,EDX ; get dividend mov ESI,EAX ; ... sub EAX,EAX ; assume top bit is 0 cmp ECX,EDX ; check high parts _if be ; if hi(divisor) <= hi(dividend) sub EDX,ECX ; - subtract divisor from dividend inc EAX ; - set quotient to 1 _endif ; endif push EAX ; save high word of quotient mov EAX,ESI ; get low part of dividend div ECX ; estimate next word of quotient push EAX ; save estimate of quotient (quot+4[EBP]) xchg EAX,EBX ; save quot., get low word of divisor mul EBX ; calc. estimate * lo(divisor) xchg EAX,ECX ; ... xchg EBX,EDX ; save partial product mul EDX ; calc. estimate * hi(divisor) add EAX,EBX ; add to partial product adc EDX,0 ; ... mov EBX,den+lo[EBP] ; get low word of divisor test byte ptr quot+8[EBP],1 ; if high word of quot is 1 _if ne ; then add EAX,EBX ; - add in divisor adc EDX,den+hi[EBP] ; - ... _endif ; endif ; subtract estimate * divisor from dividend neg ECX ; 0 - ECX sbb ESI,EAX ; ... sbb EDI,EDX ; ... _if ne ; if high word not 0 (quotient too big) _loop ; - loop (find correct quotient) sub dword ptr quot+4[EBP],1; - - decrement quotient sbb dword ptr quot+8[EBP],0; - - ... add ECX,EBX ; - - add divisor back to dividend adc ESI,den+hi[EBP] ; - - ... adc EDI,0 ; - - ... _until e ; - until done _endif ; endif mov EDI,ESI ; get new dividend mov ESI,ECX ; ... mov ECX,den+hi[EBP] ; get divisor cmp ECX,EDI ; check high parts 13-aug-90 _if be ; if hi(divisor) <= hi(dividend) sub EDI,ECX ; - subtract divisor from dividend add dword ptr quot+4[EBP],1 ; - increment quotient adc dword ptr quot+8[EBP],0 ; - ... _endif ; endif mov EDX,EDI ; get dividend into EDX:EAX mov EAX,ESI ; ... div ECX ; estimate next word of quotient push EAX ; save estimate of quotient (-4[EBP]) or EAX,EAX ; if quotient non-zero _if ne ; then xchg EAX,EBX ; - save quot., get low word of divisor mul EBX ; - calc. estimate * lo(divisor) xchg EAX,ECX ; - ... xchg EBX,EDX ; - save partial product mul EDX ; - calc. estimate * hi(divisor) add EAX,EBX ; - add to partial product adc EDX,0 ; - ... ; - subtract estimate * divisor from dividend neg ECX ; - 0 - ECX sbb ESI,EAX ; - ... sbb EDI,EDX ; - ... _if ne ; - if high word not 0 (quotient too big) _loop ; - - loop (find correct quotient) sub dword ptr quot+0[EBP],1; - - - decrement quotient sbb dword ptr quot+4[EBP],0; - - - ... sbb dword ptr quot+8[EBP],0; - - - ... add ECX,den+lo[EBP] ; - - - add divisor back to dividend adc ESI,den+hi[EBP] ; - - - ... adc EDI,0 ; - - - ... _until e ; - - until done _endif ; - endif _endif ; endif pop EAX ; get quotient pop EDX ; ... pop EBX ; get high bit add ESP,8 ; remove divisor pop EDI ; restore sign and exponent dec DI ; decrement exponent shr EBX,1 ; if non-zero _if c ; then rcr EDX,1 ; - shift answer right rcr EAX,1 ; - ... inc EDI ; - increment exponent _endif ; endif sub ESI,ESI ; get zero for zero fill mov CL,11 ; shift result over shrd EAX,EDX,CL ; ... rcr ESI,1 ; save carry shrd EDX,ESI,CL ; ... or EDX,0FFF00000h ; turn top bits all on _shl ESI,1 ; get guard bit adc EAX,0 ; round up adc EDX,0 ; ... adc EDI,0 ; increment exponent if required or DI,DI ; if exponent <= 0 _if le ; then (denormal result) _if e ; - if exponent = 0 mov CL,1 ; - - set shift count to 1 _else ; - else neg DI ; - - negate to get shift count mov CX,DI ; - - ... _endif ; - endif and EDX,001FFFFFh ; - isolate fraction sub EBX,EBX ; - for zero fill shrd EAX,EDX,CL ; - align the fraction shrd EDX,EBX,CL ; - ... sub DI,DI ; - set exponent to 0 _endif ; endif and EDX,000FFFFFh ; isolate fraction mov ESI,EDI ; get copy of sign ror EDI,11 ; get exponent _shl ESI,1 ; get sign rcr EDI,1 ; put it in and EDI,0FFF00000h ; isolate sign and exponent or EDX,EDI ; place it in result pop ESI ; restore registers pop EDI ; ... pop EBP ; ... ret ; return endproc __FDD endmod end