mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-18 04:43:06 +03:00
7ad5e56087
git-svn-id: svn://kolibrios.org@704 a494cfbc-eb01-0410-851d-a64ba20cac60
992 lines
31 KiB
NASM
992 lines
31 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!
|
|
;*
|
|
;*****************************************************************************
|
|
|
|
|
|
; static char sccs_id[] = "@(#)patch32.asm 1.12 12/21/94 14:53:51";
|
|
;
|
|
; This code is being published by Intel to users of the Pentium(tm)
|
|
; processor. Recipients are authorized to copy, modify, compile, use and
|
|
; distribute the code.
|
|
;
|
|
; Intel makes no warranty of any kind with regard to this code, including
|
|
; but not limited to, implied warranties or merchantability and fitness for
|
|
; a particular purpose. Intel assumes no responsibility for any errors that
|
|
; may appear in this code.
|
|
;
|
|
; No patent licenses are granted, express or implied.
|
|
;
|
|
;
|
|
include mdef.inc
|
|
|
|
.386
|
|
.387
|
|
|
|
DENOM EQU 0
|
|
NUMER EQU 12
|
|
PREV_CW EQU 28 ; 24 + 4 (return size)
|
|
PATCH_CW EQU 32 ; 28 + 4 (return size)
|
|
|
|
DENOM_SAVE EQU 32
|
|
|
|
MAIN_DENOM EQU 4
|
|
MAIN_NUMER EQU 16
|
|
|
|
SPILL_SIZE EQU 12
|
|
MEM_OPERAND EQU 8
|
|
STACK_SIZE EQU 44
|
|
SPILL_MEM_OPERAND EQU 20
|
|
|
|
ONESMASK EQU 0e000000h
|
|
|
|
SINGLE_NAN EQU 07f800000h
|
|
DOUBLE_NAN EQU 07ff00000h
|
|
|
|
ILLEGAL_OPC EQU 6
|
|
|
|
f_stsw macro where
|
|
fstsw where
|
|
endm
|
|
|
|
fdivr_st MACRO reg_index, reg_index_minus1
|
|
fstp tbyte ptr [esp+DENOM]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fstp tbyte ptr [esp+NUMER]
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld tbyte ptr [esp+NUMER]
|
|
fxch st(reg_index)
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
fdivr_sti MACRO reg_index, reg_index_minus1
|
|
fstp tbyte ptr [esp+NUMER]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fstp tbyte ptr [esp+DENOM]
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld tbyte ptr [esp+NUMER]
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
fdivrp_sti MACRO reg_index, reg_index_minus1
|
|
fstp tbyte ptr [esp+NUMER]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fstp tbyte ptr [esp+DENOM]
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
fdiv_st MACRO reg_index, reg_index_minus1
|
|
fstp tbyte ptr [esp+NUMER]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld st
|
|
fstp tbyte ptr [esp+DENOM]
|
|
fstp tbyte ptr [esp+DENOM_SAVE] ; save original denom,
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld tbyte ptr [esp+DENOM_SAVE]
|
|
fxch st(reg_index)
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
fdiv_sti MACRO reg_index, reg_index_minus1
|
|
fxch st(reg_index)
|
|
fstp tbyte ptr [esp+NUMER]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld st
|
|
fstp tbyte ptr [esp+DENOM]
|
|
fstp tbyte ptr [esp+DENOM_SAVE] ; save original denom,
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fld tbyte ptr [esp+DENOM_SAVE]
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
fdivp_sti MACRO reg_index, reg_index_minus1
|
|
fstp tbyte ptr [esp+DENOM]
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
fstp tbyte ptr [esp+NUMER]
|
|
call fdiv_main_routine
|
|
IF reg_index_minus1 GE 1
|
|
fxch st(reg_index_minus1)
|
|
ENDIF
|
|
add esp, STACK_SIZE
|
|
ENDM
|
|
|
|
_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
|
|
_TEXT ENDS
|
|
|
|
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
|
|
_DATA ENDS
|
|
|
|
CONST SEGMENT DWORD USE32 PUBLIC 'DATA'
|
|
CONST ENDS
|
|
|
|
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
|
|
_BSS ENDS
|
|
|
|
DGROUP GROUP CONST,_DATA,_BSS
|
|
|
|
|
|
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
|
|
|
|
fdiv_risc_table DB 0, 1, 0, 0, 4, 0, 0, 7, 0, 0, 10, 0, 0, 13, 0, 0
|
|
fdiv_scale_1 DD 03f700000h ;0.9375
|
|
fdiv_scale_2 DD 03f880000h ;1.0625
|
|
one_shl_63 DD 05f000000h
|
|
|
|
|
|
dispatch_table DD offset label0
|
|
DD offset label1
|
|
DD offset label2
|
|
DD offset label3
|
|
DD offset label4
|
|
DD offset label5
|
|
DD offset label6
|
|
DD offset label7
|
|
DD offset label8
|
|
DD offset label9
|
|
DD offset label10
|
|
DD offset label11
|
|
DD offset label12
|
|
DD offset label13
|
|
DD offset label14
|
|
DD offset label15
|
|
DD offset label16
|
|
DD offset label17
|
|
DD offset label18
|
|
DD offset label19
|
|
DD offset label20
|
|
DD offset label21
|
|
DD offset label22
|
|
DD offset label23
|
|
DD offset label24
|
|
DD offset label25
|
|
DD offset label26
|
|
DD offset label27
|
|
DD offset label28
|
|
DD offset label29
|
|
DD offset label30
|
|
DD offset label31
|
|
DD offset label32
|
|
DD offset label33
|
|
DD offset label34
|
|
DD offset label35
|
|
DD offset label36
|
|
DD offset label37
|
|
DD offset label38
|
|
DD offset label39
|
|
DD offset label40
|
|
DD offset label41
|
|
DD offset label42
|
|
DD offset label43
|
|
DD offset label44
|
|
DD offset label45
|
|
DD offset label46
|
|
DD offset label47
|
|
DD offset label48
|
|
DD offset label49
|
|
DD offset label50
|
|
DD offset label51
|
|
DD offset label52
|
|
DD offset label53
|
|
DD offset label54
|
|
DD offset label55
|
|
DD offset label56
|
|
DD offset label57
|
|
DD offset label58
|
|
DD offset label59
|
|
DD offset label60
|
|
DD offset label61
|
|
DD offset label62
|
|
DD offset label63
|
|
|
|
_DATA ENDS
|
|
|
|
|
|
_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
|
|
|
|
|
|
assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:nothing
|
|
|
|
;
|
|
; PRELIMINARY VERSION for register-register divides.
|
|
;
|
|
|
|
|
|
; In this implementation the
|
|
; fdiv_main_routine is called,
|
|
; therefore all the stack frame
|
|
; locations are adjusted for the
|
|
; return pointer.
|
|
|
|
fdiv_main_routine PROC NEAR
|
|
|
|
fld tbyte ptr [esp+MAIN_NUMER] ; load the numerator
|
|
fld tbyte ptr [esp+MAIN_DENOM] ; load the denominator
|
|
retry:
|
|
|
|
; The following three lines test for denormals and zeros.
|
|
; A denormal or zero has a 0 in the explicit digit to the left of the
|
|
; binary point. Since that bit is the high bit of the word, adding
|
|
; it to itself will produce a carry if and only if the number is not
|
|
; denormal or zero.
|
|
;
|
|
mov eax, [esp+MAIN_DENOM+4] ; get mantissa bits 32-64
|
|
add eax,eax ; shift the one's bit onto carry
|
|
jnc denormal ; if no carry, we're denormal
|
|
|
|
; The following three lines test the three bits after the four bit
|
|
; pattern (1,4,7,a,d). If these three bits are not all one, then
|
|
; the denominator cannot expose the flaw. This condition is tested by
|
|
; inverting the bits and testing that all are equal to zero afterward.
|
|
|
|
xor eax, ONESMASK ; invert the bits that must be ones
|
|
test eax, ONESMASK ; and make sure they are all ones
|
|
jz scale_if_needed ; if all are one scale numbers
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
;
|
|
; Now we test the four bits for one of the five patterns.
|
|
;
|
|
scale_if_needed:
|
|
shr eax, 28 ; keep first 4 bits after point
|
|
cmp byte ptr fdiv_risc_table[eax], 0 ; check for (1,4,7,a,d)
|
|
jnz divide_scaled ; are in potential problem area
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
divide_scaled:
|
|
mov eax, [esp + MAIN_DENOM+8] ; test denominator exponent
|
|
and eax, 07fffh ; if pseudodenormal ensure that only
|
|
jz invalid_denom ; invalid exception flag is set
|
|
cmp eax, 07fffh ; if NaN or infinity ensure that only
|
|
je invalid_denom ; invalid exception flag is set
|
|
;
|
|
; The following six lines turn off exceptions and set the
|
|
; precision control to 80 bits. The former is necessary to
|
|
; force any traps to be taken at the divide instead of the scaling
|
|
; code. The latter is necessary in order to get full precision for
|
|
; codes with incoming 32 and 64 bit precision settings. If
|
|
; it can be guaranteed that before reaching this point, the underflow
|
|
; exception is masked and the precision control is at 80 bits, these
|
|
; six lines can be omitted.
|
|
;
|
|
fnstcw [esp+PREV_CW] ; save caller's control word
|
|
mov eax, [esp+PREV_CW]
|
|
or eax, 033fh ; mask exceptions, pc=80
|
|
and eax, 0f3ffh ; set rounding mode to nearest
|
|
mov [esp+PATCH_CW], eax
|
|
fldcw [esp+PATCH_CW] ; mask exceptions & pc=80
|
|
|
|
; The following lines check the numerator exponent before scaling.
|
|
; This in order to prevent undeflow when scaling the numerator,
|
|
; which will cause a denormal exception flag to be set when the
|
|
; actual divide is preformed. This flag would not have been set
|
|
; normally. If there is a risk of underflow, the scale factor is
|
|
; 17/16 instead of 15/16.
|
|
;
|
|
mov eax, [esp+MAIN_NUMER+8] ; test numerator exponent
|
|
and eax, 07fffh
|
|
cmp eax, 00001h
|
|
je small_numer
|
|
|
|
fmul fdiv_scale_1 ; scale denominator by 15/16
|
|
fxch
|
|
fmul fdiv_scale_1 ; scale numerator by 15/16
|
|
fxch
|
|
|
|
;
|
|
; The next line restores the users control word. If the incoming
|
|
; control word had the underflow exception masked and precision
|
|
; control set to 80 bits, this line can be omitted.
|
|
;
|
|
|
|
fldcw [esp+PREV_CW] ; restore caller's control word
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
small_numer:
|
|
fmul fdiv_scale_2 ; scale denominator by 17/16
|
|
fxch
|
|
fmul fdiv_scale_2 ; scale numerator by 17/16
|
|
fxch
|
|
|
|
;
|
|
; The next line restores the users control word. If the incoming
|
|
; control word had the underflow exception masked and precision
|
|
; control set to 80 bits, this line can be omitted.
|
|
;
|
|
|
|
fldcw [esp+PREV_CW] ; restore caller's control word
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
denormal:
|
|
mov eax, [esp+MAIN_DENOM] ; test for whole mantissa == 0
|
|
or eax, [esp+MAIN_DENOM+4] ; test for whole mantissa == 0
|
|
jnz denormal_divide_scaled ; denominator is not zero
|
|
invalid_denom: ; zero or invalid denominator
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
denormal_divide_scaled:
|
|
mov eax, [esp + MAIN_DENOM + 8] ; get exponent
|
|
and eax, 07fffh ; check for zero exponent
|
|
jnz invalid_denom ;
|
|
;
|
|
; The following six lines turn off exceptions and set the
|
|
; precision control to 80 bits. The former is necessary to
|
|
; force any traps to be taken at the divide instead of the scaling
|
|
; code. The latter is necessary in order to get full precision for
|
|
; codes with incoming 32 and 64 bit precision settings. If
|
|
; it can be guaranteed that before reaching this point, the underflow
|
|
; exception is masked and the precision control is at 80 bits, these
|
|
; five lines can be omitted.
|
|
;
|
|
|
|
fnstcw [esp+PREV_CW] ; save caller's control word
|
|
mov eax, [esp+PREV_CW]
|
|
or eax, 033fh ; mask exceptions, pc=80
|
|
and eax, 0f3ffh ; set rounding mode to nearest
|
|
mov [esp+PATCH_CW], eax
|
|
fldcw [esp+PATCH_CW] ; mask exceptions & pc=80
|
|
|
|
mov eax, [esp + MAIN_NUMER +8] ; test numerator exponent
|
|
and eax, 07fffh ; check for denormal numerator
|
|
je denormal_numer
|
|
cmp eax, 07fffh ; NaN or infinity
|
|
je invalid_numer
|
|
mov eax, [esp + MAIN_NUMER + 4] ; get bits 32..63 of mantissa
|
|
add eax, eax ; shift the first bit into carry
|
|
jnc invalid_numer ; if there is no carry, we have an
|
|
; invalid numer
|
|
jmp numer_ok
|
|
|
|
denormal_numer:
|
|
mov eax, [esp + MAIN_NUMER + 4] ; get bits 32..63 of mantissa
|
|
add eax, eax ; shift the first bit into carry
|
|
jc invalid_numer ; if there is a carry, we have an
|
|
; invalid numer
|
|
|
|
numer_ok:
|
|
fxch
|
|
fstp st ; pop numerator
|
|
fld st ; make copy of denominator
|
|
fmul dword ptr[one_shl_63] ; make denominator not denormal
|
|
fstp tbyte ptr [esp+MAIN_DENOM] ; save modified denominator
|
|
fld tbyte ptr [esp+MAIN_NUMER] ; load numerator
|
|
fxch ; restore proper order
|
|
fwait
|
|
|
|
; The next line restores the users control word. If the incoming
|
|
; control word had the underflow exception masked and precision
|
|
; control set to 80 bits, this line can be omitted.
|
|
;
|
|
|
|
fldcw [esp+PREV_CW] ; restore caller's control word
|
|
jmp retry ; start the whole thing over
|
|
|
|
invalid_numer:
|
|
;
|
|
; The next line restores the users control word. If the incoming
|
|
; control word had the underflow exception masked and precision
|
|
; control set to 80 bits, this line can be omitted.
|
|
;
|
|
fldcw [esp + PREV_CW]
|
|
fdivp st(1), st ; use of hardware is OK.
|
|
ret
|
|
|
|
fdiv_main_routine ENDP
|
|
|
|
public __fdiv_fpr
|
|
defpe __fdiv_fpr
|
|
|
|
sub esp, STACK_SIZE
|
|
jmp dword ptr dispatch_table[eax*4]
|
|
|
|
|
|
label0:
|
|
fdiv st,st(0) ; D8 F0 FDIV ST,ST(0)
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label1:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label2:
|
|
fdivr st,st(0) ; D8 F8 FDIVR ST,ST(0)
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label3:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label4:
|
|
fdiv st(0),st ; DC F8/D8 F0 FDIV ST(0),ST
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label5:
|
|
fdivp st(0),st ; DE F8 FDIVP ST(0),ST
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label6:
|
|
fdivr st(0),st ; DC F0/DE F0 FDIVR ST(0),ST
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label7:
|
|
fdivrp st(0),st ; DE F0 FDIVRP ST(0),ST
|
|
add esp, STACK_SIZE
|
|
ret
|
|
label8:
|
|
fdiv_st 1, 0
|
|
ret
|
|
label9:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label10:
|
|
fdivr_st 1, 0
|
|
ret
|
|
label11:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label12:
|
|
fdiv_sti 1, 0
|
|
ret
|
|
label13:
|
|
fdivp_sti 1, 0
|
|
ret
|
|
label14:
|
|
fdivr_sti 1, 0
|
|
ret
|
|
label15:
|
|
fdivrp_sti 1, 0
|
|
ret
|
|
label16:
|
|
fdiv_st 2, 1
|
|
ret
|
|
label17:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label18:
|
|
fdivr_st 2, 1
|
|
ret
|
|
label19:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label20:
|
|
fdiv_sti 2, 1
|
|
ret
|
|
label21:
|
|
fdivp_sti 2, 1
|
|
ret
|
|
label22:
|
|
fdivr_sti 2, 1
|
|
ret
|
|
label23:
|
|
fdivrp_sti 2, 1
|
|
ret
|
|
label24:
|
|
fdiv_st 3, 2
|
|
ret
|
|
label25:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label26:
|
|
fdivr_st 3, 2
|
|
ret
|
|
label27:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label28:
|
|
fdiv_sti 3, 2
|
|
ret
|
|
label29:
|
|
fdivp_sti 3, 2
|
|
ret
|
|
label30:
|
|
fdivr_sti 3, 2
|
|
ret
|
|
label31:
|
|
fdivrp_sti 3, 2
|
|
ret
|
|
label32:
|
|
fdiv_st 4, 3
|
|
ret
|
|
label33:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label34:
|
|
fdivr_st 4, 3
|
|
ret
|
|
label35:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label36:
|
|
fdiv_sti 4, 3
|
|
ret
|
|
label37:
|
|
fdivp_sti 4, 3
|
|
ret
|
|
label38:
|
|
fdivr_sti 4, 3
|
|
ret
|
|
label39:
|
|
fdivrp_sti 4, 3
|
|
ret
|
|
label40:
|
|
fdiv_st 5, 4
|
|
ret
|
|
label41:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label42:
|
|
fdivr_st 5, 4
|
|
ret
|
|
label43:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label44:
|
|
fdiv_sti 5, 4
|
|
ret
|
|
label45:
|
|
fdivp_sti 5, 4
|
|
ret
|
|
label46:
|
|
fdivr_sti 5, 4
|
|
ret
|
|
label47:
|
|
fdivrp_sti 5, 4
|
|
ret
|
|
label48:
|
|
fdiv_st 6, 5
|
|
ret
|
|
label49:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label50:
|
|
fdivr_st 6, 5
|
|
ret
|
|
label51:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label52:
|
|
fdiv_sti 6, 5
|
|
ret
|
|
label53:
|
|
fdivp_sti 6, 5
|
|
ret
|
|
label54:
|
|
fdivr_sti 6, 5
|
|
ret
|
|
label55:
|
|
fdivrp_sti 6, 5
|
|
ret
|
|
label56:
|
|
fdiv_st 7, 6
|
|
ret
|
|
label57:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label58:
|
|
fdivr_st 7, 6
|
|
ret
|
|
label59:
|
|
add esp, STACK_SIZE
|
|
int ILLEGAL_OPC
|
|
label60:
|
|
fdiv_sti 7, 6
|
|
ret
|
|
label61:
|
|
fdivp_sti 7, 6
|
|
ret
|
|
label62:
|
|
fdivr_sti 7, 6
|
|
ret
|
|
label63:
|
|
fdivrp_sti 7, 6
|
|
ret
|
|
__fdiv_fpr ENDP
|
|
|
|
|
|
__fdivp_sti_st PROC NEAR
|
|
; for calling from mem routines
|
|
sub esp, STACK_SIZE
|
|
fdivp_sti 1, 0
|
|
ret
|
|
__fdivp_sti_st ENDP
|
|
|
|
__fdivrp_sti_st PROC NEAR
|
|
; for calling from mem routines
|
|
sub esp, STACK_SIZE
|
|
fdivrp_sti 1, 0
|
|
ret
|
|
__fdivrp_sti_st ENDP
|
|
|
|
public __fdiv_chk
|
|
defpe __fdiv_chk
|
|
; for calling from mem routines
|
|
sub esp, STACK_SIZE
|
|
fdivrp_sti 1, 0
|
|
ret
|
|
__fdiv_chk ENDP
|
|
|
|
;
|
|
; PRELIMINARY VERSIONS of the routines for register-memory
|
|
; divide instructions
|
|
;
|
|
|
|
;;; FDIV_M32 - FDIV m32real FIX
|
|
;;
|
|
;; Input : Value of the m32real in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIV in ST
|
|
|
|
PUBLIC __fdiv_m32
|
|
defpe __fdiv_m32
|
|
|
|
push eax ; save eax
|
|
mov eax, [esp + MEM_OPERAND] ; check for
|
|
and eax, SINGLE_NAN ; NaN
|
|
cmp eax, SINGLE_NAN ;
|
|
je memory_divide_m32 ;
|
|
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack ; is FP stack full?
|
|
fld dword ptr[esp + MEM_OPERAND] ; load m32real in ST
|
|
call __fdivp_sti_st ; do actual divide
|
|
pop eax
|
|
ret 4
|
|
spill_fpstack:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fld dword ptr[esp + SPILL_MEM_OPERAND] ; load m32 real
|
|
call __fdivp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivrp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret 4
|
|
memory_divide_m32:
|
|
fdiv dword ptr[esp + MEM_OPERAND] ; do actual divide
|
|
pop eax
|
|
ret 4
|
|
|
|
__fdiv_m32 ENDP
|
|
|
|
|
|
;;; FDIV_M64 - FDIV m64real FIX
|
|
;;
|
|
;; Input : Value of the m64real in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIV in ST
|
|
|
|
PUBLIC __fdiv_m64
|
|
defpe __fdiv_m64
|
|
|
|
push eax ; save eax
|
|
mov eax, [esp + MEM_OPERAND + 4] ; check for
|
|
and eax, DOUBLE_NAN ; NaN
|
|
cmp eax, DOUBLE_NAN ;
|
|
je memory_divide_m64 ;
|
|
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m64 ; is FP stack full?
|
|
fld qword ptr[esp + MEM_OPERAND] ; load m64real in ST
|
|
call __fdivp_sti_st ; do actual divide
|
|
pop eax
|
|
ret 8
|
|
spill_fpstack_m64:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp] ; save user's ST(1)
|
|
fld qword ptr[esp + SPILL_MEM_OPERAND] ; load m64real
|
|
call __fdivp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivrp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret 8
|
|
|
|
memory_divide_m64:
|
|
fdiv qword ptr[esp + MEM_OPERAND] ; do actual divide
|
|
pop eax
|
|
ret 8
|
|
|
|
__fdiv_m64 ENDP
|
|
|
|
|
|
|
|
;;; FDIVR_M32 - FDIVR m32real FIX
|
|
;;
|
|
;; Input : Value of the m32real in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIVR in ST
|
|
|
|
PUBLIC __fdiv_m32r
|
|
defpe __fdiv_m32r
|
|
push eax ; save eax
|
|
mov eax, [esp + MEM_OPERAND] ; check for
|
|
and eax, SINGLE_NAN ; NaN
|
|
cmp eax, SINGLE_NAN ;
|
|
je memory_divide_m32r ;
|
|
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m32r ; is FP stack full?
|
|
fld dword ptr[esp + MEM_OPERAND] ; load m32real in ST
|
|
call __fdivrp_sti_st ; do actual divide
|
|
pop eax
|
|
ret 4
|
|
spill_fpstack_m32r:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fld dword ptr[esp + SPILL_MEM_OPERAND] ; load m32 real
|
|
call __fdivrp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret 4
|
|
memory_divide_m32r:
|
|
fdivr dword ptr[esp + MEM_OPERAND] ; do actual divide
|
|
pop eax
|
|
ret 4
|
|
|
|
__fdiv_m32r ENDP
|
|
|
|
|
|
;;; FDIVR_M64 - FDIVR m64real FIX
|
|
;;
|
|
;; Input : Value of the m64real in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIVR in ST
|
|
|
|
PUBLIC __fdiv_m64r
|
|
defpe __fdiv_m64r
|
|
push eax ; save eax
|
|
mov eax, [esp + MEM_OPERAND + 4] ; check for
|
|
and eax, DOUBLE_NAN ; NaN
|
|
cmp eax, DOUBLE_NAN ;
|
|
je memory_divide_m64r ;
|
|
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m64r ; is FP stack full?
|
|
fld qword ptr[esp + MEM_OPERAND] ; load m64real in ST
|
|
call __fdivrp_sti_st ; do actual divide
|
|
pop eax
|
|
ret 8
|
|
spill_fpstack_m64r:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fld qword ptr[esp + SPILL_MEM_OPERAND] ; load m64real
|
|
call __fdivrp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret 8
|
|
memory_divide_m64r:
|
|
fdivr qword ptr[esp + MEM_OPERAND] ; do actual divide
|
|
pop eax
|
|
ret 8
|
|
|
|
|
|
__fdiv_m64r ENDP
|
|
|
|
comment ~******************************************************************
|
|
;;; FDIV_M16I - FDIV m16int FIX
|
|
;;
|
|
;; Input : Value of the m16int in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIV in ST
|
|
|
|
PUBLIC FDIV_M16I
|
|
FDIV_M16I PROC NEAR
|
|
push eax ; save eax
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m16i ; is FP stack full?
|
|
fild word ptr[esp + MEM_OPERAND] ; load m16int in ST
|
|
call __fdivp_sti_st ; do actual divide
|
|
pop eax
|
|
ret
|
|
spill_fpstack_m16i:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fild word ptr[esp + SPILL_MEM_OPERAND] ; load m16int
|
|
call __fdivp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivrp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret
|
|
|
|
FDIV_M16I ENDP
|
|
|
|
;;; FDIV_M32I - FDIV m16int FIX
|
|
;;
|
|
;; Input : Value of the m16int in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIV in ST
|
|
|
|
PUBLIC FDIV_M32I
|
|
FDIV_M32I PROC NEAR
|
|
push eax ; save eax
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m32i ; is FP stack full?
|
|
fild dword ptr[esp + MEM_OPERAND] ; load m32int in ST
|
|
call __fdivp_sti_st ; do actual divide
|
|
pop eax
|
|
ret
|
|
spill_fpstack_m32i:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fild dword ptr[esp + SPILL_MEM_OPERAND] ; load m32int
|
|
call __fdivp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivrp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret
|
|
|
|
|
|
FDIV_M32I ENDP
|
|
|
|
|
|
;;; FDIVR_M16I - FDIVR m16int FIX
|
|
;;
|
|
;; Input : Value of the m16int in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIVR in ST
|
|
|
|
PUBLIC FDIVR_M16I
|
|
FDIVR_M16I PROC NEAR
|
|
push eax ; save eax
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m16ir ; is FP stack full?
|
|
fild word ptr[esp + MEM_OPERAND] ; load m16int in ST
|
|
call __fdivrp_sti_st ; do actual divide
|
|
pop eax
|
|
ret
|
|
spill_fpstack_m16ir:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fild word ptr[esp + SPILL_MEM_OPERAND] ; load m16int
|
|
call __fdivrp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret
|
|
|
|
|
|
FDIVR_M16I ENDP
|
|
|
|
|
|
;;; FDIVR_M32I - FDIVR m32int FIX
|
|
;;
|
|
;; Input : Value of the m32int in the top of STACK
|
|
;;
|
|
;; Output: Result of FDIVR in ST
|
|
|
|
PUBLIC FDIVR_M32I
|
|
FDIVR_M32I PROC NEAR
|
|
push eax ; save eax
|
|
f_stsw ax ; get status word
|
|
and eax, 3800h ; get top of stack
|
|
je spill_fpstack_m32ir ; is FP stack full?
|
|
fild dword ptr[esp + MEM_OPERAND] ; load m32int in ST
|
|
call __fdivrp_sti_st ; do actual divide
|
|
pop eax
|
|
ret
|
|
spill_fpstack_m32ir:
|
|
fxch
|
|
sub esp, SPILL_SIZE ; make temp space
|
|
fstp tbyte ptr[esp ] ; save user's ST(1)
|
|
fild dword ptr[esp + SPILL_MEM_OPERAND] ; load m32int
|
|
call __fdivrp_sti_st ; do actual divide
|
|
fld tbyte ptr[esp] ; restore user's ST(1)
|
|
;esp is adjusted by fdivp fn
|
|
fxch
|
|
add esp, SPILL_SIZE
|
|
pop eax
|
|
ret
|
|
|
|
FDIVR_M32I ENDP
|
|
**********************************************************************~
|
|
|
|
|
|
|
|
_TEXT ENDS
|
|
|
|
end
|