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 + -
显示快捷键?