mac-rom/Toolbox/InSANE/ELEMS020_1.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
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.
2017-12-26 09:52:23 +08:00

1466 lines
44 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: ELEMS020_1.a
;
; Contains: xxx put contents here xxx
;
; Written by: The Apple Numerics Group
;
; Copyright: © 1990-1993 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 time.
;
;-----------------------------------------------------------
; CHANGE HISTORY, kept for historical purposes:
;
; 26 MAR 90 Modified to support 96-bit extended type (JPO).
; 18 MAY 90 Raise inexact for finite, nonzero results of
; LOG and LN1 [see LOGFINI below] (JPO).
; 10 OCT 90 Changed SANETrapAddr equate to $15AC
; 28 APR 92 Removed MACRO ELFLOGBX and subroutine ELLOGBX. In-lined LOGB
; functionality in LOG2R code sequence (JPO).
; Removed MACRO ELFCLASSX and subroutine ELCLASSX. In-lined
; classification code in subroutine CLASSIFY, which also
; normalizes unnormalized input (JPO).
; Simplified subroutine SCALBXX in light of pre-filtering of small
; magnitude inputs in exponential function implementations (JPO).
; Improved code flow for logarithms by filtering out small magnitude
; input for LN1 and LOG21 (JPO).
; Added trailing stub routines TINYX, P0XSTUFF, P1XSTUFF, M1XSTUFF,
; and PINFXSTUFF (JPO).
;-----------------------------------------------------------
;-----------------------------------------------------------
; There are four logarithm functions: LN(x), LOG2(x), LN(1+x), and LOG2(1+x).
; They share much of the same code, but are distinguished by two bits.
; In the same way, EXP(x), EXP2(x), EXP(x)-1, EXP2(x)-1 share the same
; startup code.
;-----------------------------------------------------------
BLANKS ON
STRING ASIS
BTLOGBASE2 EQU 1 ; SET IF EITHER LOG2(X) OR LOG2(1+X)
; SET IF EITHER EXP2(X) OR EXP2(X)-1
BTLOG1PLUSX EQU 2 ; SET IF EITHER LN(1+X) OR LOG2(1+X)
; SET IF EITHER EXP(X)-1 OR EXP2(X)-1
;-----------------------------------------------------------
; When ELEMS68 is entered the stack has the form:
; ret adrs < opcode word < dst adrs < src adrs < src2 adrs
; with a second source address only in the case of the financial functions
; Compound and Annuity. A LINK is made through A6 (leaving A5 intact for
; the debugger people) and the following stack frame is set up:
;
; ......
; source2 address -- only if Compound or Annuity
; source address -- for Comp., Ann., X^I, X^Y
; destination address
; opcode word
; return address -- top of stack on entry to ELEMS68
; saved A6 -- for LINK, pntd to by A6 throughout ELEMS68
; environment word-- slot to save user's env across ELEMS68
; I -- word for integer temporary
; J -- word...
; W -- 5 words for extended temporary
; X -- 5 words...
; Y -- 5 words...
; Z -- 5 words...
; SRCCOPY -- 5 words for 80-bit copy of 96-bit SRC
; SRC2COPY -- 5 words for 80-bit copy of 96-bit SRC2
; saved D0-D7/A0-A4-- done with MOVEM.L after LINK
;
; After the operand addresses are fetched, the return address is written
; onto the deepest operand address, and the high word of the return address
; (the top of stack after the UNLK) is set to the number of bytes down to
; the relocated return address. To see how simple the subsequent exit
; procedure is, look at the code below label RESULTDELIVERED.
;
; The following constants index the stack frame off of A6:
;-----------------------------------------------------------
STSRC2 EQU 18 ; SOURCE2
STSRC EQU 14 ; SOURCE
STDST EQU 10 ; DESTINATION
STOPCODE EQU 8 ; OPCODE WORD
STRET EQU 4 ; RETURN ADDRESS
STA5 EQU 0 ; SAVED A6
STENV EQU -2 ; ENVIRONMENT SLOT
STI EQU -4 ; I
STJ EQU -6 ; J
STW EQU -16 ; W
STX EQU -26 ; X
STY EQU -36 ; Y
STZ EQU -46 ; Z
SCOPY EQU -56 ; SRC copy
S2COPY EQU -66 ; SRC2 copy
STLOCK EQU -68 ; HIGH WORD OF HANDLE
STSIZE EQU -68 ; SIZE OR FRAME FROM LINK
;-----------------------------------------------------------
; The following constants give the number of stack bytes to pop before exit.
;-----------------------------------------------------------
KI1ADRS EQU 6 ; OLD RET AND OPCODE
KI2ADRS EQU 10 ; OLD RET, OPCODE, DST
KI3ADRS EQU 14 ; OLD RET, OPCODE, DST, SRC
;-----------------------------------------------------------
; The opword is defined as:
; XY00 0000 Z0NN NNN0
; where X=1 for 2- or 3-address functions, Y=1 for 3-address functions,
; Z = 1 for 96-bit extended operands, and <NN NNN0> is the index
; into the jump table for the specific instruction.
;-----------------------------------------------------------
OP2ADRS EQU 15 ; SET IF 2-ADRS
OP3ADRS EQU 14 ; SET IF 3-ADRS
OPMASK EQU $003E ; MASK FOR JUMP TABLE INDEX
;-----------------------------------------------------------
; For scaling via FSCALBX, integer argument must be kept less than the
; maximum magnitude in a 16-bit integer. When outlandish scaling is
; required below, FSCALBX is called in units of MAXINT.
;-----------------------------------------------------------
;MAXINT EQU 32767 ; 2^15 - 1 DELETED <4/28/92, JPO>
;-----------------------------------------------------------
; When raising extended to an integer power, do explicit multiplies when
; the exponent is smaller than some threshold. It's 255 for now.
; When the exponent exceeds this threshold, computation is done with
; log and exp.
;-----------------------------------------------------------
SMALLEXP EQU 255
;-----------------------------------------------------------
; The environment word is maintained at low memory addr FPSTATE.
;-----------------------------------------------------------
FPSTATE EQU $0A4A
;-----------------------------------------------------------
; The PACK4 (SANE FP) entry point is in low memory addr SANETrapAddr.
;-----------------------------------------------------------
SANETrapAddr EQU $15ac
;-----------------------------------------------------------
; Here are the poor man's macros for getting at the arithmetic:
;-----------------------------------------------------------
MACRO
ELFADDX
MOVE #0,-(SP)
JSR (A3)
ENDM
MACRO
ELFSUBX
MOVE #2,-(SP)
JSR (A3)
ENDM
MACRO
ELFMULX
MOVE #4,-(SP)
JSR (A3)
ENDM
MACRO
ELFDIVX
MOVE #6,-(SP)
JSR (A3)
ENDM
MACRO
ELFCMPX
MOVE #8,-(SP)
JSR (A3)
ENDM
MACRO
ELFREMX
MOVE #$C,-(SP)
JSR (A3)
ENDM
MACRO
ELFI2X
BSR ELI2X
ENDM
MACRO
ELFX2X
MOVE #$0E,-(SP)
JSR (A3)
ENDM
MACRO
ELFX2I
MOVE #$2010,-(SP)
JSR (A3)
ENDM
MACRO
ELFRINTX
MOVE #$14,-(SP)
JSR (A3)
ENDM
MACRO
ELFSCALBX
MOVE #$18,-(SP)
JSR (A3)
ENDM
MACRO
ELFPROCEXIT
BSR ELPROCEXIT
ENDM
; MACRO ; MACRO DELETED <4/28/92, JPO>
; ELFLOGBX
; BSR ELLOGBX
; ENDM
; MACRO ; MACRO DELETED <4/28/92, JPO>
; ELFCLASSX
; BSR ELCLASSX
; ENDM
;-----------------------------------------------------------
;-----------------------------------------------------------
; ELEMS020---sole entry point to package
;-----------------------------------------------------------
;-----------------------------------------------------------
ELEMS020 PROC EXPORT
LINK A6,#STSIZE ; ALLOCATE TEMP CELLS
MOVEM.L D0-D7/A0-A4,-(SP) ; PRESERVE WORKING REGS
MOVEQ #0,D3 ; ERROR BITS AND OPCODE
;-----------------------------------------------------------
; Load the registers as follows:
; A3 <-- PACK4 (SANE FP) entry point stored
; in low memory global SANETrapAddr
; A4 <-- dst adrs
; D4 <-- src adrs, if any
; D5 <-- src2 adrs, if any, dst if there is none
; D3 <-- opcode word
; D2 <-- src class, if any
; D1 <-- dst/src2 class
;
; D6 <-- scratch
; D7 <-- scratch
;
; Nuisance: must avoid trying to classify the integer src to the X^I operation.
;
; Note: the assembly language class function FCLASSX returns a nonzero value
; with the sign of the input argument; the magnitude of the value is 1
; greater than the value of the Pascal enumerated type in the Elems interface.
;
; Note after the operand addresses are fetched the stack is set up for later
; exit, that is the return address is moved to the deepest available long
; word and the number of other bytes to kill is stored in the high word of
; the former return address. See the stack notes in the EQU section above
; and the exit sequence at label RESULTDELIVERED.
;-----------------------------------------------------------
MOVEA.L (SANETrapAddr).W,A3 ; A3 <- PACK4 entry point for duration
LEA STRET(A6),A2 ; POINT TO RET ADRS
LEA STOPCODE(A6),A0 ; POINT INTO STACK ARGS
MOVE.W (A0)+,D3 ; GET OPCODE
; BPL DSTONLY ; QUICK TEST OF #OP2ADRS BIT ; DELETED <4/28/92, JPO>
BPL.B DSTONLY ; Unary op (short branch) <4/28/92, JPO>
MOVEA.L (A0)+,A4 ; DST ADRS, ANOTHER ADRS COMING
MOVE.L (A0),D4 ; SRC TOO, BUT NO INCREMENT
BTST #OP3ADRS,D3
BNE.S HAVESRC2
;-----------------------------------------------------------
; Get here if have src and dst operands only.
;-----------------------------------------------------------
TST.B D3 ; 96-bit extended?
BPL.S @1 ; no. 80-bit
MOVE.W (A4),2(A4) ; yes. convert DST to 80-bit and bump pointer
ADDQ.L #2,A4
@1:
MOVE.L (A2),(A0) ; RET ADRS ON SRC ADRS
MOVE.W #KI2ADRS,(A2) ; STACK KILL COUNT
MOVE.L A4,D5 ; PRETEND THERE'S A SRC2
MOVEQ #15,D2 ; PRESET SRC CLASS IN CASE X^I
MOVEQ #OPMASK,D0 ; SPECIAL CASE WITH INTEGER OP
AND.W D3,D0
CMPI.B #$10,D0
BEQ.S CLASSDSTORSRC2
CLASSCOM:
TST.B D3 ; 96-bit extended?
BPL.S CLCOM2 ; no. 80-bit
CLCOM1:
MOVE.L D4,A0 ; yes. copy 96-bit SRC to 80-bit SRCCOPY
LEA SCOPY(A6),A1
MOVE.L A1,D4 ; D4 points to SRCCOPY
MOVE.W (A0),(A1)+
MOVE.L 4(A0),(A1)+
MOVE.L 8(A0),(A1)
CLCOM2:
MOVEA.L D4,A0 ; CLASSIFY SRC OPERAND
; BSR.S CLASSIFY ; DELETED <4/28/92, JPO>
BSR CLASSIFY ; word branch <4/28/92, JPO>
MOVE.W D0,D2 ; SRC CLASS CODE
CLASSSKIP:
BRA.S CLASSDSTORSRC2
;-----------------------------------------------------------
; Get here if src, src2, and dst operands. Get src2 adrs and classify.
; Only Compound and Annuity have a src2.
;-----------------------------------------------------------
HAVESRC2:
ADDQ.L #4,A0 ; SKIP OVER SRC ADRS
MOVE.L (A0),D5 ; SRC2 addr
MOVE.L (A2),(A0) ; RET ADRS ON SRC ADRS
MOVE.W #KI3ADRS,(A2) ; STACK KILL COUNT
TST.B D3 ; 96-bit extended operands?
BPL.S CLCOM2 ; no. 80-bit extended
ADDQ #2,A4 ; yes. bump DST pointer for 80-bit interim result
MOVE.L D5,A0 ; copy 96-bit SRC2 to 80-bit SRC2COPY
LEA S2COPY(A6),A1
MOVE.L A1,D5
MOVE.W (A0),(A1)+
MOVE.L 4(A0),(A1)+
MOVE.L 8(A0),(A1)
BRA.S CLCOM1 ; copy 96-bit SRC to 80-bit SRCCOPY
;-----------------------------------------------------------
; Handy place to stick the following routine. DELETED <4/28/92, JPO>
; Input: A0 = operand address
; Output: D0 = class code
; Uses: stack cell I to receive class
; D0.B has value 1-6 according to SNAN, QNAN, INF, ZERO, NORMAL, DENORMAL
; and the high bit D0.W (i.e. #$8000) is set according to the op's sign.
;-----------------------------------------------------------
;CLASSIFY: ; old implementation DELETED <4/28/92, JPO>
; PEA (A0) ; EXTENDED SOURCE
; PEA STI(A6) ; INTEGER DST FOR CLASS
; ELFCLASSX ; RETURNS SIGNED 1-6
; MOVE.W STI(A6),D0
; BPL.S @1
; NEG.W D0
; ORI.W #$8000,D0 ; ISOLATE SIGN IN HIGH BIT
;@1
; RTS
;-----------------------------------------------------------
; Get here in usual case of unary operator.
;-----------------------------------------------------------
DSTONLY:
MOVEQ #15,D2 ; FAKE A NON-NAN CLASS CODE
MOVE.L (A0),A4 ; DST ADRS
TST.B D3 ; 96-bit extended?
BPL.S @1 ; no. 80-bit
MOVE.W (A4),2(A4) ; yes. convert to 80-bit and bump pointer
ADDQ.L #2,A4
@1:
MOVE.L (A2),(A0) ; RET ADRS
MOVE.W #KI1ADRS,(A2) ; KILL COUNT
MOVE.L A4,D5 ; PRETEND DST IS SRC2
CLASSDSTORSRC2:
MOVEA.L D5,A0 ; SRC2 OR DST ADRS
BSR.S CLASSIFY
MOVE.W D0,D1
;-----------------------------------------------------------
; Now save the user's environment and set all flags and halts off and rounding
; to nearest.
; Output: Environment cell.
; Uses: cell I to hold default environment
;-----------------------------------------------------------
MOVE.W (FPSTATE).W,STENV(A6) ; save environment in cell
CLR.W (FPSTATE).W ; set default environment
;-----------------------------------------------------------
; Check for NANs, either D1 (dst/src2) or D2 (src) equal to 1 or 2.
; If the src is a NAN, there might be two NANs so let floating add
; determine precedence, or propagate the one NAN. If just the dst
; (or possibly src2) is a NAN, do a simple move, in order to touch
; any signaling NAN that may have appeared.
;-----------------------------------------------------------
SUBQ.B #FCINF,D2 ; IS < 0 FOR SRC NANS
BGE.S NOT2NANS
MOVEA.L D5,A0 ; MIGHT BE DST OR SRC2
MOVEA.L A4,A1 ; ALWAYS DST ADRS
BSR.S A0TOA1 ; JUST BIT COPY
MOVE.L D4,-(SP) ; SRC ADRS
PEA (A4) ; ALWAYS DST ADRS
ELFADDX
BRA.S NANEXIT
NOT2NANS:
SUBQ.B #FCINF,D1 ; CHECK SRC2 OR DST
BGE.S NONANS
MOVE.L D5,-(SP) ; SRC2 OR DST ADRS
PEA (A4) ; DST ADRS
ELFX2X
NANEXIT:
BRA RESULTDELIVERED
NONANS:
;-----------------------------------------------------------
; Fall through to here in typical case of no NANs.
; Have dst address in A4, src address in D4, dst or src2 address in D5.
; D1 and D2 contain the dst/src2 and src class codes, decremented by
; #FCINF.
; Jump to specific routine based on opword in D3.W.
;-----------------------------------------------------------
LIFTOFF:
MOVE.W D3,D0
ANDI.W #OPMASK,D0
MOVE.W ELEMSTAB(D0),D0
JMP LIFTOFF(D0)
ELEMSTAB:
DC.W LOGTOP-LIFTOFF ; LNX
DC.W LOGTOP-LIFTOFF ; LOG2X
DC.W LOGTOP-LIFTOFF ; LN1X
DC.W LOGTOP-LIFTOFF ; LOG21X
DC.W EXPTOP-LIFTOFF ; EXPX
DC.W EXPTOP-LIFTOFF ; EXP2X
DC.W EXP1TOP-LIFTOFF ; EXPX - 1
DC.W EXP1TOP-LIFTOFF ; EXP2X - 1
DC.W XPWRITOP-LIFTOFF
DC.W XPWRYTOP-LIFTOFF
DC.W COMPOUNDTOP-LIFTOFF
DC.W ANNUITYTOP-LIFTOFF
DC.W SINTOP-LIFTOFF
DC.W COSTOP-LIFTOFF
DC.W TANTOP-LIFTOFF
DC.W ATANTOP-LIFTOFF
DC.W RANDTOP-LIFTOFF
;-----------------------------------------------------------
; Utility to copy an extended operand from (A0) to (A1), resetting
; A1 to point to the head. Turns out not to be useful to reset A0,
; since it is always thrown away.
;-----------------------------------------------------------
A0TOA1:
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.W (A0),(A1)
SUBQ.L #8,A1
RTS
;-----------------------------------------------------------
; Subroutine CLASSIFY modified with in-line code - <4/28/92, JPO>
;
; Input: A0 = operand address
; Output: D0 = class code
; STACK: &ret
;
; D0.B has value 1-6 according to SNAN, QNAN, INF, ZERO, NORMAL, DENORMAL
; and the high bit D0.W (i.e. #$8000) is set according to the op's sign.
; This algorithm will normalize unnormalized zero and finite values.
;-----------------------------------------------------------
CLASSIFY: ; NEW in-line implementation <4/28/92, JPO>
MOVE.L D1,-(SP) ; save D1
MOVE.W (A0),D0 ; D0.W <- exponent
ANDI.W #$7FFF,D0
CMPI.W #$7FFF,D0 ; max exponent?
BNE.B @clfinite ; no, finite class
MOVEQ #3,D0 ; yes. assume infinite class
BFEXTU 2(A0){1:31},D1 ; any significand bits set other
OR.L 6(A0),D1 ; than explicit bit?
BEQ.B @clsign ; no. INF class
SUBQ #1,D0 ; yes, assume QNaN
BTST.B #6,2(A0) ; QNaN bit set?
BNE.B @clsign ; yes
SUBQ #1,D0 ; no, SNaN class
BRA.B @clsign
@clfinite:
TST.W 2(A0) ; normalized?
BPL.B @abnorm ; no
@clnorm:
MOVEQ #5,D0 ; yes, normal class
@clsign:
TST.W (A0) ; set bit 15 of D0 if sign bit is set
BPL.B @restore
ORI.W #$8000,D0
@restore:
MOVE.L (SP)+,D1 ; restore D1
RTS ; return
@abnorm:
MOVE.L 2(A0),D1 ; any low significand bits set?
OR.L 6(A0),D1
BEQ.B @clzero ; no, zero value
TST.W D0 ; yes, is it denorm?
BNE.B @donorm ; no, normalize unnormalized number
@cldenorm: ; denormal
MOVEQ #6,D0
BRA.B @clsign
@donorm:
MOVE.L D2,-(SP) ; save D2
MOVE.L 2(A0),D1 ; significand in D1/D2
MOVE.L 6(A0),D2
@loop: ; normalization loop
SUBQ.W #1,D0 ; decrement exponent
ADD.L D2,D2 ; shift significand
ADDX.L D1,D1
BMI.B @done ; done if explicit bit is set
TST.W D0 ; or exponent is zero
BNE.B @loop
@done:
BFINS D0,(A0){1:15} ; write normalized value back to (A0)
MOVE.L D1,2(A0)
MOVE.L D2,6(A0)
MOVE.L (SP)+,D2 ; restore D2
TST.L D1 ; explicit bit set?
BMI.B @clnorm ; yes, normal value
BRA.B @cldenorm ; no, denormal
@clzero:
ANDI.W #$8000,(A0) ; normalize the zero
MOVEQ #4,D0 ; zero class
BRA.B @clsign
;-----------------------------------------------------------
; Utility to evaluate a polynomial using Horner's recurrence.
; Input: A0 pts to result field (preserved).
; A1 pts to coefficient table (advanced beyond table).
; A2 pts to function value (preserved).
; Uses: D0
; All operands are extended. The polynomial table consists of
; a leading word N, a positive integer giving the degree of the
; polynomial, and then (N+1) extended coefficients, starting with
; that of the leading term.
; RESULT <-- C0 initially.
; RESULT <-- (RESULT * X) + CJ for J = 1 to DEGREE
; Since A1 is advanced beyond the end of the given coefficient table,
; POLEVAL may be used successively with consecutive tables, after setting
; A1 just once.
;-----------------------------------------------------------
POLYEVAL:
MOVE.W (A1)+,D0 ; GET LOOP INDEX
MOVE.L (A1),(A0) ; transfer leading coefficient to
MOVE.L 4(A1),4(A0) ; result field
MOVE.W 8(A1),8(A0)
POLYLOOP:
PEA (A2)
PEA (A0)
ELFMULX ; ACCUM <-- ACCUM * X
ADDQ.L #8,A1 ; SKIP 10 BYTES TO NEXT
ADDQ.L #2,A1 ; ...COEFFICIENT
PEA (A1)
PEA (A0)
ELFADDX ; ACCUM <-- ACCUM + CJ
SUBQ.W #1,D0
BGT.S POLYLOOP
ADDQ.L #8,A1 ; SKIP BEYOND END OF TABLE
ADDQ.L #2,A1
RTS
;-----------------------------------------------------------
; Clear the exception flag.
; Uses: D0.
;-----------------------------------------------------------
CLEARUFLOW:
MOVEQ #FBUFLOW,D0
BRA.S CLEARX
CLEAROFLOW:
MOVEQ #FBOFLOW,D0
BRA.S CLEARX
CLEARINVALID:
MOVEQ #FBINVALID,D0
BRA.S CLEARX
CLEARINEXACT:
MOVEQ #FBINEXACT,D0
CLEARX:
BCLR D0,(FPSTATE).W ; exception bit in high byte
RTS
;-----------------------------------------------------------
; Utility to force an exception flag. No halts are enabled in
; environment due to PROCENTRY, so simply turn on appropriate
; exception bit in environment global.
; Uses: D0.
;-----------------------------------------------------------
FORCEOFLOW:
MOVEQ #FBOFLOW,D0
BRA.S FORCEX
FORCEUFLOW:
MOVEQ #FBUFLOW,D0
BRA.S FORCEX
FORCEDIVZER:
MOVEQ #FBDIVZER,D0
BRA.S FORCEX
FORCEINVALID:
MOVEQ #FBINVALID,D0
BRA.S FORCEX
FORCEINEXACT:
MOVEQ #FBINEXACT,D0
FORCEX:
BSET D0,(FPSTATE).W ; exception bit in high byte
RTS
;-----------------------------------------------------------
; Utility to test an exception flag.
; Output: Z flag in CCR is true if flag is off, Z is false if flag is set.
;-----------------------------------------------------------
TESTDIVZER:
MOVEQ #FBDIVZER,D0
BRA.S TESTX
TESTUFLOW:
MOVEQ #FBUFLOW,D0
BRA.S TESTX
TESTOFLOW:
MOVEQ #FBOFLOW,D0
BRA.S TESTX
TESTINVALID:
MOVEQ #FBINVALID,D0
BRA.S TESTX
TESTINEXACT:
MOVEQ #FBINEXACT,D0
TESTX: ; test exception bit in high byte
BTST D0,(FPSTATE).W ; of environment word
RTS
;-----------------------------------------------------------
; Floating scalb function computes (A0) <-- (A0) * 2^(A1)
; Because of the 15-bit exponent range, just two invocations
; of FSCALBX are required if an over/underflow is to be stimulated.
; A0, A1, and (A1) are not modified.
; Uses: cells J and Y, A2 old implementation DELETED <4/29/92, JPO>
;-----------------------------------------------------------
;SCALBXX: Implementation DELETED <4/29/92, JPO>
; MOVE.W #MAXINT,STJ(A6) ; SEEDED INTEGER SLOT
; LEA STY+10(A6),A2 ; BEYOND CELL Y
; MOVE.L 6(A1),-(A2) ; COPY OF (A1)
; MOVE.L 2(A1),-(A2)
; MOVE.W (A1),-(A2)
;
; BCLR #7,(A2) ; ABS (A1) COPY
;
;-----------------------------------------------------------
; If ABS(A1) is larger than MAXINT then do one step of scaling by MAXINT.
;-----------------------------------------------------------
; BSR.S VSMAXINT
; FBGES At1 ; FLOATING >=
;
;-----------------------------------------------------------
; Must diminish (A2) by FPKMAXINT.
;-----------------------------------------------------------
; PEA FPKMAXINT
; PEA (A2)
; ELFSUBX
;
; TST.B (A1) ; CHECK OPERAND SIGN
; BPL.S @1
; NEG.W STJ(A6) ; -MAXINT IN INTEGER CELL
;@1:
; BSR.S SCALEINT ; SCALE BY STJ(A6)
;
;-----------------------------------------------------------
; If (SP) exceeds FPKMAXINT at this step, just force signed FPMAXINT.
;-----------------------------------------------------------
; BSR.S VSMAXINT ; (A2) VS FPMAXINT
; FBGES At1 ; FLOATING >=
;
; PEA FPKMAXINT
; BRA.S At3
;
;At1:
; PEA (A2) ; USE REDUCED VALUE
;
;At3:
; PEA STJ(A6) ; ADDRESS OF INT SLOT
; ELFX2I
;
; TST.B (A1)
; BPL.S @5
;
; NEG.W STJ(A6) ; FORCE SIGN OF INTEGER
;@5:
;-----------------------------------------------------------
; FALL THROUGH AND EXIT
;
; Scale (A0) by integer at STJ(A6).
;-----------------------------------------------------------
;SCALEINT:
; PEA STJ(A6)
; PEA (A0)
; ELFSCALBX
; RTS
;
;-----------------------------------------------------------
; Compare STY(A6) with FPMAXINT. DELETED <4/28/92, JPO>
;-----------------------------------------------------------
;VSMAXINT:
; PEA STY(A6)
; PEA FPKMAXINT
; ELFCMPX
; RTS
;-----------------------------------------------------------
; New floating scalb function computes (A0) <- (A0) * 2^(A1)
; Because of data pre-filtering, just one invocation of FSCALBX
; is required [(A1) is normalized and integral in range -32768
; <= (A1) <= 32767. A0, A1, and (A1) are not modified.
; Uses: cells J and Y, register D0 <4/28/92, JPO>
;-----------------------------------------------------------
SCALBXX: ; NEW implementation <4/28/92, JPO>
MOVE.L D1,-(SP) ; save D1
BFEXTU (A1){1:15},D0 ; D0 <- exponent of (A1)
MOVE.W #$400E,D1 ; D1 <- exponent of 2^15
SUB.W D0,D1 ; D1 <- right shift count
MOVE.W 2(A1),D0 ; D0.W <- normalized sig.HI of (A1)
BEQ.B @done ; shift parameter is zero
LSR.W D1,D0 ; D0.W <- abs value of shift parameter
TST.W (A1) ; negate if (A1) < 0.0
BPL.B @1
NEG.W D0
@1:
MOVE.W D0,STJ(A6) ; write shift parameter to cell J
PEA STJ(A6) ; do single scaling
PEA (A0)
ELFSCALBX
@done:
MOVE.L (SP)+,D1 ; restore D1
RTS ; return
;-----------------------------------------------------------
; ELLOGBX---fast LOGB routine expects finite, nonzero extended
; input, and so is nonexceptional. Interface is the same as
; that of the SANE ROM routine except for the absence of
; OPWORD on stack. Upon entry,
; STACK: &ret < &DST (input extended addr).
; Upon exit, integral exponent value is written in extended
; format to DST addr and stack is popped.
;-----------------------------------------------------------
;ELLOGBX: ; subroutine DELETED <4/28/92, JPO>
; MOVEM.L A0/D0-D2,-(SP) ; save small # of registers
; MOVEQ #0,D1 ; zero D1
; MOVEA.L 20(SP),A0 ; A0 <- &DST
; MOVE.W (A0),D1 ; D1.W <- sign/exp
; BCLR #15,D1 ; sign of operand irrelevant
; MOVE.L 2(A0),D0 ; sig.HI into D0
; BMI.S @3 ; already normalized
;
; BFFFO D0{0:0},D2 ; find first set bit in sig.HI
; BNE.S @1 ; sig.HI is nonzero
;
; SUB.W D2,D1 ; adjust exp (D2 must contain 32)
; MOVE.L 6(A0),D0 ; D0 <- sig.LO (must be nonzero)
; BFFFO D0{0:0},D2 ; find first set bit in sig.LO
;@1:
; SUB.W D2,D1 ; adjust exp to normalized value
;@3:
; MOVE.W #$401E,D0 ; tentative exp for LOGB
; SUB.W #$3FFF,D1 ; unbias exp of input
; BGT.S @7 ; result > 0
; BLT.S @5 ; result < 0
;
; MOVE.L D1,D0 ; zero result
; BRA.S @9 ; deliver it
;@5:
; BSET #15,D0 ; negative result; set sign bit
; NEG.W D1 ; negate integer
;@7:
; BFFFO D1{0:0},D2 ; find first one to normalize
; LSL.L D2,D1 ; shift left
; SUB.W D2,D0 ; adjust result exponent
;@9:
; MOVE.W D0,(A0)+ ; deliver exp of result
; MOVE.L D1,(A0)+ ; deliver sig.HI
; CLR.L (A0) ; sig.LO is zero
;
; MOVEM.L (SP)+,A0/D0-D2 ; restore registers
; RTD #4 ; return
;-----------------------------------------------------------
; ELCLASSX---fast CLASSX routine simulates the SANE ROM DELETED <4/28/92, JPO>
; routine except for absence of OPWORD on stack. Upon entry,
; STACK: &ret < &DST < &SRC.
; Upon exit, classify code (integer) is written to &DST and
; stack is popped.
;-----------------------------------------------------------
;ELCLASSX: ; DELETED <4/28/92, JPO>
; MOVEM.L A0/D0-D1,-(SP) ; save small # of registers
; MOVEA.L 20(SP),A0 ; SRC addr
; MOVE.W (A0)+,D0 ; get sign/exp in D0.W
; ADD.L D0,D0 ; sign in D0 bit 16
; LSR.W #1,D0 ; positive exp in D0.W
;
; CMPI.W #$7FFF,D0 ; max exp?
; BEQ.S @5 ; yes, NAN or INF class
;
; MOVE.L (A0)+,D1 ; normalized?
; BPL.S @8 ; zero or unnormalized
;
;@2:
; MOVEQ #5,D1 ; NORMAL
;
;@3:
; BTST #16,D0 ; negate class code if
; BEQ.S @4 ; sign bit is set
; NEG.W D1
;@4:
; MOVEA.L 16(SP),A0 ; DST addr
; MOVE.W D1,(A0) ; deliver classify result
; MOVEM.L (SP)+,A0/D0-D1 ; restore registers
; RTD #8 ; done
;
;
;@5: ; INF or NAN class
; MOVE.L (A0)+,D1 ; read high half of significand
; ADD.L D1,D1 ; clr explicit bit of sig
; LSR.L #1,D1
; BEQ.S @7 ; INF or SNAN class since sig high is zero
;
; BTST #30,D1 ; QNAN or SNAN
; BEQ.S @6 ;
;
; MOVEQ #2,D1 ; QNAN
; BRA.S @3
;@6:
; MOVEQ #1,D1 ; SNAN
; BRA.S @3
;
;@7:
; MOVE.L (A0),D1 ; INF or SNAN?
; BNE.S @6 ; SNAN
;
; MOVEQ #3,D1 ; INF
; BRA.S @3
;
;@8:
; BEQ.S @11 ; ZERO or SUBNORM
;
;@9:
; SUBQ.W #1,D0 ; normalization loop
; ADD.L D1,D1
; BPL.S @9
;
;@10:
; TST.W D0 ; negative exponent means SUBNORM
; BPL.S @2 ; nonnegative means NORMAL
;
; MOVEQ #6,D1 ; SUBNORM
; BRA.S @3
;
;@11: ; high significand is zero
; SUB.W #32,D0 ; decrease exponent
; MOVE.L (A0),D1 ; D1 <- low significand
; BEQ.S @12 ; ZERO
; BPL.S @9 ; still unnormalized
; BRA.S @10 ; check exponent
;
;@12:
; MOVEQ #4,D1 ; ZERO
; BRA.S @3
;-----------------------------------------------------------
; ELI2X---Fast INT2X conversion routine uses SANE ROM interface
; except for absence of OPWORD on stack. Upon entry:
; STACK: &ret < &DST < &SRC, where &SRC contains a 16-bit
; integer value and &DST will store the 80-bit
; extended result of the conversion.
; Upon exit, the stack is popped.
;-----------------------------------------------------------
ELI2X:
MOVEM.L A0/D0-D1,-(SP) ; save 3 registers
MOVEA.L 20(SP),A0 ; A0 <- SRC addr
MOVE.W #$400E,D0 ; set exponent for integer in D0.HI
SWAP D0
MOVE.W (A0),D0 ; SRC integer into D0.LO
BEQ.S @5 ; zero
BPL.S @1 ; positive; normalize
BSET #31,D0 ; negative; set sign bit
NEG.W D0 ; negate D0.L0
BMI.S @3 ; already normalized
@1:
SWAP D0 ; swap exp and first 16 sig bits
BFFFO D0{0:16},D1 ; find first one bit in sig
SUB.W D1,D0 ; adjust exponent
SWAP D0 ; swap exp and sig bits back
LSL.W D1,D0 ; shift significand to normalize
@3:
MOVEA.L 16(SP),A0 ; DST addr
MOVE.L D0,(A0)+ ; write extended result
CLR.L (A0)+ ; with trailing zeros
CLR.W (A0)
MOVEM.L (SP)+,A0/D0-D1 ; pop registers
RTD #8 ; return
@5:
MOVEQ #0,D0 ; zero result
BRA.S @3 ; output it
;-----------------------------------------------------------
; ELPROCEXIT---Fast PROCEXIT routine uses SANE ROM interface
; except for absence of OPWORD on stack. Upon entry:
; STACK: &ret < &DST, where &DST contains an environment
; word to be restored.
; Upon exit, the current exceptions are ORed into the environment
; at &DST, the result becomes the new environment, a halt is
; taken if any of the current exceptions were halt-enabled in
; the restored environment, and the stack is popped.
;-----------------------------------------------------------
ELPROCEXIT:
MOVEM.L D0/D6/A0,-(SP) ; Use 3 registers
MOVEA.L 16(SP),A0 ; old environment addr
MOVE.W #$0019,D6 ; opword into D6.HI
SWAP D6
MOVE.W #$1F00,D6 ; exception mask in D6.W
AND.W (FPSTATE).W,D6 ; current exceptions in D6.W
MOVE.W (A0),D0 ; old environment into D0.W for restoration
;FASTFIN: ; label DELETED <4/28/92, JPO>
OR.W D6,D0 ; OR new exceptions with old environment
MOVE.W D0,($0A4A).W ; store resulting environment
LSR.W #8,D6 ; check for halt
AND.W D6,D0
BNE.S FASTHALT ; handle halt
FASTEX:
MOVE D0,CCR ; zero CCR
MOVEM.L (SP)+,D0/D6/A0 ; restore registers
RTD #4 ; done
;-----------------------------------------------------------
; Fast halt vectoring routine for PROCEXIT
;-----------------------------------------------------------
FASTHALT:
LEA 16(SP),A0 ; A0 points to DST addr on stack
CLR.W -(SP) ; push CCR = 0 below D0 save
MOVE.W D0,-(SP) ; push HALT exceptions
PEA (SP) ; push MISCHALTINFO record pointer
MOVE.L 8(A0),-(SP) ; push bogus SRC2 addr
MOVE.L 4(A0),-(SP) ; push bogus SRC addr
MOVE.L (A0),-(SP) ; push DST addr
SWAP D6 ; push opword
MOVE.W D6,-(SP)
MOVEA.L ($0A4C).W,A0 ; call user halt handler
JSR (A0)
MOVE.L (SP)+,D0 ; pop HALT exception/CCR off stack
BRA.S FASTEX ; exit
;-----------------------------------------------------------
;-----------------------------------------------------------
; Logarithm functions.
; All four functions LN(x), LOG2(x), LN(1+x), and LOG2(1+x)
; are launched by common error-checking code. In the usual case
; that arithmetic is required, the computation is cast in the form
; log2(1+z). The only difference between LN and LOG2 is that the
; former requires a final multiplication by LN(2).
;
; The four functions are distinguished by the BTLOGBASE2 and
; BDLOG1PLUSX bits as described in the EQUATES section above.
;
; Since the only operand is the destination, the relevant class code
; (already diminished by FCINF in the NAN check) is in D1.
;-----------------------------------------------------------
;-----------------------------------------------------------
LOGTOP:
SUBQ.B #1,D1
BPL.S LOGFINITE ; -1 FOR INF, NONNEG FOR FINITE
TST.W D1 ; CHECK SIGN BIT
; BPL PINFSTUFF ; LOG(+INF) IS +INF DELETED <4/28/92, JPO>
BPL RESULTDELIVERED ; arg is exact result (+INF) <4/28/92, JPO>
LOGERROR:
MOVEQ #NANLOG,D0 ; ERROR CODE
BRA ERRORNAN ; LOG(-INF) IS AN ERROR
LOGFINITE:
BTST #BTLOG1PLUSX,D3
BNE.S LOG1PLUSX
TST.B D1 ; 0 IF OPERAND IS 0
BEQ.S LOG0 ; -INF, WITH DIVIDE BY 0
TST.W D1 ; CHECK SIGN
BMI.S LOGERROR
BRA.S LOG2R ; COMPUTE LOG(X)
LOG1PLUSX:
TST.B D1
BEQ RESULTDELIVERED ; LOG(+-0) IS +-0
BFEXTU (A4){1:15},D0 ; is |arg| < 2^(-64)? <4/28/92, JPO>
CMPI.W #$3FBF,D0 ; <4/28/92, JPO>
BGE.B @m1chk ; yes, check if < -1.0 <4/28/92, JPO>
; Small magnitude input (< 2.0^(-64)) for ln(1+x) and log2(1+x) yield fast results <4/28/92, JPO>
BTST #BTLOGBASE2,D3 ; base 2 logarithm? <4/28/92, JPO>
BEQ.B @gottiny ; no. return input value <4/28/92, JPO>
PEA FPKLOGE2 ; base 2: divide by ln(2.0) <4/28/92, JPO>
PEA (A4) ; <4/28/92, JPO>
ELFDIVX ; <4/28/92, JPO>
@gottiny: ; label ADDED <4/28/92, JPO>
BRA TINYX ; done RESULTDELIVERED
@m1chk: ; label ADDED <4/28/92, JPO>
PEA (A4)
PEA FPKM1
ELFCMPX
; FBUGTS LOGERROR ; -1 > OPERAND --> ERROR MOVED below <4/28/92, JPO>
FBLTS LOG12R ; FIND LOG(1+X)
FBUGTS LOGERROR ; -1 > OPERAND --> ERROR <4/28/92, JPO>
; FALL THROUGH WHEN = -1
LOG0:
BRA DIVM0STUFF
;-----------------------------------------------------------
; END OF SPECIAL CASES
;-----------------------------------------------------------
;-----------------------------------------------------------
; Compute LOG2(1+T) for some positive, finite T.
; If 1+T falls outside the range SQRT(1/2) to SQRT(2) then
; just go to the code for LOG2(S) below. Else use LOGAPPROX
; on T itself, IGNORING the sum 1+T.
;-----------------------------------------------------------
LOG12R:
;-----------------------------------------------------------
; First compute 1+T, saving the input T in cell W.
;-----------------------------------------------------------
MOVEA.L A4,A0 ; INPUT PTR
LEA STW(A6),A1 ; PTR TO W CELL
BSR A0TOA1 ; COPY OF INPUT IN W
PEA FPK1
PEA (A4)
ELFADDX ; T <-- 1+T
;-----------------------------------------------------------
; Now compare with bounds SQRT(1/2) and SQRT(2).
;-----------------------------------------------------------
PEA FPKSQRTHALF
PEA (A4)
ELFCMPX
FBULES LOG2R
PEA (A4)
PEA FPKSQRT2
ELFCMPX
FBLES LOG2R
;-----------------------------------------------------------
; Input T is within the required range so restore input value and
; just LOGAPPROX and finish up.
;-----------------------------------------------------------
MOVEA.L A1,A0 ; STW(A6) LEFT FROM BEFORE
MOVEA.L A4,A1
BSR A0TOA1
BSR LOGAPPROX
; BRA.S LOGFINI ; DELETED <4/28/92, JPO>
BRA LOGFINI ; word branch <4/28/92, JPO>
;-----------------------------------------------------------
; Compute LOG2(T) for some positive, finite T at (A4).
; Represent T as 2^L * Q for SQRT(1/2) <= Q <= SQRT(2).
; Then LOG2(T) is L + LOG2(Q).
; LOG2(Q) for that restricted range is computed at LOGAPPROX below.
;-----------------------------------------------------------
LOG2R:
;-----------------------------------------------------------
; Compute LOGB(T), i.e. L, in W.
;-----------------------------------------------------------
; MOVEA.L A4,A0 ; DELETED <4/28/92, JPO>
LEA STW(A6),A1
; BSR A0TOA1 ; COPY X TO W DELETED <4/28/92, JPO>
; PEA (A1) ; DELETED <4/28/92, JPO>
; ELFLOGBX ; DELETED <4/28/92, JPO>
;-----------------------------------------------------------
; Compute LOGB(T) in-line, putting result L in W (extended format)
; and -L in cell J (16-bit integer format). D0 is used as
; a scratch register. <4/28/92, JPO>
;-----------------------------------------------------------
BFEXTU (A4){1:15},D0 ; D0 <- exponent of T
MOVE.L D1,-(SP) ; save D1
TST.W 2(A4) ; is T normalized?
BMI.B @tnorm ; yes
BFFFO 2(A4){0:32},D1 ; no, adjust exponent for leading zero bits
BNE.B @1 ; got leading zero count
SUB.W D1,D0 ; adjust exponent (D1 contains 32)
BFFFO 6(A4){0:32},D1
@1:
SUB.W D1,D0 ; final adjustment
@tnorm:
MOVE.W #$400E,D1 ; D1.HI <- tentative exponent for L
SUB.W #$3FFF,D0 ; D0 <- unbiased L
SWAP D1
MOVE.W D0,D1 ; D1.W <- L
BPL.B @2 ; L >= 0
NEG.W D1 ; L < 0, negate in D1.W
BSET.L #31,D1 ; set sign bit in D1.HI
@2:
NEG.W D0 ; write -L (integer) to cell J
SWAP D1 ; swap exp and high sig bits
MOVE.W D0,STJ(A6)
BFFFO D1{0:16},D0
BNE.B @3 ; normalize significand
MOVEQ #0,D1 ; zero result
BRA.B @4
@3:
SUB.W D0,D1 ; adjust exponent
SWAP D1 ; swap exp and sig bits back
LSL.W D0,D1 ; shift to normalize
@4:
MOVE.L D1,(A1) ; write extended L to cell W
CLR.L 4(A1)
CLR.W 8(A1)
MOVE.L (SP)+,D1 ; restore D1
;-----------------------------------------------------------
; Then scale T down to range 1 to 2. A single scaling step suffices
; since the logb result ranges between -16446 and +16383
;-----------------------------------------------------------
; BCHG #7,(A1) ; -L IN W DELETED <4/28/92, JPO>
; PEA (A1) ; CONVERT LOGB RESULT TO INTEGER DELETED <4/28/92, JPO>
; PEA STJ(A6) ; USE CELL J DELETED <4/28/92, JPO>
; ELFX2I ; DELETED <4/28/92, JPO>
PEA STJ(A6)
PEA (A4)
ELFSCALBX ; (A4) <-- (A4) * 2^(A1)
; BCHG #7,(A1) ; BACK TO L IN W DELETED <4/28/92, JPO>
;-----------------------------------------------------------
; If scaled value exceeds SQRT(2), then halve T and increment L.
;-----------------------------------------------------------
PEA FPKSQRT2
PEA (A4)
ELFCMPX
FBULES At11
PEA FPK1
PEA STW(A6)
ELFADDX ; INCREMENT L
SUB.W #1,(A4) ; HALVE T BY DECREMENTING ITS EXPONENT
At11:
;-----------------------------------------------------------
; Now must subtract 1 from (A4) in order to use LOGAPPROX,
; which approximates LOG2(1+S).
;-----------------------------------------------------------
PEA FPK1
PEA (A4)
ELFSUBX
BSR.S LOGAPPROX
;-----------------------------------------------------------
; Add L in. Exit via check to see whether to multiply by LN(2).
;-----------------------------------------------------------
PEA STW(A6)
PEA (A4)
ELFADDX
;-----------------------------------------------------------
; Finish up with a multiply by LN(2) if a natural log was requested.
;-----------------------------------------------------------
LOGFINI:
BTST #BTLOGBASE2,D3
BNE.S @1
PEA FPKLOGE2
PEA (A4)
ELFMULX ; LOG2(X) * LN(2)
MOVE.L 2(A4),D0 ; nonzero result is inexact <18 May 90, JPO>
OR.L 6(A4),D0
BEQ.S @1
BSR FORCEINEXACT
@1:
BRA RESULTDELIVERED
;-----------------------------------------------------------
; Compute LOG2(1+S) for S between SQRT(1/2) and SQRT(2).
; Assume all special cases have been filtered out and that
; number (A4) is indeed within range.
; Let R := S / (2 + S).
; Then LOGAPPROX := R * P(R*R) / Q(R*R),
; where the coefficients are taken from LOG21P and LOG21Q.
;
; Leave cell W alone, for use by LOG2R.
; Use cell Y for R, X for R*R.
; Use (A4) for R * P(R*R); then Y for Q(R*R).
; Registers A0-A2 are used by the POLYEVAL.
;
; To avoid spurious inexact, filter out 0.
; To keep accuracy, filter out denorms.
;-----------------------------------------------------------
LOGAPPROX:
; PEA (A4) ; INPUT OPERAND X DELETED <4/28/92, JPO>
; PEA STJ(A6) ; CELL J FOR CLASS DELETED <4/28/92, JPO>
; ELFCLASSX ; LEAVES -6, ..., 6 IN CELL J DELETED <4/28/92, JPO>
; MOVE.W STJ(A6),D0 ; DELETED <4/28/92, JPO>
; BPL.S @1 ; DELETED <4/28/92, JPO>
; NEG.W D0 ; DELETED <4/28/92, JPO>
;@1 ; label DELETED <4/28/92, JPO>
; SUBQ.W #FCZERO,D0 ; QUICK EXIT IF ZERO, #FCZERO=4 DELETED <4/28/92, JPO>
MOVE.L 2(A4),D0 ; Filter out 0 to avoid spurious inexact <4/28/92, JPO>
OR.L 6(A4),D0 ; <4/28/92, JPO>
; BNE.S LANONZERO ; DELETED <4/28/92, JPO>
BNE.B LANORMAL ; <4/28/92, JPO>
RTS
; At this point, only normal values with magnitude >= 2^-64 are allowed <4/28/92, JPO>
;LANONZERO: ; label DELETED <4/28/92, JPO>
; SUBQ.W #1,D0 ; #FCNORM=5, #FCDENORM=6 DELETED <4/28/92, JPO>
; BEQ.S LANORMAL ; DELETED <4/28/92, JPO>
;-----------------------------------------------------------
; Since log2(1 + tiny) = ln(1 + tiny) / ln(2) and ln(1 + tiny) is tiny + ...
; just divide denorm by ln(2) and return. Share exit code with main computation.
;-----------------------------------------------------------
; PEA FPKLOGE2
; BSR FORCEUFLOW
; BRA.S LAFINI
LANORMAL:
MOVEA.L A4,A0
LEA STX(A6),A1
BSR A0TOA1 ; COPY ARGUMENT TO X
PEA FPK2
PEA (A4)
ELFADDX ; S := S + 2
PEA (A4)
PEA (A1) ; ADRS OF CELL X
ELFDIVX ; X := S / S + 2
MOVEA.L A1,A0 ; ADRS OF CELL X
PEA (A1) ; TWO COPIES FOR SQUARE
PEA (A1)
LEA STY(A6),A1 ; ADRS OF CELL Y
BSR A0TOA1 ; Y := R
ELFMULX ; X := R * R
;-----------------------------------------------------------
; Evaluate P(R*R) into (A4).
;-----------------------------------------------------------
MOVEA.L A4,A0 ; RESULT SLOT
LEA LOG21P,A1 ; COEFFICIENTS OF P
LEA STX(A6),A2 ; R*R
BSR POLYEVAL ; P(R*R)
;-----------------------------------------------------------
; Evaluate R * P(R*R) into (A4); then finished with R in Y.
;-----------------------------------------------------------
PEA STY(A6) ; R
PEA (A4) ; P(R*R)
ELFMULX ; R * P(R*R)
;-----------------------------------------------------------
; Evaluate Q(R*R) into cell Y.
;-----------------------------------------------------------
LEA STY(A6),A0 ; RESULT SLOT
LEA LOG21Q,A1 ; COEFFICIENTS OF Q
LEA STX(A6),A2 ; R*R
BSR POLYEVAL ; Q(R*R)
;-----------------------------------------------------------
; Be sure inexact is set (isn't it set in the course of things?) and clear
; all underflows up to the last step.
; Finally, divide (R* P(R*R)) in (A4) by Q(R*R) in cell Y.
;-----------------------------------------------------------
; BSR CLEARUFLOW ; DELETED <4/28/92, JPO>
PEA STY(A6)
;LAFINI: label DELETED <4/28/92, JPO>
PEA (A4)
ELFDIVX ; (R * P(R*R)) / Q(R*R)
BSR FORCEINEXACT
RTS ; EXIT LOGAPPROX
;-----------------------------------------------------------
; Trailing stubs to deal with special values to be delivered.
; It is less efficient to use a BSR.S at every label and compute the
; value's address from the return address on the stack.
;-----------------------------------------------------------
TINYX: ; small result already at (A4) label ADDED <4/28/92, JPO>
TST.W 2(A0) ; is value denormal? <4/28/92, JPO>
BMI.B @1 ; no, normal <4/28/92, JPO>
BSR FORCEUFLOW ; yes, signal UNDERFLOW <4/28/92, JPO>
@1: ; label ADDED <4/28/92, JPO>
BSR FORCEINEXACT ; result is always INEXACT <4/28/92, JPO>
BRA.B RESULTDELIVERED ; done <4/28/92, JPO>
P0XSTUFF: ; label ADDED <4/28/92, JPO>
BSR FORCEINEXACT ; deliver +0.0 with INEXACT <4/28/92, JPO>
BSR FORCEUFLOW ; and UNDERFLOW signaled <4/28/92, JPO>
P0STUFF:
LEA FPK0,A0
BRA.S STUFFVAL
M0STUFF:
LEA FPKM0,A0
BRA.S STUFFVAL
P1XSTUFF: ; label ADDED <4/28/92, JPO>
BSR FORCEINEXACT ; deliver +1.0 with INEXACT <4/28/92, JPO>
P1STUFF:
LEA FPK1,A0
BRA.S STUFFVAL
M1XSTUFF: ; label ADDED <4/28/92, JPO>
BSR FORCEINEXACT ; deliver -1.0 with INEXACT <4/29/92, JPO>
M1STUFF:
LEA FPKM1,A0
BRA.S STUFFVAL
PINFXSTUFF: ; label ADDED <4/28/92, JPO>
BSR FORCEINEXACT ; deliver +INF with INEXACT <4/28/92, JPO>
BSR FORCEOFLOW ; and OVERFLOW signaled <4/28/92, JPO>
BRA.B PINFSTUFF ; <4/28/92, JPO>
DIVP0STUFF:
BSR FORCEDIVZER
PINFSTUFF:
LEA FPKINF,A0
BRA.S STUFFVAL
DIVM0STUFF:
BSR FORCEDIVZER
MINFSTUFF:
LEA FPKMINF,A0 ; AND FALL THROUGH...
STUFFVAL:
MOVEA.L A4,A1 ; DST ADRS
BSR A0TOA1 ; STUFF THE VAL
STUFFEXIT:
BRA.S RESULTDELIVERED
;-----------------------------------------------------------
; Fabricate a silent NAN, set Invalid, and deliver to destination.
; D0.B should be a nonzero byte code.
;-----------------------------------------------------------
ERRORNAN:
ORI.L #$7FFF4000,D0 ; MAX EXP AND QNANBIT SET! <01APR85>
MOVE.L D0,(A4)+
CLR.L (A4)+
CLR.W (A4)
SUBQ.L #8,A4
BSR FORCEINVALID
;-----------------------------------------------------------
; FALL THROUGH TO...
;-----------------------------------------------------------
;-----------------------------------------------------------
; Finally, a result has been placed in (A4). Restore the environment,
; signaling any required exceptions, restore the registers,
; clean up the stack, and go. The return address has been written onto the
; deepest operand address, and the high word of the old return address is
; an integer count of the amount of stack to kill to get to the true return
; address.
;-----------------------------------------------------------
RESULTDELIVERED:
;-----------------------------------------------------------
; The first step is to expand the 80-bit result to 96 bits if
; the operation is for the latter format. In this case, A4
; contains &DST + 2, and the sign/exponent must simply be
; copied from (A4) to -2(A4).
;-----------------------------------------------------------
TST.B D3 ; 96-bit result required?
BPL.S @1 ; no. 80-bit OK
MOVE.W (A4),-2(A4) ; yes. copy sign/exp to lead word
;-----------------------------------------------------------
; Restore from environment word
;-----------------------------------------------------------
@1:
PEA STENV(A6)
ELFPROCEXIT
;-----------------------------------------------------------
; Clean up the regs and exit.
;-----------------------------------------------------------
MOVEM.L (SP)+,D0-D7/A0-A4 ; RESTORE ALL REGS
UNLK A6
ADDA.W (SP),SP
RTS