📄 fp.asm
字号:
or ax, si
jnz FMulDone
;
; If underflow occurs, set the result to zero.
;
mov fpacc.exponent, ax
mov fpacc.sign, al
;
FMulDone: pop di
pop si
pop dx
pop cx
pop bx
pop ax
pop ds
ret
sl_fmul endp
assume ds:nothing
;
;
;
;
; Mul64- Multiplies the 8 bytes in fpacc.mant by the 8 bytes in fpop.mant
; and leaves the result in fprod.
;
Mul64 proc near
assume ds:StdGrp
xor ax, ax
mov fprod[0], ax
mov fprod[2], ax
mov fprod[4], ax
mov fprod[6], ax
mov fprod[8], ax
mov fprod[10], ax
mov fprod[12], ax
mov fprod[14], ax
;
; Computing the following (each character represents 16-bits):
;
; A B C D
; x E F G H
; -------
;
; Product is computed by:
;
; A B C D
; x E F G H
; ----------
; HD
; HC0
; HB00
; HA000
; GD0
; GC00
; GB000
; GA0000
; FD00
; FC000
; FB0000
; FA00000
; ED000
; EC0000
; EB00000
; + EA000000
; ----------
; xxxxxxxx
;
; In the loop below, si indexes through A, B, C, and D above (or E, F, G,
; and H since multiplication is commutative).
;
mov si, ax ;Set Index to zero.
flp1: mov ax, fpacc.mantissa[si] ;Multiply A, B, C, or D
mul fpop.mantissa[0] ; by H.
add fprod [si], ax ;Add it into the partial
adc fprod+2 [si], dx ; product computed so far.
jnc NoCarry0
inc fprod+4 [si]
jnz NoCarry0
inc fprod+6 [si]
jnz NoCarry0
inc fprod+8 [si]
jnz NoCarry0
inc fprod+10 [si]
jnz NoCarry0
inc fprod+12 [si]
jnz NoCarry0
inc fprod+14 [si]
;
NoCarry0:
mov ax, fpacc.mantissa[si] ;Multiply A, B, C, or D
mul fpop.mantissa[2] ; (selected by SI) by G
add fprod+2 [si], ax ; and add it into the
adc fprod+4 [si], dx ; partial product.
jnc NoCarry1
inc fprod+6 [si]
jnz NoCarry1
inc fprod+8 [si]
jnz NoCarry1
inc fprod+10 [si]
jnz NoCarry1
inc fprod+12 [si]
jnz NoCarry1
inc fprod [14]
;
NoCarry1:
mov ax, fpacc.mantissa [si] ;Multiply A, B, C, or D
mul fpop.mantissa [4] ; (SI selects) by F and add
add fprod+4 [si], ax ; it into the partial prod.
adc fprod+6 [si], dx
jnc NoCarry2
inc fprod+8 [si]
jnz NoCarry2
inc fprod+10 [si]
jnz NoCarry2
inc fprod+12 [si]
jnz NoCarry2
inc fprod+14 [si]
;
NoCarry2:
mov ax, fpacc.mantissa [si] ;Multiply A/B/C/D (selected
mul fpop.mantissa [6] ; by SI) by E and add it
add fprod+6 [si], ax ; into the partial product.
adc fprod+8 [si], dx
jnc NoCarry3
inc fprod+10 [si]
jnz NoCarry3
inc fprod+12 [si]
jnz NoCarry3
inc fprod+14 [si]
;
NoCarry3:
inc si ;Select next multiplier
inc si ; (B, C, or D above).
cmp si, 8 ;Repeat for 64 bit x 64 bit
jnb QuitMul64 ; multiply.
jmp flp1
QuitMul64: ret
assume ds:nothing
Mul64 endp
;
;
;
;
;
;
;
;
;---------------------------------------------------------------------------
; Floating Point Division
;---------------------------------------------------------------------------
;
;
;
;
; Floating point division: Divides fpacc by fpop.
;
public sl_fdiv
sl_fdiv proc far
assume ds:StdGrp
push ds
push ax
push bx
push cx
push dx
push si
push di
push bp
;
mov ax, StdGrp
mov ds, ax
;
; See if either operand is zero:
;
mov ax, fpacc.mantissa[0] ;No need to check exponent!
or ax, fpacc.mantissa[2]
or ax, fpacc.mantissa[4]
or ax, fpacc.mantissa[6]
jz QuoIsZero
;
mov ax, fpop.mantissa[0]
or ax, fpop.mantissa[2]
or ax, fpop.mantissa[4]
or ax, fpop.mantissa[6]
jnz DenomNotZero
;
; Whoops! Division by zero! Set to largest possible value (+inf) and leave.
;
DivOvfl: mov ax, 0ffffh
mov fpacc.exponent, ax
mov fpacc.mantissa[0], ax
mov fpacc.mantissa[2], ax
mov fpacc.mantissa[4], ax
mov fpacc.mantissa[6], ax
mov al, fpop.sign
xor fpacc.sign, al
;
; Note: we could also do an INT 0 (div by zero) or floating point exception
; here, if necessary.
;
jmp FDivDone
;
;
; If the numerator is zero, the quotient is zero. Handle that here.
;
QuoIsZero: xor ax, ax ;Need this!
mov fpacc.sign, al
mov fpacc.exponent, ax
mov fpacc.mantissa[0], ax
mov fpacc.mantissa[2], ax
mov fpacc.mantissa[4], ax
mov fpacc.mantissa[6], ax
jmp FDivDone
;
;
;
; If both operands are non-zero, compute the quotient down here.
;
DenomNotZero: mov al, fpop.sign ;Compute the new sign.
xor fpacc.sign, al
;
mov ax, fpop.exponent ;Compute new exponent.
sub ax, 7fffh ;Subtract BIAS.
mov bx, fpacc.exponent
sub bx, 7fffh
sub bx, ax ;Compute new exponent
jo DivOvfl
add bx, 7fffh ;Add in BIAS
mov fpacc.exponent, bx ;Save as new exponent.
;
; Okay, compute the quotient of the mantissas down here.
;
call Div64
;
; Normalize the Quotient.
;
mov cx, fpacc.exponent
jmp short TestNrmDiv
;
; Normalize by shifting 16 bits at a time here.
;
NrmDiv1: sub cx, 16
mov ax, fpacc.mantissa[4]
mov fpacc.mantissa[6], ax
mov ax, fpacc.mantissa[2]
mov fpacc.mantissa[4], ax
mov ax, fpacc.mantissa[0]
mov fpacc.mantissa[2], ax
mov fpacc.mantissa[0], 0
TestNrmDiv: cmp cx, 16
jb DoNrmDiv8
mov ax, fpacc.mantissa[6]
or ax, ax
jz NrmDiv1
;
; Normalize by shifting eight bits at a time here.
;
; See if we can shift the product a whole byte
;
DoNrmDiv8: cmp byte ptr fpacc.mantissa[7], 0
jnz DoOneBitsDiv
cmp cx, 8
jb DoOneBitsDiv
mov ax, fpacc.mantissa[5]
mov fpacc.mantissa[6], ax
mov ax, fpacc.mantissa[3]
mov fpacc.mantissa[4], ax
mov ax, fpacc.mantissa[1]
mov fpacc.mantissa[2], ax
mov al, byte ptr fpacc.mantissa[0]
mov byte ptr fpacc.mantissa[1], al
mov byte ptr fpacc.mantissa[0], 0
sub cx, 8
;
DoOneBitsDiv: mov ax, fpacc.mantissa[6]
mov bx, fpacc.mantissa[4]
mov dx, fpacc.mantissa[2]
mov si, fpacc.mantissa[0]
jmp short TestOneBitsDiv
;
; One bit at a time normalization here.
;
OneBitLoopDiv: shl si, 1
rcl dx, 1
rcl bx, 1
rcl ax, 1
dec cx
TestOneBitsDiv: jcxz StoreQuo
test ah, 80h
jz OneBitLoopDiv
;
StoreQuo: mov fpacc.mantissa[6], ax
mov fpacc.mantissa[4], bx
mov fpacc.mantissa[2], dx
mov fpacc.mantissa[0], si
mov fpacc.exponent, cx
or ax, bx
or ax, dx
or ax, si
jnz FDivDone
;
; If underflow occurs, set the result to zero.
;
mov fpacc.exponent, ax
mov fpacc.sign, al
;
FDivDone: pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
pop ds
ret
sl_fdiv endp
assume ds:nothing
;
;
;
;
; Div64- Divides the 64-bit fpacc.mantissa by the 64-bit fpop.mantissa.
;
div64 proc near
assume ds:StdGrp
;
;
; First, normalize fpop if necessary and possible:
;
mov ax, fpop.mantissa[6]
mov bx, fpop.mantissa[4]
mov cx, fpop.mantissa[2]
mov dx, fpop.mantissa[0]
mov si, fpacc.exponent
jmp short Div16NrmTest
;
; The following loop normalizes fpop 16 bits at a time.
;
Div16NrmLp: mov ax, bx
mov bx, dx
mov cx, dx
xor dx, dx
add si, 16
Div16NrmTest: cmp si, -16
ja Div16Nrm8 ;Must be unsigned because this
or ax, ax ; is bias arithmetic, not
jz Div16NrmLp ; two's complement!
;
;
; The following code checks to see if it can normalize by eight bits at
; a time.
;
Div16Nrm8: cmp si, -8
ja Div1NrmTest ;Must be unsigned!
cmp ah, 0
jnz Div1NrmTest
mov ah, al
mov al, bh
mov bh, bl
mov bl, ch
mov ch, cl
mov cl, dh
mov dh, dl
mov dl, 0
add si, 8
jmp short Div1NrmTest
;
; Down here we're stuck with the slow task of normalizing by a bit
; at a time.
;
Div1NrmLp: shl dx, 1
rcl cx, 1
rcl bx, 1
rcl ax, 1
inc si
Div1NrmTest: cmp si, -1
je DivOvfl2 ;Can't do it!
test ah, 80h
jz Div1NrmLp
jmp short DoSlowDiv
;
; If overflow occurs, set FPACC to the maximum possible value and quit.
;
DivOvfl2: mov ax, 0ffffh
mov fpacc.exponent, ax
mov fpacc.mantissa[0], ax
mov fpacc.mantissa[2], ax
mov fpacc.mantissa[4], ax
mov fpacc.mantissa[6], ax
jmp QuitDiv
;
; Oh No! A GawdAwful bit-by-bit division routine. Terribly slow!
; Actually, it was sped up a little by checking to see if it could
; shift eight or sixteen bits at a time (because it encounters eight
; or sixteen zeros during the division).
;
; Could possibly speed this up some more by checking for the special
; case of n/16 bits. Haven't tried this idea out though.
;
DoSlowDiv: mov fpacc.exponent, si
mov si, ax
mov di, bx
mov fpop.mantissa[2], cx
mov fpop.mantissa[0], dx
mov ax, fpacc.mantissa[6]
mov bx, fpacc.mantissa[4]
mov cx, fpacc.mantissa[2]
mov dx, fpacc.mantissa[0]
mov bp, 64
DivideLoop: cmp bp, 16
jb Test8
or ax, ax
jnz Test8
;
; Do a shift by 16 bits here:
;
mov ax, Quotient[4]
mov Quotient[6], ax
mov ax, Quotient[2]
mov Quotient[4], ax
mov ax, Quotient[0]
mov Quotient[2], ax
mov Quotient[0], 0
mov ax, bx
mov bx, cx
mov cx, dx
xor dx, dx
sub bp, 16
jnz DivideLoop
jmp FinishDivide
;
Test8: cmp bp, 8
jb Do1
cmp ah, 0
jnz Do1
;
; Do a shift by 8 bits here:
;
push ax
mov ax, Quotient[5]
mov Quotient[6], ax
mov ax, Quotient[3]
mov Quotient[4], ax
mov ax, Quotient[1]
mov Quotient[2], ax
mov al, byte ptr Quotient [0]
mov byte ptr Quotient [1], al
mov byte ptr Quotient[0], 0
pop ax
mov ah, al
mov al, bh
mov bh, bl
mov bl, ch
mov ch, cl
mov cl, dh
mov dh, dl
mov dl, 0
sub bp, 8
jz FinishDivide2
jmp DivideLoop
FinishDivide2: jmp FinishDivide
;
Do1: cmp ax, si
jb shift0
ja Shift1
cmp bx, di
jb shift0
ja Shift1
cmp cx, fpop.mantissa[2]
jb shift0
ja shift1
cmp dx, fpop.mantissa[0]
jb shift0
;
; fpacc.mantiss IS greater than fpop.mantissa, shift a one bit into
; the result here:
;
Shift1: stc
rcl Quotient[0], 1
rcl Quotient[2], 1
rcl Quotient[4], 1
rcl Quotient[6], 1
sub dx, fpop.mantissa[0]
sbb cx, fpop.mantissa[2]
sbb bx, di
sbb ax, si
shl dx, 1
rcl cx, 1
rcl bx, 1
rcl ax, 1 ;Never a carry out.
dec bp
jnz jDivideLoop
jmp FinishDivide
;
; If fpacc.mantissa was less than fpop.mantissa, shift a zero bit into
; the quotient.
;
Shift0: shl Quotient[0], 1
rcl Quotient[2], 1
rcl Quotient[4], 1
rcl Quotient[6], 1
shl dx, 1
rcl cx, 1
rcl bx, 1
rcl ax, 1
jc Greater
dec bp
jnz jDivideLoop
jmp FinishDivide
jDivideLoop: jmp DivideLoop
;
; If there was a carry out of the shift, we KNOW that fpacc must be
; greater than fpop. Handle that case down here.
;
Greater: dec bp
jz FinishDivide
stc
rcl Quotient[0], 1
rcl Quotient[2], 1
rcl Quotient[4], 1
rcl Quotient[6], 1
sub dx, fpop.mantissa[0]
sbb cx, fpop.mantissa[2]
sbb bx, di
sbb ax, si
shl dx, 1
rcl cx, 1
rcl bx, 1
rcl ax, 1
jc Greater
dec bp
jz FinishDivide
jmp DivideLoop
;
; Okay, clean everything up down here:
;
FinishDivide: mov ax, Quotient[0]
mov fpacc.mantissa[0], ax
mov ax, Quotient[2]
mov fpacc.mantissa[2], ax
mov ax, Quotient[4]
mov fpacc.mantissa[4], ax
mov ax, Quotient[6]
mov fpacc.mantissa[6], ax
;
QuitDiv: ret
assume ds:nothing
div64 endp
;
;
;
;
;
;---------------------------------------------------------------------------
; Floating Point => TEXT (Output) conversion routines.
;---------------------------------------------------------------------------
;
;
;
;
; Power of ten tables used by the floating point I/O routines.
;
; Format for each entry (13 bytes):
;
; 1st through
; 11th bytes Internal FP format for this particular number.
;
; 12th &
; 13th bytes: Decimal exponent for this value.
;
;
; This first table contains the negative powers of ten as follows:
;
; for n:= 0 to 12 do
; entry [12-n] := 10 ** (-2 ** n)
; entry [13] := 1.0
;
PotTbln dw 9fdeh, 0d2ceh, 4c8h, 0a6ddh, 4ad8h ; 1e-4096
db 0 ; Sign
dw -4096 ; Dec Exponent
;
dw 2de4h, 3436h, 534fh, 0ceaeh, 656bh ; 1e-2048
db 0
dw -2048
;
dw 0c0beh, 0da57h, 82a5h, 0a2a6h, 72b5h ; 1e-1024
db 0
dw -1024
;
dw 0d21ch, 0db23h, 0ee32h, 9049h, 795ah ; 1e-512
db 0
dw -512
;
dw 193ah, 637ah, 4325h, 0c031h, 7cach ; 1e-256
db 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -