fpuatofl.asm
来自「工欲善其事」· 汇编 代码 · 共 309 行
ASM
309 行
; #########################################################################
;
; FpuAtoFL
;
;##########################################################################
; -----------------------------------------------------------------------
; This procedure was written by Raymond Filiatreault, December 2002
;
; This FpuAtoFL function converts a decimal number from a zero terminated
; alphanumeric string format (Src) to an 80-bit REAL number and returns
; the result as an 80-bit REAL number at the specified destination (the
; FPU itself or a memory location), unless an invalid operation is
; reported by the FPU or the definition of the parameters (with uID) is
; invalid.
;
; The source can be a string in regular numeric format or in scientific
; notation. The number of digits (including leading 0's) must not exceed
; 18. If in scientific format, the exponent must be within +/-4931
;
; The source is checked for validity. The procedure returns an error if
; a character other than those acceptable is detected prior to the
; terminating zero or the above limits are exceeded.
;
; This procedure is based on converting the digits into a specific packed
; decimal format which can be used by the FPU and then adjusted for an
; exponent of 10.
;
; Only EAX is used to return error or success. All other registers are
; preserved.
;
; -----------------------------------------------------------------------
.486
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include Fpu.inc
.data
tempdw dd 0
bcdstr dt 0
stword dw 0
ten dd 10
.code
; #########################################################################
FpuAtoFL proc public lpSrc:DWORD, lpDest:DWORD, uID:DWORD
finit
push ebx
push ecx
push edx
push esi
push edi
xor eax,eax
xor ebx,ebx
xor edx,edx
lea edi,bcdstr
stosd
stosd
mov [edi],ax
mov esi,lpSrc
mov ecx,19
@@:
lodsb
cmp al," "
jz @B ;eliminate leading spaces
or al,al ;is string empty?
jnz @F
atoflerr:
xor eax,eax
pop edi
pop esi
pop edx
pop ecx
pop ebx
ret
;----------------------
;check for leading sign
;----------------------
@@:
cmp al,"+"
jz @F
cmp al,"-"
jnz integer
mov ah,80h
@@:
mov [edi+1],ah ;put sign byte in bcd string
xor eax,eax
lodsb
;------------------------------------
;convert the digits to packed decimal
;------------------------------------
integer:
cmp al,"."
jnz @F
test bh,1
jnz atoflerr ;only one decimal point allowed
or bh,1 ;use bh to set the decimal point flag
lodsb
@@:
cmp al,"e"
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before e
jmp scient
@@:
cmp al,"E"
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before E
jmp scient
@@:
or al,al
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before terminating 0
jmp laststep
@@:
sub al,"0"
jc atoflerr ;unacceptable character
cmp al,9
ja atoflerr ;unacceptable character
test bh,1
jnz @F
inc bl
@@:
dec ecx
jz atoflerr ;error if more than 18 digits in number
mov ah,al
lodsb
cmp al,"."
jnz @F
test bh,1
jnz atoflerr ;only one decimal point allowed
or bh,1 ;use bh to set the decimal point flag
lodsb
@@:
cmp al,"e"
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before e
mov al,0
rol al,4
ror ax,4
mov [edi],al
jmp scient
@@:
cmp al,"E"
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before E
mov al,0
rol al,4
ror ax,4
mov [edi],al
jmp scient
@@:
or al,al
jnz @F
cmp cl,19
jz atoflerr ;error if no digit before terminating 0
rol al,4
ror ax,4
mov [edi],al
jmp laststep
@@:
sub al,"0"
jc atoflerr ;unacceptable character
cmp al,9
ja atoflerr ;unacceptable character
test bh,1
jnz @F
inc bl
@@:
dec ecx
jz atoflerr ;error if more than 18 digits in number
rol al,4
ror ax,4
mov [edi],al
dec edi
lodsb
jmp integer
laststep:
fbld bcdstr
xor eax,eax
mov al,18
sub al,bl
sub edx,eax
call XexpY
fmul
fstsw stword ;retrieve exception flags from FPU
fwait
test stword,1 ;test for invalid operation
jnz srcerr ;clean-up and return error
mov eax,lpDest
test uID,DEST_FPU ;check where result should be stored
jnz @F ;leave result on FPU if so indicated
fstp tbyte ptr [eax] ;store result at specified address
@@:
or al,1 ;to insure EAX!=0
@@:
pop edi
pop esi
pop edx
pop ecx
pop ebx
ret
srcerr:
finit
xor eax,eax
jmp @B
scient:
xor eax,eax
lodsb
cmp al,"+"
jz @F
cmp al,"-"
jnz scient1
stc
rcr eax,1 ;keep sign of exponent in most significant bit of EAX
@@:
lodsb ;get next digit after sign
scient1:
push eax
and eax,0ffh
jnz @F ;continue if 1st byte of exponent is not terminating 0
scienterr:
pop eax
jmp atoflerr ;no exponent
@@:
sub al,30h
jc scienterr ;unacceptable character
cmp al,9
ja scienterr ;unacceptable character
push eax
mov eax,edx
mul ten
mov edx,eax
pop eax
add edx,eax
cmp edx,4931
ja scienterr ;exponent too large
lodsb
or al,al
jnz @B
pop eax ;retrieve exponent sign flag
rcl eax,1 ;is most significant bit set?
jnc @F
neg edx
@@:
jmp laststep
FpuAtoFL endp
; #########################################################################
;put 10 to the proper exponent (value in EDX) on the FPU
XexpY:
mov tempdw,edx
fild tempdw ;load the exponent
fldl2t ;load log2(10)
fmul ;->log2(10)*exponent
;at this point, only the log base 2 of the 10^exponent is on the FPU
;the FPU can compute the antilog only with the mantissa
;the characteristic of the logarithm must thus be removed
fld st(0) ;copy the logarithm
frndint ;keep only the characteristic
fsub st(1),st ;keeps only the mantissa
fxch ;get the mantissa on top
f2xm1 ;->2^(mantissa)-1
fld1
fadd ;add 1 back
;the number must now be readjusted for the characteristic of the logarithm
fscale ;scale it with the characteristic
;the characteristic is still on the FPU and must be removed
fxch ;bring it back on top
fstp st(0) ;clean-up the register
ret
;##########################################################################
end
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?