fsmath.asm
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 493 行 · 第 1/2 页
ASM
493 行
;*****************************************************************************
;*
;* 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!
;*
;*****************************************************************************
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>
;<> real*4 math library for Graphics Library
;<>
;<> inputs: DX,AX - operand 1 (high word, low word resp. ) (op1)
;<> CX,BX - operand 2 (op2)
;<>
;<> operations are performed as op1 (*) op2 where (*) is the selected
;<> operation
;<>
;<> output: DX,AX - result (high word, low word resp. )
;<>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
include mdef.inc
include struct.inc
xref F4DivZero ; Fstatus
xref F4OverFlow ; Fstatus
xref F4UnderFlow ; Fstatus
modstart grmath,WORD
xdefp __FSA ; add real*4 to real*4
xdefp __FSS ; subtract real*4 from real*4
xdefp __FSM ; 4-byte real multiply
xdefp __FSD ; 4-byte real divide
defp __FSS
jcxz ret_op1 ; if op2 is 0 then return operand 1
xor CH,80h ; flip the sign of op2 and add
defp __FSA
jcxz ret_op1 ; if op2 is 0 then return operand 1
or DX,DX ; if op1 is 0
_if e ; then
mov DX,CX ; - return operand 2
mov AX,BX ; - . . .
ret_op1: ret ; - return
_endif ; endif
push DI ; save DI
xchg AX,BX ; flip registers around
xchg AX,DX ; . . .
;
; now have:
; AX:BX
; +- CX:DX
;<> Scheme for calculating sign of result:
;<> The sign word is built and kept in DL
;<> Bits 0 and 1 hold the sum of the sign bits
;<> shifted out of op_1 and op_2
;<> Bit 2 holds the sign of the larger operand. It is assumed to be
;<> op_1 until op_2 is found larger
mov DI,DX ; put low order word of op2 in DI
sub DX,DX ; clear DX
_shl AX,1 ; get exponent of op1 into AH
_rcl DL,1 ;
mov DH,DL ;
_shl DL,1 ;
_shl DL,1 ;
add DL,DH ;
stc ; put implied 1 bit into top bit of
rcr AL,1 ; ... fraction
_shl CX,1 ; get exponent of op2 into CH
adc DL,0 ;
stc ; put implied 1 bit into top bit
rcr CL,1 ; ... of fraction
mov DH,AH ; assume op1 > op2
sub AH,CH ; calculate difference in exponents
_if ne ; if different
_if b ; - if op1 < op2
mov DH,CH ; - - get larger exponent for result
neg AH ; - - negate the shift count
xchg AL,CL ; - - flip operands
xchg BX,DI ; - - . . .
xor DL,4
;<> op_2 is larger, so its sign now occupies bit 2 of sign word. This
;<> information is only correct if the signs of op-1 and op-2 are different.
;<> Since we look past bit 1 for sign only if the signs are different, bit2
;<> will supply the correct information when it is needed. We get the sign of
;<> op_2 by flipping the sign of op_1, already in bit 2
_endif ; - endif
mov CH,AH ; - get shift count
mov AH,0 ; - zero guard byte
_loop ; - loop (align fractions)
shr CL,1 ; - - shift over fraction
rcr DI,1 ; - - . . .
dec CH ; - - decrement shift count
_until e ; - until fractions aligned
rcr AH,1 ; - only need last bit in guard byte
;<> bit 7 of the guard byte holds an extra significant bit from mantissa
;<> of the operand we shifted left to allign with the greater operand
;<> it is added or subtracted from with operands by shifting the bit into
;<> the carry bit just before the operation
_endif ; endif
shr DL,1 ; get bit 0 of sign word - value is 0 if
; both operands have same sign, 1 if not
_if nc ; if signs are the same
add BX,DI ; - add the fractions
adc AL,CL ; - . . .
_if c ; - if carry
rcr AL,1 ; - - shift fraction right 1 bit
rcr BX,1 ; - - . . .
rcr AH,1 ; - - save extra sig bit in guard bit
inc DH ; - - increment exponent
_if z ; - - if we overflowed
ror dl,1 ; - - - set sign of infinity
rcr ah,1 ; - - - . . .
jmp add_oflow ; - - - handle overflow
_endif ; - - endif
_endif ; - endif
_else ; else (signs are different)
shr DL,1 ; - skip junk bit
rol AH,1 ; - get guard bit
ror AH,1 ; - and put it back
sbb BX,DI ; - subtract the fractions
sbb AL,CL ; - . . .
_guess ; - guess
_quif nc ; - - quit if no borrow
inc DL ; - - sign := sign of op_2
not AL ; - - negate the fraction (considering
; - - the guard bit an extension of the
not BX ; - - fraction)
neg AH ; - - . . .
sbb BX,-1 ; - - . . .
sbb AL,-1 ; - - . . .
_admit ; - admit
cmp AL,0 ; - - quit if answer is not 0
_quif ne ; - - . . .
or BX,BX ; - - . . .
_quif ne ; - - . . .
sub AX,AX ; - - set result to 0
sub DX,DX ; - - . . .
pop DI ; - - restore DI
ret ; - - return (answer is 0)
_endguess ; - endguess
_endif ; endif
; normalize the fraction
_shl AH,1 ; get guard bit
adc BX,0 ; round up fraction if required
adc AL,0 ; . . .
_guess underflow ; guess
_quif nc ; - quit if round up didn't overflow frac
inc DH ; - adjust exponent
_admit ; admit
_loop ; - loop (shift until high bit appears)
_rcl BX,1 ; - - shift fraction left
_rcl AL,1 ; - - . . .
_quif c,underflow ; - - quit if carry has appeared
dec DH ; - - decrement exponent
_until e ; - until underflow
jmp add_uflow ; - handle underflow
_endguess ; endguess
mov AH,DH ; get exponent
ror DL,1 ; get sign bit
rcr AX,1 ; shift it into result
rcr BX,1 ; . . .
mov DX,AX ; get result in DX:AX
mov AX,BX ; . . .
pop DI ; restore DI
ret ; return
add_uflow: ; handle underflow
pop DI ; restore DI
jmp F4UnderFlow ; goto underflow routine
add_oflow: ; handle overflow
pop DI ; restore DI
jmp F4OverFlow ; handle overflow
endproc __FSA
endproc __FSS
;=====================================================================
defp __FSM
;<> 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
_guess ; guess: answer not 0
or DX,DX ; - see if first arg is zero
_quif e ; - quit if op1 is 0
or CX,CX ; - quit if op2 is 0
jne __FSMEmu
_endguess ; endguess
sub AX,AX ; set answer to 0
sub DX,DX ; . . .
ret ; return
__FSMEmu:
push SI ; save SI
push DI ; save DI
xchg AX,BX ; flip registers around
xchg AX,DX ; . . .
;
; now have:
; AX:BX
; * CX:DX
;
mov DI,BX ; move arguments to better registers
mov BX,AX ; . . .
mov SI,DX ; move X1 to less volatile register
_shl BX,1 ; move sign of X
_rcl AL,1 ; into AL
stc ; rotate implied high bit into X
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?