mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1036 lines
29 KiB
Plaintext
1036 lines
29 KiB
Plaintext
;
|
|
; File: ELEMS020_2.a
|
|
;
|
|
; Contains: xxx put contents here xxx
|
|
;
|
|
; Written by: The Apple Numerics Group
|
|
;
|
|
; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; This file is used in these builds: Mac32
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM2> 2/3/93 CSS Update from Horror:
|
|
; <H2> 9/29/92 BG Rolling in Jon Okada's latest fixes.
|
|
; <1> 11/14/90 BG Added to BBS for the first time.
|
|
;
|
|
; To Do:
|
|
;
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; CHANGE HISTORY, kept for historical purposes:
|
|
;
|
|
; 21 MAY 90 Signal underflow for all inexact, subnormal results
|
|
; of EXP and EXP2 [see EXPROOT below] and do faster test
|
|
; for extended zero [see EXP1ROOT and EXPAPPROX below] (JPO)
|
|
; 29 APR 92 Filter out very large and small magnitude inputs for
|
|
; exponential functions, thus avoiding spurious exceptions and
|
|
; large magnitude SCALB factors (JPO)
|
|
;-----------------------------------------------------------
|
|
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
; EXP(x) and EXP2(x) share the same exception code. To compute
|
|
; numerical results, express result as 2^K * ((2^frac - 1) + 1),
|
|
; and use EXPAPPROX to figure (2^frac - 1).
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
|
|
EXPTOP:
|
|
SUBQ.B #1,D1 ; HAVE SUB #CLINF ALREADY
|
|
; BEQ.S P1STUFF ; EXP(+-0) IS +1 MOVED below <4/29/92, JPO>
|
|
BGT.S EXPNONZERO
|
|
BEQ.S P1STUFF ; EXP(+-0) IS +1 <4/29/92, JPO>
|
|
|
|
TST.W D1
|
|
BMI.S P0STUFF ; EXP(-INF) IS +0
|
|
BRA.S RESULTDELIVERED ; ALREADY HAVE +INF
|
|
|
|
;-----------------------------------------------------------
|
|
; Limit argument to range |arg| >= 2^(-64) and |arg| <= 16447. This will guarantee
|
|
; that the integral scale parameter will fit in 16-bit integer format. <4/29/92, JPO>
|
|
;-----------------------------------------------------------
|
|
EXPNONZERO:
|
|
BFEXTU (A4){1:31},D0 ; D0 <- first 32 bits of |arg| <4/29/92, JPO>
|
|
CMPI.L #$3FBF8000,D0 ; |arg| < 2.0^(-64)? <4/29/92, JPO>
|
|
BLT.B P1XSTUFF ; exp(+-tiny) is inexact +1 <4/29/92, JPO>
|
|
CMPI.L #$400D807E,D0 ; |arg| > 16447.0? <4/29/92, JPO>
|
|
BLE.B @expok ; no <4/29/92, JPO>
|
|
|
|
TST.W D1 ; yes. check sign of arg <4/29/92, JPO>
|
|
BMI P0XSTUFF ; exp(-large) underflows to zero <4/29/92, JPO>
|
|
BRA.B PINFXSTUFF ; exp(large) overflows to +INF <4/29/92, JPO>
|
|
|
|
@expok: ; label ADDED <4/29/92, JPO>
|
|
BTST #BTLOGBASE2,D3 ; NONZERO IF EXP2X
|
|
BEQ.S EXPR
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; 2^T is easy, for general T.
|
|
; Set cell W to integer part of T.
|
|
; Set T to fraction part of itself.
|
|
; Use root computation to evaluate 2^T - 1 with LOGAPPROX;
|
|
; add 1 to T, and scale by W.
|
|
;-----------------------------------------------------------
|
|
;EXP2R: ; label DELETED <4/29/92, JPO>
|
|
BSR.S SPLIT2
|
|
BRA.S EXPROOT
|
|
|
|
;-----------------------------------------------------------
|
|
; EXP(T) is just slightly more complicated than EXP2(T) above.
|
|
; Let T = K * LN(2) + F
|
|
; Then EXP(T) is 2^K + ((2^(F/LN(2)) - 1) + 1).
|
|
; So use EXP2ROOT with W set to K and T set to F/LN(2).
|
|
; Find F with REM modulo LN(2); then subtract from T and divide by LN(2)
|
|
; to get K.
|
|
;-----------------------------------------------------------
|
|
; ***NOTE*** Spurious OVERFLOW is prevented by pre-filtering of input <4/29/92, JPO>
|
|
EXPR:
|
|
BSR.S SPLIT
|
|
; BSR TESTOFLOW ; DELETED <4/29/92, JPO>
|
|
; BEQ.S EXPROOT ; DELETED <4/29/92, JPO>
|
|
|
|
; BSR FORCEINEXACT ; EITHER O/UFLOW DELETED <4/29/92, JPO>
|
|
; TST.W D1 ; OPERAND SIGN DELETED <4/29/92, JPO>
|
|
; BPL.S PINFSTUFF ; OFLOW TO +INF DELETED <4/29/92, JPO>
|
|
|
|
; BSR CLEAROFLOW ; DELETED <4/29/92, JPO>
|
|
; BSR FORCEUFLOW ; DELETED <4/29/92, JPO>
|
|
; BRA P0STUFF ; DELETED <4/29/92, JPO>
|
|
|
|
;-----------------------------------------------------------
|
|
; This is the root of V^X where V is 2 or E.
|
|
; Compute ((2^T - 1) + 1) * 2*W. EXPAPPROX gives the innermost
|
|
; expression. W is presumed to be an integer, possibly huge.
|
|
;-----------------------------------------------------------
|
|
EXPROOT:
|
|
BSR EXPAPPROX ; 2^T - 1
|
|
|
|
PEA FPK1 ; (2^T - 1) + 1
|
|
PEA (A4)
|
|
ELFADDX
|
|
|
|
MOVEA.L A4,A0 ; RESULT PTR
|
|
LEA STW(A6),A1 ; INTEGER PART
|
|
BSR SCALBXX
|
|
|
|
; TST.W 2(A4) ; if result is subnormal and inexact, DELETED <4/29/92, JPO>
|
|
; BMI.S RESULTDELIVERED ; raise UNDERFLOW exception <21 MAY 90, JPO> DELETED <4/29/92, JPO>
|
|
|
|
; BFEXTU (A4){1:15},D0 ; DELETED <4/29/92, JPO>
|
|
; BNE.S RESULTDELIVERED ; DELETED <4/29/92, JPO>
|
|
|
|
BFTST (A4){1:16} ; if result is subnormal or zero and inexact, <4/29/92, JPO>
|
|
BNE.S RESULTDELIVERED ; raise underflow exception <4/29/92, JPO>
|
|
|
|
BSR TESTINEXACT
|
|
BEQ.S RESULTDELIVERED
|
|
|
|
BSR FORCEUFLOW
|
|
BRA.S RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Given general number in T, split into integer part in W
|
|
; and fraction in T, rounding.
|
|
;-----------------------------------------------------------
|
|
SPLIT2:
|
|
MOVEA.L A4,A0
|
|
LEA STW(A6),A1
|
|
BSR A0TOA1 ; COPY T
|
|
|
|
PEA (A1) ; CELL W
|
|
ELFRINTX ; INTEGER PART OF T, ROUNDED
|
|
|
|
; BSR CLEARINEXACT ; DON'T RECORD ROUNDING ERROR DELETED <4/29/92, JPO>
|
|
|
|
PEA (A1) ; INTEGER PART
|
|
PEA (A4) ; ALL OF NUMBER
|
|
ELFSUBX
|
|
RTS
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; Split T for EXP(x) and EXP(x)-1.
|
|
; Let T = K * LN(2) + F. Want W=K and T=F/LN(2).
|
|
; Find F with REM modulo LN(2); then subtract from T and divide by LN(2)
|
|
; to get K.
|
|
;-----------------------------------------------------------
|
|
SPLIT:
|
|
MOVEA.L A4,A0 ; T POINTER
|
|
LEA STW(A6),A1 ; COPY T INTO CELL W
|
|
BSR A0TOA1
|
|
|
|
PEA FPKLOGE2 ; NEED 3 COPIES OF LN(2)
|
|
MOVE.L (SP),-(SP)
|
|
MOVE.L (SP),-(SP)
|
|
PEA (A4)
|
|
ELFREMX ; T REM LN(2) IN T
|
|
|
|
PEA (A4)
|
|
PEA (A1)
|
|
ELFSUBX ; T - (T REM LN(2)) IN W
|
|
|
|
PEA (A1)
|
|
ELFDIVX ; T - (T REM...) / LN(2)
|
|
PEA (A1)
|
|
ELFRINTX ; MAKE SURE IT'S AN INT
|
|
|
|
PEA (A4)
|
|
ELFDIVX ; (T REM LN(2)) / LN(2)
|
|
|
|
; BRA CLEARINEXACT ; ...AND EXIT DELETED <4/29/92, JPO>
|
|
RTS ; EXIT <4/29/92, JPO>
|
|
|
|
;-----------------------------------------------------------
|
|
; EXP(x)-1 and EXP2(x)-1 share the same exception code. They both exploit
|
|
; EXPAPPROX for the root computation 2^frac - 1.
|
|
;-----------------------------------------------------------
|
|
EXP1TOP:
|
|
SUBQ.B #1,D1 ; SUBTRACTED #CLINF BEFORE
|
|
BGT.S EXP1FINITE ; FINITE, NONZERO
|
|
BEQ.S EXPEASY ; Y^+-0 - 1 IS +-0
|
|
|
|
TST.W D1 ; TEST SIGN OF INF
|
|
BMI M1STUFF ; Y^-INF - 1 IS -1
|
|
EXPEASY:
|
|
BRA RESULTDELIVERED ; Y^+INF - 1 IS +INF
|
|
EXP1FINITE:
|
|
;-----------------------------------------------------------
|
|
; If the number is denormalized, have easy case whether EXP1 or EXP21.
|
|
; Have subtracted #CLZERO so far. Subtracting 1 more from D1.B leaves
|
|
; 0 if normalized, 1 if denormalized.
|
|
;-----------------------------------------------------------
|
|
; SUBQ.B #1,D1 ; 0-NORM 1-DENORM DELETED <4/29/92, JPO>
|
|
|
|
;-----------------------------------------------------------
|
|
; Limit argument to range -64.0 <= arg <= +16384. This will guarantee
|
|
; that the integral scale parameter will fit in 16-bit integer format. <4/29/92, JPO>
|
|
;-----------------------------------------------------------
|
|
BFEXTU (A4){1:31},D0 ; D0 <- first 32 bits of |arg| <4/29/92, JPO>
|
|
TST.W D1 ; check sign of arg <4/29/92, JPO>
|
|
BPL.B @exp1pos ; check for overflow <4/29/92, JPO>
|
|
|
|
CMPI.L #$40058000,D0 ; arg < -64.0 <4/29/92, JPO>
|
|
BLE.B @exp1ok ; no. <4/29/92, JPO>
|
|
BRA M1XSTUFF ; yes, return -1.0 and signal inexact <4/29/92, JPO>
|
|
|
|
@exp1pos:
|
|
CMPI.L #$400D8000,D0 ; arg > 16384? <4/29/92, JPO>
|
|
BGT PINFXSTUFF ; yes, overflow to +INF <4/29/92, JPO>
|
|
@exp1ok: ; label ADDED <4/29/92, JPO>
|
|
BTST #BTLOGBASE2,D3 ; NONZERO IF EXP2X
|
|
BEQ.S EXP1R
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; As above, for 2^T-1 split T into fraction part in T and integer
|
|
; in W, and go to root computation.
|
|
;-----------------------------------------------------------
|
|
;EXP21R: ; label DELETED <4/29/92, JPO>
|
|
; TST.B D1 ; DELETED <4/29/92, JPO>
|
|
; BEQ.S EXP21RNORM ; DELETED <4/29/92, JPO>
|
|
|
|
CMPI.L #$3FBF8000,D0 ; |arg| < 2.0^(-64)? <4/29/92, JPO>
|
|
BGE.B EXP21RNORM ; no <4/29/92, JPO>
|
|
|
|
PEA FPKLOGE2 ; 2^T-1 IS T*LN(2) FOR TINY T
|
|
PEA (A4)
|
|
ELFMULX
|
|
EXP1OUT:
|
|
; BSR FORCEUFLOW ; DELETED <4/29/92, JPO>
|
|
; BSR FORCEINEXACT ; DELETED <4/29/92, JPO>
|
|
; BRA.S EXP1RDONE ; DELETED <4/29/92, JPO>
|
|
BRA TINYX ; <4/29/92, JPO>
|
|
|
|
EXP21RNORM:
|
|
BSR SPLIT2 ; ???? WAS BSR.S
|
|
BRA.S EXP1ROOT
|
|
|
|
;-----------------------------------------------------------
|
|
; For E^T-1, split T into K and F/LN(2), where T = K*LN(2) + F.
|
|
; If overflow, then force INF or -1...
|
|
;-----------------------------------------------------------
|
|
EXP1R:
|
|
; TST.B D1 ; DELETED <4/29/92, JPO>
|
|
; BNE.S EXP1OUT ; E^T-1 IS T, WITH UFLOW FOR NOW DELETED <4/29/92, JPO>
|
|
|
|
CMPI.L #$3FBF8000,D0 ; |arg| < 2.0^(-64)? <4/29/92, JPO>
|
|
BLT.B EXP1OUT ; yes, return arg with proper flags <4/29/92, JPO>
|
|
|
|
; BSR.S SPLIT ; DELETED <4/29/92, JPO>
|
|
BSR SPLIT ; word branch <4/29/92, JPO>
|
|
; BSR TESTOFLOW ; DELETED <4/29/92, JPO>
|
|
; BEQ.S EXP1ROOT ; DELETED <4/29/92, JPO>
|
|
|
|
; BSR FORCEINEXACT ; EITHER O/UFLOW DELETED <4/29/92, JPO>
|
|
; TST.W D1 ; OPERAND SIGN DELETED <4/29/92, JPO>
|
|
; BPL PINFSTUFF ; OFLOW TO +INF DELETED <4/29/92, JPO>
|
|
|
|
; BSR CLEAROFLOW ; LEAVE INEXACT SET DELETED <4/29/92, JPO>
|
|
; BRA M1STUFF ; FORCE -1 DELETED <4/29/92, JPO>
|
|
|
|
;-----------------------------------------------------------
|
|
; This is the root of V^X-1 where V is 2 or E.
|
|
; Compute (2^T - 1) for fraction T. Then if (integer) W is
|
|
; nonzero, finish off with (((2^T - 1) + 1) * 2^W) - 1.
|
|
;-----------------------------------------------------------
|
|
EXP1ROOT:
|
|
BSR.S EXPAPPROX ; 2^T - 1
|
|
|
|
MOVE.L 2+STW(A6),D0 ; quick check if W = 0.0
|
|
OR.L 6+STW(A6),D0
|
|
BEQ.S EXP1RDONE
|
|
|
|
PEA FPK1 ; (2^T - 1) + 1
|
|
PEA (A4)
|
|
ELFADDX
|
|
|
|
MOVEA.L A4,A0 ; RESULT PTR
|
|
LEA STW(A6),A1 ; INTEGER PART
|
|
BSR SCALBXX ; ((2^T - 1) + 1) * 2^W
|
|
|
|
PEA FPK1 ; FINALLY, SUBTRACT 1
|
|
PEA (A4)
|
|
ELFSUBX
|
|
|
|
;-----------------------------------------------------------
|
|
; Reset underflow, which cannot occur if W (as in 2^W) is nonzero.
|
|
;-----------------------------------------------------------
|
|
; BSR CLEARUFLOW ; DELETED <4/29/92, JPO>
|
|
|
|
EXP1RDONE:
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Compute approximate (2^T - 1) for T in (A4).
|
|
; Uses cells X and Y, regs D0-D2/A0-A2.
|
|
; Expression has the form
|
|
; ( 2 * T * P(T*T) ) / ( Q(T*T) - (T * P(T*T)) )
|
|
; One special case: if T is 0, just return 0, and don't set
|
|
; the inexact flag.
|
|
;-----------------------------------------------------------
|
|
EXPAPPROX:
|
|
MOVE.L 2(A4),D0 ; fast comparison of input with 0.0
|
|
OR.L 6(A4),D0
|
|
BNE.S EXPHARD
|
|
RTS ; EASY IF 0
|
|
EXPHARD:
|
|
LEA STY(A6),A1 ; CELL Y
|
|
MOVEA.L A4,A0
|
|
BSR A0TOA1 ; COPY INPUT T
|
|
|
|
PEA (A1)
|
|
PEA (A1)
|
|
ELFMULX ; T^2 INTO CELL Y
|
|
|
|
LEA STX(A6),A0 ; PLACE P(Y) INTO X
|
|
LEA EXP21P,A1 ; EXPONENT P COEFS
|
|
LEA STY(A6),A2 ; VAR IS T^2 IN Y
|
|
BSR POLYEVAL
|
|
|
|
PEA STX(A6)
|
|
PEA (A4)
|
|
ELFMULX ; T * P(T^2) IN RESULT
|
|
|
|
LEA STX(A6),A0 ; PLACE Q(Y) INTO X
|
|
LEA EXP21Q,A1
|
|
LEA STY(A6),A2
|
|
BSR POLYEVAL
|
|
|
|
PEA (A4)
|
|
PEA STX(A6)
|
|
ELFSUBX ; Q(Y) - T*P(Y)
|
|
|
|
PEA FPK2 ; 2.0
|
|
PEA (A4) ; Y*P(Y)
|
|
ELFMULX
|
|
|
|
PEA STX(A6)
|
|
PEA (A4)
|
|
ELFDIVX
|
|
|
|
;-----------------------------------------------------------
|
|
; Finally, set inexact and clear any underflow messages.
|
|
;-----------------------------------------------------------
|
|
BSR FORCEINEXACT
|
|
; BRA CLEARUFLOW ; AND EXIT... DELETED <4/29/92, JPO>
|
|
RTS ; EXIT <4/29/92, JPO>
|
|
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
; XPWRITOP---Raise extended dst to integer src power.
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
XPWRITOP:
|
|
MOVEA.L D4,A0 ; SRC PTR
|
|
MOVE.W (A0),D2 ; I OVERWRITES BOGUS CLASS
|
|
BEQ P1STUFF ; ANY^0 IS 1
|
|
|
|
SUBQ.B #1,D1 ; #CLINF ALREADY SUBTRACTED
|
|
BGT.S FINPWRI ; GT MEANS NONZERO^I
|
|
|
|
;-----------------------------------------------------------
|
|
; Get here if INF^I or 0^I. If I is negative, must reciprocate
|
|
; (signaling div by 0 in case of 0^-N). If I is even, must clear
|
|
; sign.
|
|
;-----------------------------------------------------------
|
|
ASR.W #1,D2 ; GET ODD BIT OF I INTO C,X
|
|
BCS.S @1 ; CARRY SET IF ODD
|
|
BCLR #7,(A4) ; ABS OF DST (LEAVES X BIT ALONE)
|
|
@1:
|
|
ADDX.W D2,D2 ; REGAIN ORIGINAL VALUE I
|
|
BPL RESULTDELIVERED ; (INF OR ZERO)^POS ???? WAS BPL.S
|
|
|
|
TST.B D1 ; INF OR ZERO?
|
|
BPL.S ZPWRNEG
|
|
|
|
TST.B (A4)
|
|
BPL P0STUFF ; +INF^NEG IS +0
|
|
BRA M0STUFF ; -INF^NEG IS -0
|
|
ZPWRNEG:
|
|
TST.B (A4)
|
|
BPL DIVP0STUFF ; +0^NEG IS +INF
|
|
BRA DIVM0STUFF ; -0^NEG IS -INF
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; NONZERO^I is broken into two cases:
|
|
; If I is small, then just multiply out. Note that sign perseveres if
|
|
; I is odd.
|
|
; Otherwise, convert I to extended and evaluate with exponentials.
|
|
;-----------------------------------------------------------
|
|
FINPWRI:
|
|
MOVE.W D2,D0 ; ABS(D2) --> D0
|
|
BPL.S @1
|
|
NEG.W D0
|
|
@1:
|
|
CMPI.W #SMALLEXP,D0
|
|
BHI.S XPWRBIG ; USE LOG AND EXP
|
|
|
|
BSR.S XPWRK ; MULTIPLY OUT
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Integer power is too large to multiply out, so convert to extended
|
|
; and use general x^y routine. Make copy of integer in cell W.
|
|
;-----------------------------------------------------------
|
|
XPWRBIG:
|
|
MOVE.W (A4),-(SP) ; SAVE SIGN OF INPUT
|
|
BCLR #7,(A4) ; ABS(DST) IN T
|
|
|
|
MOVE.L D4,-(SP) ; ADRS OF INT
|
|
PEA STW(A6) ; ADRS OF CELL W
|
|
MOVE.L (SP),D4 ; PRETEND IT'S SRC
|
|
ELFI2X ; CONVERT INT TO EXT IN W
|
|
|
|
BSR XPWRY ; COMPUTE (A4)^(D4)
|
|
;-----------------------------------------------------------
|
|
; Note that XPWRY must preserve the integer value in D2.
|
|
;-----------------------------------------------------------
|
|
MOVE.W (SP)+,D0 ; RETRIEVE SIGN OF INPUT
|
|
BPL.S @3 ; IF POSITIVE, DON'T CARE
|
|
|
|
ASR.W #1,D2 ; LOW BIT TO CARRY
|
|
BCC.S @3
|
|
|
|
BSET #7,(A4) ; NEGATE OUTPUT
|
|
@3:
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Raise T to the power D2, leaving the result in (A4). D0 = abs(D2).
|
|
; If D2 is negative, evaluate the positive power and reciprocate at
|
|
; the end. Know D2 is nonzero. Sign of (A4) is propagated correctly.
|
|
; Trash A0, A1, D0, and cells I, W and X.
|
|
;-----------------------------------------------------------
|
|
XPWRK:
|
|
MOVEA.L A4,A0 ; COPY T
|
|
LEA STX(A6),A1 ; INTO CELL W
|
|
BSR A0TOA1
|
|
|
|
BSR.S XPWRKLOOP
|
|
|
|
;-----------------------------------------------------------
|
|
; Now that loop is finished, produce 1 * T^|I| or 1 / T^|I|, depending
|
|
; on sign of I. If overflow or underflow has occurred and I is negative,
|
|
; redo computation with pre-reciprocated T.
|
|
;-----------------------------------------------------------
|
|
TST.W D2 ; IS I NEGATIVE?
|
|
BMI.S XPWRKDIV
|
|
XPWRKSTORE:
|
|
MOVEA.L A1,A0 ; T^|I|
|
|
MOVEA.L A4,A1 ; RESULT ADRS
|
|
BRA A0TOA1 ; T <-- T^|I|, AND EXIT
|
|
|
|
XPWRKDIV:
|
|
LEA FPK1,A0
|
|
LEA (A4),A1 ; LOSE ADRS OF CELL X FROM LOOP
|
|
BSR A0TOA1 ; T <-- 1
|
|
|
|
BSR TESTUFLOW
|
|
BNE.S XPWRKCLEAR
|
|
BSR TESTOFLOW
|
|
BNE.S XPWRKCLEAR
|
|
|
|
PEA STW(A6) ; W = T^|I| FROM XPWRKLOOP
|
|
PEA (A4) ; RES=1
|
|
ELFDIVX
|
|
RTS
|
|
XPWRKCLEAR:
|
|
BSR CLEAROFLOW
|
|
BSR CLEARUFLOW
|
|
PEA STX(A6) ; SAVED INPUT T ATOP T^|I|
|
|
PEA (A4)
|
|
ELFDIVX
|
|
|
|
MOVE.W D2,D0 ; GET K AGAIN
|
|
BPL.S @11
|
|
NEG.W D0
|
|
@11:
|
|
BSR.S XPWRKLOOP
|
|
BRA.S XPWRKSTORE
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; Input: D0 = positive integer K
|
|
; A4 = X
|
|
; Output: A1 = W = X^K
|
|
; Uses: cell W, A0
|
|
; Trashes: D0
|
|
;-----------------------------------------------------------
|
|
XPWRKLOOP:
|
|
LEA FPK1,A0
|
|
LEA STW(A6),A1
|
|
BSR A0TOA1 ; SEED RESULT WITH 1.0
|
|
BRA.S XKLPENTRY
|
|
XKLPTOP:
|
|
PEA (A4)
|
|
PEA (A4)
|
|
ELFMULX ; T^(2^(I+1))
|
|
XKLPENTRY:
|
|
LSR.W #1,D0 ; GET LOW BIT INTO C
|
|
BCC.S XKLPSKIP
|
|
|
|
PEA (A4) ; T^(2^I)
|
|
PEA (A1) ; RESULT SO FAR
|
|
ELFMULX
|
|
XKLPSKIP:
|
|
TST.W D0 ; ANY MORE BITS?
|
|
BNE.S XKLPTOP
|
|
RTS
|
|
|
|
;-----------------------------------------------------------
|
|
; Simple routine to compute (A4)^(D4) into (A4).
|
|
; Know that (A4) is positive. Know that the FMULX will never
|
|
; encounter 0 * INF, so extreme cases, like INF^3, will be handled
|
|
; correctly. Fixed to use temp X while computing, in case sources and
|
|
; dest are the same.
|
|
;-----------------------------------------------------------
|
|
XPWRY:
|
|
MOVEA.L A4,A0 ; COPY DST ARG
|
|
LEA STX(A6),A1
|
|
BSR A0TOA1 ; CELL X <-- INPUT X
|
|
|
|
PEA (A1) ; X = INPUT
|
|
MOVE.W #FOLOG2X,-(SP)
|
|
BSR ELEMS020 ; LOG2((A1))
|
|
|
|
MOVE.L D4,-(SP)
|
|
PEA (A1)
|
|
ELFMULX ; (D4) * LOG2((A1))
|
|
|
|
PEA (A1)
|
|
MOVE.W #FOEXP2X,-(SP)
|
|
BSR ELEMS020 ; (A1) ^ (D4)
|
|
|
|
MOVEA.L A1,A0
|
|
MOVEA.L A4,A1
|
|
BRA A0TOA1
|
|
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
; XPWRYTOP---General function x^y is beset by exceptional cases.
|
|
;-----------------------------------------------------------
|
|
;-----------------------------------------------------------
|
|
XPWRYTOP:
|
|
TST.W D1 ; IS X=DST NEG?
|
|
BMI.S NEGPWRY
|
|
|
|
BSR.S XPWRYCOM
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Signal X^Y error and stuff a NAN. Special entry accommodates branches from
|
|
; within subroutines, in which case a return address must be popped.
|
|
;-----------------------------------------------------------
|
|
XPWRY9ERR:
|
|
ADDQ.L #4,SP ; KILL RETURN ADDRESS
|
|
XPWRYERR:
|
|
BSR CLEARINEXACT ; SIGNAL INVALID ONLY
|
|
MOVEQ #NANPOWER,D0
|
|
BRA ERRORNAN
|
|
|
|
;-----------------------------------------------------------
|
|
; If X is negative, check that Y is integral; otherwise error.
|
|
; Save parity of Y to fix sign at end of XPWRYCOM.
|
|
;-----------------------------------------------------------
|
|
NEGPWRY:
|
|
TST.B D2 ; Y CLASS - INF
|
|
BEQ.S XPWRYERR
|
|
|
|
MOVEA.L D4,A0 ; Y=SRC
|
|
LEA STW(A6),A1 ; CELL W TEMP
|
|
BSR A0TOA1
|
|
|
|
PEA (A1) ; Y=SRC
|
|
ELFRINTX ; ROUND TO INTEGER
|
|
BSR TESTINEXACT
|
|
BNE.S XPWRYERR
|
|
|
|
;-----------------------------------------------------------
|
|
; NEG ^ INT requires that parity of Y be saved in cell J for later
|
|
; setting of sign. To find low bit of floating integer, divide by
|
|
; 2 and test inexact.
|
|
;-----------------------------------------------------------
|
|
PEA FPK2 ; 2.0
|
|
PEA (A1) ; CELL W
|
|
ELFDIVX ; W/2
|
|
|
|
PEA (A1)
|
|
ELFRINTX ; STRIP OFF ODD BIT OF W
|
|
|
|
MOVE.W (FPSTATE).W,STJ(A6) ; save env in J cell
|
|
|
|
BSR CLEARINEXACT
|
|
|
|
BCLR #7,(A4) ; ABS((A4))
|
|
|
|
BSR.S XPWRYCOM ; ABS((A4))^(D4)
|
|
|
|
;-----------------------------------------------------------
|
|
; Fix sign of power, according to parity of Y. The parity is stored in
|
|
; the inexact flag, saved in cell J. It's in the high byte so just to
|
|
; a bit test.
|
|
;-----------------------------------------------------------
|
|
BTST #FBINEXACT,STJ(A6)
|
|
BEQ.S @1
|
|
BCHG #7,(A4) ; NEGATE IF ODD (INEXACT)
|
|
@1:
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Common routine to raise (A4) to (D4) power.
|
|
; Know (A4) >= 0 and (D4) is not a NAN.
|
|
; Have class codes, less CLINF, in D1 and D2, respectively.
|
|
; Can run through 2 ^ Y*LOG2(X) code so long as won't multiply
|
|
; INF and 0 to compute exponent. As a minor detail, if Y is 0 or INF,
|
|
; clear any inexact that may have been set by LOG2(X).
|
|
;
|
|
; Since this is called as a subroutine, exits to XPWRYERR must have a special
|
|
; pop for the return address.
|
|
;-----------------------------------------------------------
|
|
XPWRYCOM:
|
|
SUBQ.B #1,D1 ; CLINF ALREADY SUBTRACTED
|
|
BNE.S NONPWRY
|
|
|
|
;-----------------------------------------------------------
|
|
; 0 ^ some
|
|
;-----------------------------------------------------------
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BEQ.S XPWRY9ERR ; 0^0, 0^INF ERRORS, WITH RTS POP
|
|
TST.W D2 ; SIGN OF Y
|
|
BPL.S @1
|
|
|
|
;-----------------------------------------------------------
|
|
; 0 ^ nonzero
|
|
;-----------------------------------------------------------
|
|
BSR FORCEDIVZER ; SIGNAL DIV BY ZERO
|
|
LEA FPKINF,A0
|
|
BRA.S @2
|
|
@1:
|
|
LEA FPK0,A0
|
|
@2:
|
|
MOVEA.L A4,A1 ; RESULT PTR
|
|
BRA A0TOA1 ; STUFF RESULT AND EXIT
|
|
|
|
;-----------------------------------------------------------
|
|
; nonzero ^ some
|
|
;-----------------------------------------------------------
|
|
NONPWRY:
|
|
BPL.S FINPWRY ; EXIT IF X FINITE
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; inf ^ some
|
|
;-----------------------------------------------------------
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BNE.S XPWRYOK
|
|
BRA XPWRY9ERR ; INF^O IS AN ERROR
|
|
|
|
;-----------------------------------------------------------
|
|
; finite ^ some
|
|
;-----------------------------------------------------------
|
|
FINPWRY:
|
|
SUBQ.B #1,D2
|
|
BPL.S XPWRYOK ; FIN ^ FIN IS OK
|
|
|
|
;-----------------------------------------------------------
|
|
; finite ^ inf has the special case 1^INF which is an error.
|
|
;-----------------------------------------------------------
|
|
PEA FPK1
|
|
PEA (A4)
|
|
ELFCMPX
|
|
FBEQL XPWRY9ERR
|
|
|
|
;-----------------------------------------------------------
|
|
; Finally, compute finite^reasonable and return.
|
|
; Two cases: if exponent is a small integer, then just multiply;
|
|
; else use log and exp. To check for an integer, try converting to
|
|
; 16 bits. Overflow is Invalid, rounding error is Inexact.
|
|
; Must reset Invalid, but if Inexact the result will be anyway.
|
|
; Save D2=YClass in D6 across possible call to XPWRK.
|
|
;-----------------------------------------------------------
|
|
XPWRYOK:
|
|
MOVE.W D2,D6 ; COPY OF Y'S CLASS LESS CLNORM
|
|
MOVE.L D4,-(SP) ; EXPONENT ADDRESS
|
|
PEA STI(A6) ; INTEGER CELL I
|
|
ELFX2I ; CONVERT TO INTEGER
|
|
|
|
BSR TESTINVALID ; X2I OFLOW IS INVALID
|
|
SNE D7
|
|
BSR CLEARINVALID ; CLEAR UNDESERVED ERROR
|
|
BSR TESTINEXACT ; MAY HAVE JUST ROUNDED OFF
|
|
SNE D1
|
|
OR.B D1,D7 ; EITHER ERROR?
|
|
BNE.S XPWRYHARD
|
|
|
|
MOVE.W STI(A6),D2 ; GET INTEGER TO REG.
|
|
MOVE.W D2,D0
|
|
BPL.S @1
|
|
NEG.W D0
|
|
@1:
|
|
CMPI.W #SMALLEXP,D0
|
|
BLE XPWRK ; DO IT AS INTEGER AND EXIT
|
|
XPWRYHARD:
|
|
BSR CLEARINEXACT
|
|
|
|
BSR XPWRY
|
|
|
|
TST.B D6 ; CHECK FOR Y 0 OR INF
|
|
BMI CLEARINEXACT ; AND RETURN FROM THERE
|
|
RTS
|
|
|
|
;-----------------------------------------------------------
|
|
; Compute dst <-- (1 + src2)^src r = src2 n = src
|
|
; Watch for special cases:
|
|
; src2 < -1 is invalid
|
|
; else src = 0 yields 1
|
|
; else src2 = 0 and src = INF is invalid
|
|
; else src = INF yields 0 or INF according to src2
|
|
; else src2 = -1 yields 0, 1, or INF according to src
|
|
; else actually compute (1 + r)^n !!
|
|
;-----------------------------------------------------------
|
|
COMPOUNDTOP:
|
|
PEA FPKM1 ; -1
|
|
MOVE.L D5,-(SP) ; SRC2
|
|
ELFCMPX
|
|
FBULTL ERRFINAN ; UNORDERED OR LESS THAN -1
|
|
FBGTS CMPGTM1
|
|
|
|
;-----------------------------------------------------------
|
|
; Get here if SRC2 is -1. Check SRC (D2) for 0 or nonzero.
|
|
;-----------------------------------------------------------
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BNE.S CMPM1N
|
|
CMPTOZERO:
|
|
BRA P1STUFF ; (1 + SOME)^0 IS +1
|
|
CMPM1N:
|
|
MOVEA.L D4,A0 ; CHECK SIGN OF SRC
|
|
TST.B (A0)
|
|
BMI DIVP0STUFF ; (1 - 1)^NEG IS +INF
|
|
CMPZERO:
|
|
BRA P0STUFF ; (1 - 1)^POS IS +0
|
|
|
|
;-----------------------------------------------------------
|
|
; Get here if SRC2 (r) is > -1.
|
|
;-----------------------------------------------------------
|
|
CMPGTM1:
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BEQ.S CMPTOZERO ; (1 + SOME)^0 IS +1
|
|
BGT.S CMPTOFIN ; GO DO (1 + SOME)^FINITE
|
|
|
|
;-----------------------------------------------------------
|
|
; Get here if (1 + SOME)^INF. Check for 1^INF, an error, else have
|
|
; INF or 0 according to SRC and SRC2.
|
|
;-----------------------------------------------------------
|
|
SUBQ.B #1,D1 ; CLINF ALREADY SUBTRACTED
|
|
BEQ.S ERRFINAN
|
|
|
|
EOR.W D2,D1 ; GET XOR OF SRC, SRC2 SIGNS
|
|
BMI.S CMPZERO ; SIGNS DIFFER --> ZERO
|
|
BRA PINFSTUFF ; SIGNS SAME --> +INF
|
|
|
|
;-----------------------------------------------------------
|
|
; Finally, compute (1 + reasonable)^finite with the usual...
|
|
;-----------------------------------------------------------
|
|
CMPTOFIN:
|
|
LEA STX(A6),A1 ; CELL X
|
|
MOVEA.L D5,A0 ; R = SRC2
|
|
BSR A0TOA1 ; COPY R TO X
|
|
|
|
MOVE (a1),d0 ; D0 gets sign/exponent of R.
|
|
BCLR #15,d0 ; Clear sign.
|
|
CMP #$3f7f,d0 ; Exponent -64.
|
|
BLT.S cmpbasee ; Natural log/exp for tiny
|
|
|
|
;-----------------------------------------------------------
|
|
; COMPOUND BASE 2.
|
|
;-----------------------------------------------------------
|
|
|
|
PEA (A1)
|
|
MOVE.W #FOLOG21X,-(SP)
|
|
BSR ELEMS020 ; LOG2(1 + (A1))
|
|
|
|
MOVE.L D4,-(SP) ; N = SRC ADDRESS
|
|
PEA (A1) ; LOG2(1+R)
|
|
ELFMULX ; N * LOG2(1+R)
|
|
|
|
PEA (A1)
|
|
MOVE.W #FOEXP2X,-(SP)
|
|
BRA.S cmpresult
|
|
|
|
cmpbasee: ; COMPOUND BASE E.
|
|
MOVE.L D4,-(SP) ; N = SRC ADDRESS
|
|
PEA (A1) ; LOG2(1+R)
|
|
ELFMULX ; N * LOG2(1+R)
|
|
|
|
PEA (A1)
|
|
MOVE.W #FOEXPX,-(SP)
|
|
|
|
cmpresult:
|
|
BSR clearuflow ; Irrelevant!
|
|
BSR ELEMS020 ; EXP2 OR EXPE((A1))
|
|
MOVEA.L A1,A0 ; CELL X
|
|
MOVEA.L A4,A1
|
|
BSR A0TOA1
|
|
|
|
BRA RESULTDELIVERED
|
|
|
|
|
|
;-----------------------------------------------------------
|
|
; Routine to stuff the financial NAN and go.
|
|
;-----------------------------------------------------------
|
|
ERRFINAN:
|
|
MOVEQ #NANFINAN,D0
|
|
BRA ERRORNAN
|
|
|
|
;-----------------------------------------------------------
|
|
; Compute annuity factor:
|
|
; ( 1 - (1 + r)^-n ) / r
|
|
; for r = SRC2 and n = SRC.
|
|
; Multitudinous special cases handled piece by piece.
|
|
;-----------------------------------------------------------
|
|
ANNUITYTOP:
|
|
PEA FPKM1 ; -1
|
|
MOVE.L D5,-(SP) ; R = SRC2
|
|
ELFCMPX ; R VS. -1
|
|
FBULTS ERRFINAN ; R < -1 IS AN ERROR
|
|
FBNES ANNOK
|
|
|
|
;-----------------------------------------------------------
|
|
; Get here if have (1 - 1)^ANY. Just check n = SRC.
|
|
;-----------------------------------------------------------
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BEQ.S ANN0 ; ANN(-1, 0) IS +0
|
|
TST.W D2 ; CHECK SIGN OF NONZERO N
|
|
BPL DIVP0STUFF
|
|
ANNM1:
|
|
BRA M1STUFF
|
|
|
|
;-----------------------------------------------------------
|
|
; Know that R=SRC2 exceeds -1. Check first for N=SRC=0.
|
|
;-----------------------------------------------------------
|
|
ANNOK:
|
|
SUBQ.B #1,D2 ; CLINF ALREADY SUBTRACTED
|
|
BNE.S ANNXN
|
|
ANN0:
|
|
BRA P0STUFF
|
|
|
|
;-----------------------------------------------------------
|
|
; Now check for unusual, 0 or INF, R=SRC2.
|
|
;-----------------------------------------------------------
|
|
ANNXN:
|
|
SUBQ.B #1,D1 ; CLINF ALREADY SUBTRACTED
|
|
BGT.S ANNROK
|
|
BLT.S ANNRINF
|
|
|
|
;-----------------------------------------------------------
|
|
; R=SRC2=0. Limit gives result of N=SRC.
|
|
;-----------------------------------------------------------
|
|
ANNSRC:
|
|
MOVEA.L A4,A1 ; DST PTR
|
|
MOVEA.L D4,A0 ; SRC=N PTR
|
|
BSR A0TOA1
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; R=SRC2=+INF. If N=SRC is nonnegative have 0, else test N=SRC versus -1.
|
|
;-----------------------------------------------------------
|
|
ANNRINF:
|
|
TST.W D2 ; IT'S NONZERO, JUST TEST SIGN
|
|
BPL.S ANN0 ; FORCE +0
|
|
|
|
PEA FPKM1 ; -1
|
|
MOVE.L D4,-(SP) ; SRC
|
|
ELFCMPX
|
|
FBEQS ANNM1 ; N = -1, STUFF -1
|
|
FBGTL M0STUFF
|
|
BRA MINFSTUFF
|
|
|
|
;-----------------------------------------------------------
|
|
; Way down here, we have R=SRC2 a normal or denormal number.
|
|
; Last check is for N=SRC=INF.
|
|
;-----------------------------------------------------------
|
|
ANNROK:
|
|
TST.B D2 ; (CLINF + 1) ALREADY SUB
|
|
BPL.S ANNDOIT
|
|
|
|
EOR.W D2,D1 ; DO R AND N SIGNS MATCH
|
|
BMI.S ANNSRC
|
|
|
|
MOVEA.L D5,A0 ; ADDRESS OF 4=SRC2, DIVISOR
|
|
LEA STX(A6),A1
|
|
BSR A0TOA1
|
|
PEA (A1) ; FOR DIVIDE BELOW
|
|
|
|
MOVEA.L A4,A1
|
|
LEA FPK1,A0
|
|
BSR A0TOA1 ; DST <-- +1
|
|
PEA (A1) ; ADDRESS OF DST
|
|
ELFDIVX ; RESULT IS 1/R
|
|
BRA RESULTDELIVERED
|
|
|
|
;-----------------------------------------------------------
|
|
; Finally, compute ( 1 - (1 + r)^-n ) / r.
|
|
; Distinguish two cases:
|
|
; r normal:
|
|
; log2(1 + r)
|
|
; n * log2(1 + r)
|
|
; -n * log2(1 + r)
|
|
; 2^(...) - 1
|
|
; 1 - 2^(...)
|
|
; (1 - 2^(...)) / r
|
|
;
|
|
; r denormal:
|
|
; log(1 + r) is about r
|
|
; n * r
|
|
; -n * r
|
|
; e^(...) - 1
|
|
; 1 - e^(...)
|
|
; (1 - e^(...)) / r
|
|
; Use D1.B, from which CLZERO has already been subtracted.
|
|
; Subtracting one more (CLNORMAL) leaves D1.B 0 for normal, 1 for denormal.
|
|
;-----------------------------------------------------------
|
|
ANNDOIT:
|
|
LEA STX(A6),A1 ; CELL X FOR TEMP
|
|
MOVEA.L D5,A0 ; SRC2 PTR
|
|
BSR A0TOA1
|
|
|
|
MOVE (a1),d0 ; D0 gets sign/exponent of R.
|
|
BCLR #15,d0 ; Clear sign.
|
|
CMP #$3f7f,d0 ; Exponent -64.
|
|
BLT.S annbasee ; Natural log/exp for tiny
|
|
|
|
;-----------------------------------------------------------
|
|
; Annuity base two.
|
|
;-----------------------------------------------------------
|
|
|
|
PEA (A1) ; X
|
|
MOVE.W #FOLOG21X,-(SP)
|
|
BSR ELEMS020 ; LOG2(1 + R)
|
|
MOVE.L D4,-(SP) ; N=SRC PTR
|
|
PEA (A1)
|
|
ELFMULX ; N * LOG2(1 + R)
|
|
|
|
BCHG #7,(A1) ; -(N * LOG2(1 + R))
|
|
CMP #$4007,(a1)
|
|
BLT.S @1 ; Branch if exp(-n*log(1+r)) not huge.
|
|
MOVE.L d5,a0
|
|
CMP #$407f,(a0)
|
|
BGE.S annspecial ; Branch if r huge.
|
|
@1:
|
|
PEA (A1)
|
|
MOVE.W #FOEXP21X,-(SP)
|
|
BRA.S annresult
|
|
|
|
annbasee: ; Annuity base e.
|
|
MOVE.L D4,-(SP) ; N=SRC PTR
|
|
PEA (A1)
|
|
ELFMULX ; N * LOG2(1 + R)
|
|
|
|
BCHG #7,(A1) ; -(N * LOG2(1 + R))
|
|
|
|
PEA (A1)
|
|
MOVE.W #FOEXP1X,-(SP)
|
|
|
|
annresult:
|
|
BSR ELEMS020 ; (1 + R)^-N - 1
|
|
|
|
BCHG #7,(A1) ; 1 - (1 + R)^-N
|
|
|
|
MOVE.L D5,-(SP) ; R=SRC2
|
|
PEA (A1)
|
|
ELFDIVX ; ( 1 - (1 + R)^-N ) / R
|
|
|
|
annclear:
|
|
BSR CLEARUFLOW
|
|
BSR CLEAROFLOW
|
|
MOVEA.L A1,A0 ; SET UP REGS FOR CLASS
|
|
BSR CLASSIFY
|
|
|
|
SUBQ.B #FCINF,D0 ; IS IT INF?
|
|
BNE.S @1
|
|
BSR FORCEOFLOW
|
|
BRA.S ANNDOUT
|
|
@1:
|
|
SUBQ.B #2,D0 ; IS IT NORMAL?
|
|
BEQ.S ANNDOUT
|
|
|
|
BSR FORCEUFLOW
|
|
ANNDOUT:
|
|
LEA STX(A6),A0 ; STORE TO DESTINATION
|
|
MOVEA.L A4,A1
|
|
BSR A0TOA1
|
|
|
|
BRA RESULTDELIVERED
|
|
|
|
annspecial:
|
|
MOVEA.L D5,A0 ; SRC2 PTR
|
|
BSR A0TOA1
|
|
PEA (A1) ; X := r
|
|
MOVE.W #FOLOG2X,-(SP)
|
|
BSR ELEMS020 ; x := LOG2( R)
|
|
LEA sty(a6),a1
|
|
MOVE.L d4,a0
|
|
BSR a0toa1 ; Y gets N.
|
|
PEA fpk1
|
|
PEA (a1)
|
|
ELFADDX ; Y gets N+1.
|
|
PEA (A1)
|
|
LEA stx(a6),a1 ; A1 gets X again.
|
|
PEA (a1)
|
|
ELFMULX ; x gets (n+1) * LOG2( R)
|
|
BCHG #7,(A1) ; -(N+1) * LOG2( R)
|
|
PEA (A1)
|
|
MOVE.W #FOEXP2X,-(SP)
|
|
BSR ELEMS020 ; ( R)^-(n+1)
|
|
|
|
BCHG #7,(A1) ; - (R)^-(N+1)
|
|
BRA.S annclear
|
|
|