chipd16.asm
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 1,168 行 · 第 1/3 页
ASM
1,168 行
;*****************************************************************************
;*
;* 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[] = "@(#)patch16.asm 1.8 12/21/94 14:53:49";
;
; 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
name fdiv_patch
_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
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 DW offset label0
DW offset label1
DW offset label2
DW offset label3
DW offset label4
DW offset label5
DW offset label6
DW offset label7
DW offset label8
DW offset label9
DW offset label10
DW offset label11
DW offset label12
DW offset label13
DW offset label14
DW offset label15
DW offset label16
DW offset label17
DW offset label18
DW offset label19
DW offset label20
DW offset label21
DW offset label22
DW offset label23
DW offset label24
DW offset label25
DW offset label26
DW offset label27
DW offset label28
DW offset label29
DW offset label30
DW offset label31
DW offset label32
DW offset label33
DW offset label34
DW offset label35
DW offset label36
DW offset label37
DW offset label38
DW offset label39
DW offset label40
DW offset label41
DW offset label42
DW offset label43
DW offset label44
DW offset label45
DW offset label46
DW offset label47
DW offset label48
DW offset label49
DW offset label50
DW offset label51
DW offset label52
DW offset label53
DW offset label54
DW offset label55
DW offset label56
DW offset label57
DW offset label58
DW offset label59
DW offset label60
DW offset label61
DW offset label62
DW offset label63
;
; Stack variables for divide routines.
;
DENOM EQU 0
NUMER EQU 12
PATCH_CW EQU 28
PREV_CW EQU 24
DENOM_SAVE EQU 32
STACK_SIZE EQU 44
MAIN_DENOM EQU 0
MAIN_NUMER EQU 12
SPILL_SIZE EQU 12
if _MODEL and _BIG_CODE
MEM_OPERAND EQU 10
else
MEM_OPERAND EQU 8
endif
SPILL_MEM_OPERAND EQU (MEM_OPERAND+SPILL_SIZE)
;
; Stack frame locations for MS C/C++
;
SINGLE1 EQU 6 + STACK_SIZE
SINGLE2 EQU 10 + STACK_SIZE
DOUBLE1 EQU 6 + STACK_SIZE
DOUBLE2 EQU 14 + STACK_SIZE
LDOUBLE1 EQU 6 + STACK_SIZE
LDOUBLE2 EQU 22 + STACK_SIZE
SRESULT EQU 14
DRESULT EQU 22
LDRESULT EQU 38
ONESMASK EQU 0e00h
SINGLE_NAN EQU 07f80h
DOUBLE_NAN EQU 07ff0h
ILLEGAL_OPC EQU 6
f_stsw macro where
fstsw where
endm
fdivr_st MACRO reg_index, reg_index_minus1
fstp tbyte ptr [bp+DENOM]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fstp tbyte ptr [bp+NUMER]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld tbyte ptr [bp+NUMER]
fxch st(reg_index)
add sp, STACK_SIZE ; update stack
ENDM
fdivr_sti MACRO reg_index, reg_index_minus1
fstp tbyte ptr [bp+NUMER]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fstp tbyte ptr [bp+DENOM]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld tbyte ptr [bp+NUMER]
add sp, STACK_SIZE ; update stack
ENDM
fdivrp_sti MACRO reg_index, reg_index_minus1
fstp tbyte ptr [bp+NUMER]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fstp tbyte ptr [bp+DENOM]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
add sp, STACK_SIZE ; update stack
ENDM
fdiv_st MACRO reg_index, reg_index_minus1
fstp tbyte ptr [bp+NUMER]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld st
fstp tbyte ptr [bp+DENOM]
fstp tbyte ptr [bp+DENOM_SAVE]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld tbyte ptr [bp+DENOM_SAVE]
fxch st(reg_index)
add sp, STACK_SIZE ; update stack
ENDM
fdiv_sti MACRO reg_index, reg_index_minus1
fxch st(reg_index)
fstp tbyte ptr [bp+NUMER]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld st
fstp tbyte ptr [bp+DENOM]
fstp tbyte ptr [bp+DENOM_SAVE]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fld tbyte ptr [bp+DENOM_SAVE]
add sp, STACK_SIZE ; update stack
ENDM
fdivp_sti MACRO reg_index, reg_index_minus1
fstp tbyte ptr [bp+DENOM]
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
fstp tbyte ptr [bp+NUMER]
call fdiv_main_routine
IF reg_index_minus1 GE 1
fxch st(reg_index_minus1)
ENDIF
add sp, STACK_SIZE ; update stack
ENDM
assume cs:_TEXT, ds:nothing, ss:nothing
; 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 [bp+MAIN_NUMER] ; load the numerator
fld tbyte ptr [bp+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 ax, [bp+MAIN_DENOM+6] ; get mantissa bits 48-64
add ax,ax ; shift one's bit into carry
jnc denormal ; if no carry, we have a 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 ax, ONESMASK ; invert the bits that must be one
test ax, ONESMASK ; test for needed bits
jz scale_if_needed ; if all one, it may need scalling
fdivp st(1), st ; OK to use the hardware
ret
;
; Now we test the four bits for one of the five patterns.
;
scale_if_needed:
shr ax, 12 ; keep first four bits after point
push bx ; save bx
mov bx,ax ; bx = index
cmp byte ptr fdiv_risc_table[bx], 0 ; check for (1,4,7,a,d)
pop bx ; restore bx
jnz divide_scaled
fdivp st(1), st ; OK to use the hardware
ret
divide_scaled:
mov ax, [bp + MAIN_DENOM+8] ; test denominator exponent
and ax, 07fffh ; if pseudodenormal ensure that only
jz invalid_denom ; invalid exception flag is set
cmp ax, 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
; five lines can be omitted.
;
fnstcw [bp+PREV_CW] ; save caller's control word
mov ax, [bp+PREV_CW]
or ax, 033fh ; mask exceptions, pc=80
and ax, 0f3ffh ; set rounding mode to nearest
mov [bp+PATCH_CW], ax
fldcw [bp+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 ax, [bp+MAIN_NUMER+8] ; test numerator exponent
and ax, 07fffh
cmp ax, 00001h
je small_numer
; perform scaling of both numerator and denominator
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 [bp+PREV_CW] ; restore caller's control word
fdivp st(1), st ; OK to use the hardware
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 [bp+PREV_CW] ; restore caller's control word
fdivp st(1), st ; OK to use the hardware
ret
denormal:
mov eax, [bp+MAIN_DENOM] ; test for whole mantissa == 0
or eax, [bp+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 ; OK to use the hardware
ret
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?