mac-rom/Toolbox/InSANE/FPHWNonArith.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

2077 lines
83 KiB
Plaintext

;
; File: FPHWNonArith.a
;
; Contains: Non-arithmetic FP68K functions
;
; Written by: Apple Numerics Group, DSG
;
; Copyright: © 1985-1993 by Apple Computer, Inc., all rights reserved.
;
; 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> 10/24/91 SAM/KSM Rolled in Regatta file.
;
; Regatta Change History:
;
; <3> 6/30/91 SAM Merged from TERROR. [<8> Fixed the PrivTrap detection method to
; account for when PrivTrap is not physically located in Pack4.]
; <2> 5/28/91 SAM Merged from TERROR. [<7> Added Stuart McDonald's latest fixes
; (see below for details)]
; <1> 5/15/91 SAM Split off from TERROR Proj.
;
; Terror Change History:
;
; <5> 1/18/91 BG Removed debugging code.
; <4> 1/17/91 BG Conditionalized the PrivTrap source and installation code so it
; will only check whether or not it is needs to be installed if it
; is assembled as a System Disk .rsrc. The 040 code is retained so
; that 020/030 machines containing an 040 accelerator will work
; correctly.
; <3> 1/14/91 BG Integrated the 040 PrivTrap (installation and run-time) code
; into this file.
; <2> 1/9/91 BG Modified the code to handle at run-time the differences between
; the 881/882 and the 040 FPUs.
; <1> 1/6/90 BG Added to TERROR/BBS for the time.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; File: FP881nonarith.a
;; Implementation of FP68K non-arithmetic functions.
;; Copyright Apple Computer, Inc. 1985,1986,1987,1989,1990
;; All Rights Reserved
;; Confidential and Proprietary to Apple Computer,Inc.
;;
;; Written by Clayton Lewis, begun 14 Feb 85.
;; Debugged by Stuart McDonald.
;;
;; Modification history:
;; Rev2: 16 May 85
;; Rev3: 17 May 85
;; Rev4: 17 May 85
;; Rev5: 27 May 85
;; Rev6: 30 May 85
;; Rev7: 04 Jun 85
;; Rev8: 16 Jun 85 CRL moved to MPW
;; Rev9: 08 Sep 86 -S.McD. Minor revs. to NextAfter to handle NaNs and SNaNs
;; RevA: 19 Nov 86 -S.McD. Fixed TestExp's case selection.
;; 26 Dec 86 -S.McD. CopySign rearranged slightly.
;; 28 Dec 86 -S.McD. Fixed ProcEx's behavior.
;; 30 Dec 86 -S.McD. Zeroed FPSR for NonArith codes exiting thru halt check.
;; 03 Jan 87 -S.McD. Nextafter was signalling on old status.
;; 13 Jan 87 -S.McD. Now save/restore any of the registers FP2-FP7 used.
;; 15 Jan 87 -S.McD. Status and copyright notice changed.
;; 21 Jan 87 -S.McD. Cleaned up SetHv/GetHv.
;; 22 Jan 87 -S.McD. SetExp was setting halt bit instead of flag bit.
;; RevB: 28 Dec 89 -S.McD. Complete rewrite begins.
;; 22 May 90 -S.McD. Goes alpha for Waimea. Updated Copyright and version.
;; 7 Sep 90 -S.McD. Goes beta for Tim. Updated version number.
;; 30 Sep 90 -S.McD. Made fp exception handlers A-trap aware.
;; 30 Sep 90 -S.McD. Goes final for Terror alpha.
;; 12 Dec 90 -S.McD. Added stmt to return computed FPIAR to FPIAR.
;; 12 Dec 90 -JPO Modified SetE, trap handlers, and PrivTrap% for MC68040
;; 17 Dec 90 -JPO Corrected sign of INF in DZHANDLER for ATANH(±1).
;; 20 Dec 90 -JPO Corrected branch dest in STDTAIL after clearing E3 exception
;; pending bit (040 mode).
;; 18 May 91 -S.McD. Fixed spurious flag errors for FMOVEs in trap enabled cases.
;; 21 May 91 -S.McD. Had test backwards for SNAN FPU dst case when traps enabled.
;; 21 Jun 91 -JPO Modified STDTAIL for 881 to check for trapping caused by
;; PrivTrap not installed by ½SANE.
;; 30 Mar 92 -JPO Substituted "FMOVE.W #1,FP2" for "FMOVECR #$32,FP1".
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GET ENVIRONMENT. INVALID halt bit kept as (BSUN OR SNAN).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QGETENV:
MOVEM.L D0-D2/A0,-(SP)
FMOVE.L FPSR,D0 ; D0 := FPSR
MOVEA.L 20(SP),A0 ; A0 := DST ADDR
MOVEQ #0,D2 ; D2 := 0, IMAGE OF ENV.
FMOVE.L FPCR,D1 ; D1 := FPCR
BFEXTU D0{24:5},D0 ; GRAB 5 STICKIES
MOVE.B STICKYMAP(D0),D0; MAP TO SANE ORDERING
BFINS D0,D2{19:5} ; STUFF 5 MAPPED STICKIES INTO USER'S ENV
BCLR #13,D1 ; PREPARE TO COPY INVALID BIT TO OPERR BIT IN D1
BFTST D1{16:2} ; HALT ON INVALID IFF (BSUN OR SNAN) IS SET
BEQ.S @1 ; NO, BRANCH
BSET #13,D1 ; YES, SET OPERR BIT
@1: BFEXTU D1{18:5},D0 ; GRAB 5 HALT ENABLES (ASSUMES SET BY QSETENV)
MOVE.B STICKYMAP(D0),D0; MAP TO SANE ORDERING
BFINS D0,D2{27:5} ; STUFF 5 MAPPED HALT ENABLES INTO USER'S ENV
BFEXTU D1{24:2},D0 ; GRAB 2 PREC BITS
MOVE.B PRECMAP(D0),D0 ; MAP TO SANE ORDERING
BFINS D0,D2{25:2} ; STUFF 2 MAPPED PREC BITS INTO USER'S ENV
BFEXTU D1{26:2},D0 ; GRAB 2 RND BITS
MOVE.B RNDMAP(D0),D0 ; MAP TO SANE ORDERING
BFINS D0,D2{17:2} ; STUFF 2 MAPPED RND BITS INTO USER'S ENV
MOVE D2,(A0) ; WRITE BACK UPDATED DST
MOVEM.L (SP)+,D0-D2/A0
RTD #4
STICKYMAP:
DC.B 0,16,8,24,2,18,10,26,4,20,12,28,6,22,14,30
DC.B 1,17,9,25,3,19,11,27,5,21,13,29,7,23,15,31
PRECMAP:
DC.B 0,2,1,3
RNDMAP:
DC.B 0,3,2,1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SET ENVIRONMENT. INVALID halt bit kept as (BSUN OR SNAN).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QSETENV:
MOVEM.L D0-D2/A0,-(SP)
MOVEA.L 20(SP),A0 ; A0 := SRC ADDR
MOVE (A0),D2 ; D2 := SRC ENV
FMOVE.L FPSR,D1 ; GET FPSR INTO D1
BFEXTU D2{19:5},D0 ; GRAB 5 STICKIES
MOVE.B STICKYUNMAP(D0),D0 ; MAP TO 881 ORDERING
BFINS D0,D1{24:5} ; STUFF 5 UNMAPPED STICKIES INTO D1
FMOVE.L D1,FPSR ; HAMMER FPSR WITH D1
FMOVE.L FPCR,D1 ; GET FPCR INTO D1
BFEXTU D2{27:5},D0 ; GRAB 5 HALT ENABLES
MOVE.B STICKYUNMAP(D0),D0 ; MAP TO 881 ORDERING
BSET #4,D0 ; ALWAYS ENABLE OPERR TRAPPING
BFINS D0,D1{16:7} ; STUFF 5 (SIGN EXTENDED TO 7) HALT ENABLES INTO D1
BFEXTU D2{25:2},D0 ; GRAB 2 PREC BITS
MOVE.B PRECMAP(D0),D0 ; MAP TO 881 ORDERING
BFINS D0,D1{24:2} ; STUFF 2 UNMAPPED PREC BITS INTO D1
BFEXTU D2{17:2},D0 ; GRAB 2 RND BITS
MOVE.B RNDMAP(D0),D0 ; MAP TO 881 ORDERING
BFINS D0,D1{26:2} ; STUFF 2 UNMAPPED RND BITS INTO D1
FMOVE.L D1,FPCR ; HAMMER FPCR WITH D1
MOVEM.L (SP)+,D0-D2/A0
RTD #4
STICKYUNMAP:
DC.B %0000000,%1110000,%0000100,%1110100,%0001000,%1111000,%0001100,%1111100
DC.B %0000010,%1110010,%0000110,%1110110,%0001010,%1111010,%0001110,%1111110
DC.B %0000001,%1110001,%0000101,%1110101,%0001001,%1111001,%0001101,%1111101
DC.B %0000011,%1110011,%0000111,%1110111,%0001011,%1111011,%0001111,%1111111
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SET HALT VECTOR & GET HALT VECTOR.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QSETHV:
MOVEM.L D0/A0-A1,-(SP) ; D0 < A0 < A1 < RTS < &HALTVECTOR
MOVEA.L 16(SP),A0 ; A0 := HALTVECTOR ADDR
MOVE.L (A0),FPSTATE+2 ; SAVE HALTVECTOR INTO LOW-MEMORY
cmp.b #cpu68040,CPUFlag; are we on an 040?
blt.s @use881Excepts ; branch if NOT on an 040 to install 881 exception handlers
PEA SNANHANDLER040 ; SIGNALING NAN TRAP VECTOR
PEA STDHANDLER040 ; OVERFLOW TRAP VECTOR
PEA OPERRHANDLER040 ; OPERAND ERROR TRAP VECTOR
PEA STDHANDLER040 ; UNDERFLOW TRAP VECTOR
PEA DZHANDLER040 ; DIVIDE BY ZERO TRAP VECTOR
PEA STDHANDLER040 ; INEXACT RESULT TRAP VECTOR
PEA BSUNHANDLER040 ; UNORDERED CONDITION TRAP VECTOR
bra.s @getOnWithIt ; proceed with the installation
@use881Excepts
PEA SNANHANDLER ; SIGNALING NAN TRAP VECTOR
PEA STDHANDLER ; OVERFLOW TRAP VECTOR
PEA OPERRHANDLER ; OPERAND ERROR TRAP VECTOR
PEA STDHANDLER ; UNDERFLOW TRAP VECTOR
PEA DZHANDLER ; DIVIDE BY ZERO TRAP VECTOR
PEA STDHANDLER ; INEXACT RESULT TRAP VECTOR
PEA BSUNHANDLER ; UNORDERED CONDITION TRAP VECTOR
@getOnWithIt
MOVEA.L SP,A0 ; A0 := address of seven trap vectors
MOVE #2,D0 ; D0 := PrivTrap% SetTrapVec selector
BSR.W PrivTrap% ; SET THE 881/882 TRAP VECTORS!
; (WHY THIS CAN'T BE DONE INLINE, I DON'T KNOW.
; PERHAPS A/UX GROUP LIKES FUNNY STUFF ISOLATED?)
ADDA.W #28,SP ; POP SEVEN SCRATCH ADDRESSES
MOVEM.L (SP)+,D0/A0-A1
RTD #4
QGETHV:
MOVE.L FPSTATE+2,([4,SP])
RTD #4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEGATE.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QNEG:
BCHG.B #7,([4,SP])
RTD #4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ABSOLUTE VALUE.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QABS:
BCLR.B #7,([4,SP])
RTD #4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PROCENTRY.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QPROCENTRY:
MOVE.L 4(SP),-(SP) ; COPY DST ADDRESS AND CALL GETENV
BSR.S QGETENV
FMOVEM.L ZEROENV,FPCR/FPSR ;SET DEFAULT ENVIRONMENT
RTD #4
ZEROENV:
DC.L $2000,0 ; OPERR TRAPPING ALWAYS ENABLED
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TESTEXCEPTION.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QTESTXCP:
MOVEM.L D0-D1/A0,-(SP) ; A0 < D1 < D0 < RTN ADDR < DST ADDR
MOVEQ #0,D0 ; CLEAR FOR BIT FIELD OFFSET LATER
MOVEA.L 16(SP),A0 ; A0 := DESTINATION (SOURCE) ADDRESS
FMOVE.L FPSR,D1 ; D1 := ACCRUED EXCEPTIONS
MOVE.W (A0),D0 ; D0 := SANE BIT INDEX
MOVE.W IndTab(PC,D0*2),D0 ; D0 := ABOVE MAPPED TO 881 BIT FIELD POS.
BFEXTU D1{D0:1},D1 ; GRAB THE BIT
MOVE.B D1,(A0) ; STUFF IT IN HIGH BYTE OF WORD
MOVEM.L (SP)+,D0-D1/A0 ; RESTORE REGISTERS AND GET OUT
RTD #4
IndTab:
DC.W 24,26,25,27,28 ; ALL BUT OVER/UNDERFLOW IN RIGHT ORDER!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; <5/18/91-S.McD.> <T7>
;; preFMOVE disables underflow trapping and precision control until postFMOVE <5/18/91-S.McD.> <T7>
;; is called; FMOVEs will act like FMOVEMs except SNANs WILL signal. Uses D2,D3. <5/18/91-S.McD.> <T7>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; <5/18/91-S.McD.> <T7>
preFMOVE: ; DISABLE UNDERFLOW TRAPPING FOR SUBNORMALS <5/18/91-S.McD.> <T7>
FMOVE.L FPCR,D2 ; D2 := FPCR <5/18/91-S.McD.> <T7>
MOVE.L #%100011000000,D3 ; MASK FOR UNFL,PREC,PREC <5/18/91-S.McD.> <T7>
AND.L D2,D3 ; UNFL OR PREC SET IN FPCR? <5/18/91-S.McD.> <T7>
BEQ.S @1 ; BRANCH: NONE SET <5/18/91-S.McD.> <T7>
EOR.L D3,D2 ; OTHERWISE, TOGGLE THOSE SET(CLEARING THEM)<5/18/91-S.McD.> <T7>
FMOVE.L D2,FPCR ; DISABLE UNFL TRAPS AND PRECISION CONTROL <5/18/91-S.McD.> <T7>
@1: ; <5/18/91-S.McD.> <T7>
RTS ; <5/18/91-S.McD.> <T7>
postFMOVE: ; RESTORES FPCR AFTER preFMOVE (USES D2,D3) <5/18/91-S.McD.> <T7>
TST.L D3 ; ANY OF UNFL,PREC,PREC SET? <5/18/91-S.McD.> <T7>
BEQ.S @1 ; BRANCH: NONE SET <5/18/91-S.McD.> <T7>
EOR.L D3,D2 ; OTHERWISE, TOGGLE THEM (RESTORING THEM) <5/18/91-S.McD.> <T7>
FMOVE.L D2,FPCR ; AND RESTORE FPCR <5/18/91-S.McD.> <T7>
@1: ; <5/18/91-S.McD.> <T7>
RTS ; <5/18/91-S.McD.> <T7>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEXTAFTER96 - Modify SRC96 by one ulp in direction of DST96
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QNEXTX96:
LINK A6,#-LK2SIZE ; use link so halthandler can find args
MOVE.L #LK2POP+FFEXT+FONEXT+FFEXT96,LKOP(A6); popsize & opword for halthandler
MOVEM.L D0-D3/A0,-(SP) ; SAVE REGS <5/18/91-S.McD.> <T7>
BSR.S preFMOVE ; DISABLE UNFL TRAPPING AND PREC CONTROL <5/18/91-S.McD.> <T7>
MOVEA.L LKDST(A6),A0
FMOVE (A0),FP1 ; FP1 := DST
MOVEA.L LKSRC(A6),A0 ; A0 := &SRC
FMOVE (A0),FP0 ; FP0 := SRC
FMOVE FP0,(A0) ; MUST WRITE BACK BECAUSE OF UNNORMALS
MOVE.W (A0)+,(A0) ; REPLICATE EXPONENT & BUMP A0 FOR 80-BIT CODE
BRA.S QNEXTXENTRY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEXTAFTER - Modify SRC by one ulp in direction of DST
;; 1. Handle NaN and SRC equals DST cases.
;; 2. Handle SRC zero case.
;; 3. Handle SRC non-zero case (the typical case) by bumping SRC in memory.
;; 4. Handle result underflows case.
;; 5. Handle result overflows case.
;; 6. Return.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QNEXTX:
LINK A6,#-LK2SIZE ; use link so halthandler can find args
MOVE.L #LK2POP+FFEXT+FONEXT,LKOP(A6) ; popsize & opword for halthandler
MOVEM.L D0-D3/A0,-(SP) ; SAVE REGS <5/18/91-S.McD.> <T7>
BSR.S preFMOVE ; DISABLE UNFL TRAPPING AND PREC CONTROL <5/18/91-S.McD.> <T7>
DST2STK
FMOVE (SP)+,FP1 ; FP1 := DST
; THE FOLLOWING FMOVE'S COULD BE FMOVEM'S
; TO PREVENT PRECISION CONTROL NARROWING;
; TRUE FOR ANY OTHER FOP'S IN THIS CODE, TOO.
SRC2STK
FMOVE (SP)+,FP0 ; FP0 := SRC
FPU2SRC ; MUST WRITE BACK BECAUSE OF UNNORMALS
QNEXTXENTRY:
FCMP FP0,FP1 ; EITHER INPUT A NAN?
FBOGL.W @2 ; BRANCH: ORDERED, SRC != DST CASE
; NAN AND EQUALITY CASES:
FBEQ.W @1 ; BRANCH: SRC == DST
FCMP FP0,FP0 ; IS SRC NAN?
FBUN.W @1 ; BRANCH: SRC NAN CASE
FMOVE FP1,FP0 ; SRC := DST NAN
@1: ; SRC NAN CASE (AND SRC == DST CASE):
FPU2SRC ; WRITE NAN TO MEMORY
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BRA.W @6 ; BRANCH: RETURN CASE
@2: ; ORDERED, SRC != DST CASE:
FSOLT.B D1 ; D1.B := (SRC > DST ? -1 : 0) ... USED IN @3
FTEST FP0 ; SRC ZERO?
FBNE.W @3 ; BRANCH: SRC NON-ZERO CASE
; SRC ZERO CASE:
FMOVE.X #"$000000000000000000000001",FP0 ; SRC := TINIEST SUBNORMAL
FTEST FP1 ; FP0 GETS FP1'S SIGN...
FBOGT.W @21 ; BRANCH: DST NEG. CASE
FNEG FP0 ; DST NEG. CASE:
@21: ; DST POS. CASE:
FPU2SRC ; WRITE RESULT TO MEM. BEFORE SIGNALING UNDERFLOW
BRA.S @4 ; BRANCH: RESULT EXPONENT FIELD ZERO CASE
@3: ; SRC NON-ZERO CASE (TYPICAL CASE):
FSOLT.B D0 ; D0.B := SRC'S SIGN SIGN-EXTENDED TO BYTE
EOR.B D1,D0 ; SRC < 0 TOGGLE'S SENSE (SIGN-MAG VS. 2'S COMP)
BPL.S @31 ; BRANCH: INCREMENT CASE
; DECREMENT CASE:
BFTST (A0){1:15} ; EXPONENT FIELD ZERO?
BEQ.S @30 ; IF SO, SKIP NEXT INSTRUCTION
BCLR #7,2(A0) ; ...CLEAR EXPLICIT BIT
@30: SUBQ.L #1,6(A0) ; BUMP THE LOW 3RD OF EXTENDED
BCC.S @33 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
SUBQ.L #1,2(A0) ; SUBTRACT BORROW FROM MID 3RD OF EXTENDED
BCC.S @33 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
SUBQ.W #1,(A0) ; SUBTRACT BORROW FROM HI 3RD OF EXTENDED
BRA.S @33 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
@31: ; INCREMENT CASE:
BFTST (A0){1:15} ; EXPONENT FIELD ZERO?
BEQ.S @32 ; IF SO, SKIP NEXT INSTRUCTION
BSET #7,2(A0) ; ...SET EXPLICIT BIT
@32: ADDQ.L #1,6(A0) ; BUMP THE LOW 3RD OF EXTENDED
BCC.S @33 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
ADDQ.L #1,2(A0) ; ADD CARRY INTO MID 3RD OF EXTENDED
BCC.S @33 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
ADDQ.W #1,(A0) ; ADD CARRY INTO HI 3RD OF EXTENDED
@33: ; CHECK FOR UNDER/OVERFLOW CASE:
MOVE.L (A0),D0 ; PICK IT UP AGAIN FOR SIGNAL CHECKS BELOW
BFCHG D0{1:15} ; TOGGLE THE EXPONENT FIELD
BNE.S @5 ; BRANCH: RESULT EXPONENT FIELD NON-ZERO CASE
@4: ; RESULT EXPONENT FIELD ZERO CASE:
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BTST #7,2(A0) ; DO WE HAVE A SUBNORMAL?
BNE.S @6 ; BRANCH: RETURN CASE (WAS NORMAL)
; SUBNORMAL CASE:
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 := 1.0 <3/30/92, JPO>
FSCALE.W #$8000,FP1 ; SIGNAL UNDERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
BRA.S @6 ; BRANCH: RETURN CASE
@5: ; RESULT EXPONENT FIELD NON-ZERO CASE:
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BFCHG D0{1:15} ; TOGGLE THE EXPONENT FIELD
BEQ.S @51 ; BRANCH: EXPONENT FIELD ALL-ONE
; ORDINARY EXPONENT FIELD CASE:
BSET #7,2(A0) ; SET THE EXPLICIT BIT
BRA.S @6 ; BRANCH: RETURN CASE
@51: ; RESULT EXPONENT FIELD ALL-ONE CASE:
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 := 1.0 <3/30/92, JPO>
FSCALE.W #$7FFF,FP1 ; SIGNAL OVERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
@6: ; RETURN CASE:
BTST #FPX96BIT,LKOP+3(A6); 96 BIT CLEAR?
BEQ.S @61 ; IF SO, SKIP NEXT INSTRUCTION
MOVE.W (A0),-(A0) ; COPY 80-BIT EXP. WORD TO 96-BIT LOCATION
@61:
MOVEM.L (SP)+,D0-D3/A0 ; RESTORE REGS <5/18/91-S.McD.> <T7>
UNLK A6
RTD #8
QNEXTD:
LINK A6,#-LK2SIZE ; use link so halthandler can find args
MOVE.L #LK2POP+FFDBL+FONEXT,LKOP(A6) ; popsize & opword for halthandler
MOVEM.L D0-D3/A0,-(SP) ; SAVE REGS <5/18/91-S.McD.> <T7>
BSR.W preFMOVE ; DISABLE UNFL TRAPPING AND PREC CONTROL <5/18/91-S.McD.> <T7>
MOVEA.L LKDST(A6),A0
FMOVE.D (A0),FP1 ; FP1 := DST ... SNAN DST SIGNALS HERE!
MOVEA.L LKSRC(A6),A0
FMOVE.D (A0),FP0 ; FP0 := SRC ... SNAN SRC SIGNALS HERE!
FCMP FP0,FP1 ; EITHER INPUT A NAN?
FBOGL.W @2 ; BRANCH: ORDERED, SRC != DST CASE
; NAN AND EQUALITY CASES:
FBEQ.W @1 ; BRANCH: SRC == DST
FCMP FP0,FP0 ; IS SRC NAN?
FBUN.W @1 ; BRANCH: SRC NAN CASE
FMOVE FP1,FP0 ; SRC := DST NAN
@1: ; SRC NAN CASE (AND SRC == DST CASE):
FMOVE.D FP0,(A0) ; WRITE NAN TO MEMORY
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BRA.S @6 ; BRANCH: RETURN CASE
@2: ; ORDERED, SRC != DST CASE:
FSOLT.B D1 ; D1.B := (SRC > DST ? -1 : 0) ... SEE @3
FTEST FP0 ; SRC ZERO?
FBNE.W @3 ; BRANCH: SRC NON-ZERO CASE
; SRC ZERO CASE:
FMOVE.D #"$0000000000000001",FP0 ; SRC := TINIEST SUBNORMAL
FTEST FP1 ; FP0 GETS FP1'S SIGN...
FBOGT.W @21 ; BRANCH: DST NEG. CASE
FNEG FP0 ; DST NEG. CASE:
@21: ; DST POS. CASE:
FMOVE.D FP0,(A0) ; WRITE RESULT TO MEM. BEFORE SIGNALING UNDERFLOW
BRA.S @4 ; BRANCH: RESULT EXPONENT FIELD ZERO CASE
@3: ; SRC NON-ZERO CASE (TYPICAL CASE):
FSOLT.B D0 ; D0.B := SRC'S SIGN SIGN-EXTENDED TO BYTE
EOR.B D1,D0 ; SRC < 0 TOGGLE'S SENSE (SIGN-MAG VS. 2'S COMP)
BPL.S @31 ; BRANCH: INCREMENT CASE
; DECREMENT CASE:
SUBQ.L #1,4(A0) ; BUMP THE LOW HALF OF THE DOUBLE
BCC.S @32 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
SUBQ.L #1,(A0) ; SUBTRACT BORROW FROM HIGH HALF OF DOUBLE
BRA.S @32 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
; INCREMENT CASE:
@31: ADDQ.L #1,4(A0) ; BUMP THE LOW HALF OF THE DOUBLE
BCC.S @32 ; BRANCH: CHECK FOR UNDER/OVERFLOW CASE
ADDQ.L #1,(A0) ; ADD CARRY INTO HIGH HALF OF DOUBLE
@32: ; CHECK FOR UNDER/OVERFLOW CASE:
MOVE.L (A0),D0 ; PICK IT UP AGAIN FOR SIGNAL CHECKS BELOW
BFCHG D0{1:11} ; TOGGLE THE EXPONENT FIELD
BNE.S @5 ; BRANCH: RESULT EXPONENT FIELD NON-ZERO CASE
@4: ; RESULT EXPONENT FIELD ZERO CASE:
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 :- 1.0 <3/30/92, JPO>
FSCALE.W #$8000,FP1 ; SIGNAL UNDERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
BRA.S @6 ; BRANCH: RETURN CASE
@5: ; RESULT EXPONENT FIELD NON-ZERO CASE:
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BFCHG D0{1:11} ; TOGGLE THE EXPONENT FIELD
BNE.S @6 ; BRANCH: RETURN CASE
; RESULT EXPONENT FIELD ALL-ONE CASE:
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 := 1.0 <3/30/92, JPO>
FSCALE.W #$7FFF,FP1 ; SIGNAL OVERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
@6: ; RETURN CASE:
MOVEM.L (SP)+,D0-D3/A0 ; RESTORE REGS <5/18/91-S.McD.> <T7>
UNLK A6
RTD #8
QNEXTS: ; Modify SRC by one ulp in direction of DST
LINK A6,#-LK2SIZE ; use link so halthandler can find args
MOVE.L #LK2POP+FFSGL+FONEXT,LKOP(A6) ; popsize & opword for halthandler
MOVEM.L D0-D3/A0,-(SP) ; SAVE REGS <5/18/91-S.McD.> <T7>
MOVEA.L LKDST(A6),A0
MOVE.L (A0),D1 ; D1 := DST
MOVEA.L LKSRC(A6),A0
MOVE.L (A0),D0 ; D0 := SRC
BSR.W preFMOVE ; DISABLE UNFL TRAPPING AND PREC CONTROL <5/18/91-S.McD.> <T7>
FMOVE.S D1,FP1 ; FP1 := DST ... SNAN DST SIGNALS HERE!
FMOVE.S D0,FP0 ; FP0 := SRC ... SNAN SRC SIGNALS HERE!
FCMP FP0,FP1 ; EITHER INPUT A NAN?
FBOGL.W @2 ; BRANCH: ORDERED, SRC != DST CASE
; NAN AND EQUALITY CASES:
FBEQ.W @1 ; BRANCH: SRC == DST
FCMP FP0,FP0 ; IS SRC NAN?
FBUN.W @1 ; BRANCH: SRC NAN CASE
FMOVE FP1,FP0 ; SRC := DST NAN
@1: ; SRC NAN CASE (AND SRC == DST CASE):
FMOVE.S FP0,(A0) ; WRITE NAN TO MEMORY
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BRA.S @6 ; BRANCH: RETURN CASE
@2: ; ORDERED, SRC != DST CASE:
BSR.W postFMOVE ; RESTORE FPCR. USES D2,D3. <5/18/91-S.McD.> <T7>
BFTST D0{1:31} ; IS SRC ZERO?
BNE.S @3 ; BRANCH: SRC NON-ZERO CASE
; SRC ZERO CASE:
MOVEQ.L #2,D0 ; CONSTRUCT SIGNED TINEST SUBNORMAL...
ADD.L D1,D1 ; SHIFT DST SIGN INTO CARRY
ROXR.L #1,D0 ; D0 := $80000001 (OR $00000001)
MOVE.L D0,(A0) ; WRITE RESULT TO MEMORY BEFORE SIGNALING UNDERFLOW
BRA.S @4 ; BRANCH: RESULT EXPONENT FIELD ZERO CASE
@3: ; SRC NON-ZERO CASE (TYPICAL CASE):
BTST #31,D0 ; TEST SRC'S SIGN
SNE.B D0 ; D0.B := SRC'S SIGN SIGN-EXTENDED TO BYTE
FSOLT.B D1 ; D1.B := (SRC > DST ? -1 : 0)
EOR.B D1,D0 ; SRC < 0 TOGGLE'S SENSE (SIGN-MAG VS. 2'S COMP)
EXTB.L D0 ; D0.L := -1 OR 0
ADD.L D0,D0 ; DO.L := -2 OR 0
ADDQ.L #1,D0 ; DO.L := -1 OR 1
ADD.L D0,(A0) ; BUMP THE FLOAT IN MEMORY!
MOVE.L (A0),D0 ; PICK IT UP AGAIN FOR SIGNAL CHECKS BELOW
; CHECK FOR UNDER/OVERFLOW:
BFCHG D0{1:8} ; TOGGLE THE EXPONENT FIELD
BNE.S @5 ; BRANCH: RESULT EXPONENT FIELD NON-ZERO CASE
@4: ; RESULT EXPONENT FIELD ZERO CASE:
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 := 1.0 <3/30/92, JPO>
FSCALE.W #$8000,FP1 ; SIGNAL UNDERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
BRA.S @6 ; BRANCH: RETURN CASE
@5: ; RESULT EXPONENT FIELD NON-ZERO CASE:
BFCHG D0{1:8} ; TOGGLE THE EXPONENT FIELD
BNE.S @6 ; BRANCH: RETURN CASE
; RESULT EXPONENT FIELD ALL-ONE CASE:
; FMOVECR #$32,FP1 ; FP1 := 1.0 DELETED <3/30/92, JPO>
fmove.w #1,fp1 ; FP1 := 1.0 <3/30/92, JPO>
FSCALE.W #$7FFF,FP1 ; SIGNAL OVERFLOW!!!
FNOP ; CATCH SIGNAL BEFORE RTD
@6: ; RETURN CASE:
MOVEM.L (SP)+,D0-D3/A0 ; RESTORE REGS <5/18/91-S.McD.> <T7>
UNLK A6
RTD #8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PROCEXIT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QPROCEXIT:
LINK A6,#-LK1SIZE ; use link so halthandler can find args
MOVE.L #LK1POP+FOPROCEXIT,LKOP(A6) ; popsize & opword for halthandler
MOVEM.L D0-D1/A0,-(SP) ; SAVE REGS
FMOVE.L FPSR,D1 ; D1 := SAVE PENDING PENDING FLAGS
BFEXTS D1{24:5},D0 ; D0.L := ACCRUED EXCEPTIONS SIGN-EXTENDED
BFINS D0,D1{16:7} ; MAP ACCRUED EXCEPTIONS ONTO NON-ACCRUED
MOVE.L LKDST(A6),-(SP) ; PUSH OLD ENVIRONMENT ADDRESS
BSR.S QSETENV ; RESTORE OLD ENVIRONMENT...SOMEWHAT WASTEFUL
BRA.S SetE ; BRANCH: SIGNAL PENDING FLAGS IN D1 AND RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SETEXCEPTION * ASSUMPTION: BSUN AND SNAN SET IFF INVALID HALT ENABLED.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QXCPMAP: DC.W $E080,$0820,$1040,$0410,$0208 ; ALL BUT OVER/UNDERFLOW IN RIGHT ORDER!
QSETXCP:
LINK A6,#-LK1SIZE ; use link so halthandler can find args
MOVE.L #LK1POP+FOSETXCP,LKOP(A6) ; popsize & opword for halthandler
MOVEM.L D0-D1/A0,-(SP) ; SAVE REGS
MOVEA.L LKDST(A6),A0 ; A0 := &XCP
MOVEQ #0,D1 ; CLEAR FOR USE AS A FPSR VALUE
MOVE.W (A0),D1 ; D0 := XCP (0=I,1=U, 2=O,3=D,4=X)
MOVE.W QXCPMAP(D1*2),D1 ; MAPS XCP TO FPSR FORMAT
SetE:
FMOVE.L FPCR,D0 ; DO WE REALLY HAVE TO TRAP?
AND.W D1,D0 ; INTERSECT PENDINGS WITH HALT ENABLES
ANDI.W #$DF00,D0 ; MASK OUT JUNK, ANY INTERSECTION? (SEE * ABOVE)
BEQ @1 ; BRANCH: JUST SET FLAGS CASE
cmp.b #cpu68040,CPUFlag ; are we an 040? <T2>
blt @trapAs881 ; branch if NOT an 040/050 <T2>
; Handle trap case for MC68040 <T2>
; 000000000000 444444 000000000000
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 444444444444444 00 00
; 00 00 44 00 00
; 00 00 44 00 00
; 000000000000 44 000000000000
MOVEA.L D0,A0 ; save trap exceptions
FMOVE.L FPSR,D0 ; D0 <- FPSR
OR.W D1,D0 ; set desired exceptions in FPSR
FMOVE.L D0,FPSR
MOVE.L A0,D0 ; restore trap exceptions
BTST #15,D0 ; BSUN trap?
BEQ.S @10 ; no
FMOVE.S #"$7FFFFFFF",FP1 ; yes; create BSUN condition
FBGT.W @15
FNOP
BRA.S @2
@10:
BTST #14,D0 ; SNaN trap?
BEQ.S @11 ; no
FCMP.S #"$7FBFFFFF",FP1 ; yes; create SNaN condition
BRA.S @15
@11:
BTST #12,D0 ; OVERFLOW trap?
BEQ.S @12 ; no
FMOVE.S #"$7F000000",FP1 ; yes; create OVERFLOW condition
FSMUL.X FP1,FP1
BRA.S @15
@12:
BTST #11,D0 ; UNDERFLOW trap?
BEQ.S @13 ; no
FMOVE.S #"$1F000000",FP1 ; yes; create UNDERFLOW condition
FSMUL.X FP1,FP1
BRA.S @15
@13:
BTST #10,D0 ; DIVIDE-BY-ZERO trap?
BEQ.S @14 ; no; must be INEXACT
FMOVE.B #1,FP1 ; yes; create DIVIDE-BY-ZERO condition
FDIV.B #0,FP1
BRA.S @15
@14:
FMOVE.B #1,FP1 ; create INEXACT condition
FADD.S #"$01000000",FP1
@15:
FNOP
BRA.S @2
; ------- 040 ----------------------------------------------------------------
@trapAs881 ; handle trap case as 881/2 <T2>
; 888888888888 888888888888 1111
; 88 88 88 88 11 11
; 88 88 88 88 11 11
; 88 88 88 88 11
; 888888888888 888888888888 11
; 88 88 88 88 11
; 88 88 88 88 11
; 88 88 88 88 11
; 888888888888 888888888888 1111111111
MOVE.L D1,A0 ; PRIVTRAP% EXPECTS PENDING FLAGS IN A0
MOVEQ #0,D0 ; SET SELECTOR TO SETEXCEPT
BSR.W PrivTrap% ; CALL THE PRIVILEGED INSTRUCTION TRAP
FNOP ; FLOATING-POINT EXCEPTION HAPPENS HERE!
BRA.S @2
; ------- 881 ----------------------------------------------------------------
@1: ; JUST SET FLAGS CASE:
FMOVE.L FPSR,D0 ; GET FPSR ...WASTEFUL, QSETENV ALREADY GOT IT!
AND.W $00FF,D0 ; RETAIN ACCRUED EXCEPTIONS ONLY
OR.W D1,D0 ; MODIFY FPSR WITH NEW EXCEPTIONS
FMOVE.L D0,FPSR ; RESTORE FPSR
@2:
MOVEM.L (SP)+,D0-D1/A0 ; RESTORE REGS
UNLK A6
RTD #4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COPYSIGN. ; SRC GETS DST'S SIGN:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QCPYSGN:
MOVE.L A0,-(SP) ; A0 < RTN < &DST < &SRC
MOVEA.L 12(SP),A0 ; A0 := SRC ADDR
BCLR #7,(A0) ; CLEAR SRC'S SIGN
TST ([8,SP]) ; DST'S SIGN ZERO?
BPL.S @1 ; IF SO, SKIP NEXT INSTRUCTION
BSET #7,(A0) ; ...SET SRC'S SIGN
@1: MOVE.L (SP)+,A0
RTD #8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; WRITEFPU writes extended (SP)+ to FPn, where n = D0.W. TRASHES: A0.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WRITEFPU:
MOVEA.L (SP)+,A0 ; POP RETURN ADDRESS
JMP CASEFP0(D0*8) ; SKIP 2 FOR JMP'S EXTENSION WORD (PC POINTS THERE)
CASEFP0: FMOVEM (SP)+,FP0 ; 4 BYTE INSTRUCTION, FP0 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP1 ; 4 BYTE INSTRUCTION, FP1 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP2 ; 4 BYTE INSTRUCTION, FP2 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP3 ; 4 BYTE INSTRUCTION, FP3 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP4 ; 4 BYTE INSTRUCTION, FP4 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP5 ; 4 BYTE INSTRUCTION, FP5 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP6 ; 4 BYTE INSTRUCTION, FP6 := (SP)+
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM (SP)+,FP7 ; 4 BYTE INSTRUCTION, FP7 := (SP)+
@1:
JMP (A0) ; RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NAN2FPU writes NaN(D1.B) to FPn, where n = D0.W (0 thru 7). TRASHES: A0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NAN2FPU:
CLR.L -(SP) ; CREATE NAN'S LEAST SIG. LONG
MOVE.L #$40000000,-(SP) ; CREATE NAN'S MID. SIG. LONG
MOVE.B D1,1(SP) ; STUFF NAN CODE BYTE XX INTO 40XX0000
MOVE.L #$7FFF0000,-(SP) ; CREATE NAN'S MOST SIG. LONG
BSR.B WRITEFPU ; POPS AND WRITES IT TO FPn
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 000000000000 444444 000000000000
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 444444444444444 00 00
; 00 00 44 00 00
; 00 00 44 00 00
; 000000000000 44 000000000000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The code that follows applies to the 881/882 exception handling model.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DIVIDE BY ZERO FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also writes back an infinite result from
;; finite operands because the FPU by default does nothing in the trap enabled case;
;; See 6.1.6 Divide-by-Zero, Trap Enabled Results, p. 6-14 of the 881/2 Manual for futher
;; details. Table 6-3 (Possible Operand Errors) on p. 6-14 is also instructive, as well as
;; Table 4-13 (Extension Filed Encoding for Arithmetic Operations), p. 4-128.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DZHANDLER040:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BEQ.S @0 ; IF NOT, BRANCH: NON-NULL FRAME
TST.B 1(SP) ; IDLE 040 frame?
BNE.S @1 ; no
@0: ; null or idle 040 frame: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@1: ; NON-NULL/IDLE FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; SAVE FPU CONTROL REGS FOR TRAPS USE
MOVEQ #4,D0 ; A1 <- addr just beyond ETEMP in FSAVE frame
ADD.B 1+8*4(SP),D0
LEA 8*4(SP),A1
ADDA.L D0,A1
*
* Write-back answer depending on FDIV & FSGLDIV, FLOGx, FATANH.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
MOVEQ #$7F,D1
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL040 ; IF NOT, GET OUT VIA STANDARD TAIL
AND D2,D1 ; D1 := EXTENSION FIELD (SEE TABLE 4-13, 882 MANUAL)
BCLR #6,D1 ; make FSDIV and FDDIV look like FDIV
BEQ.S @2
BCLR #2,D1
@2:
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
CLR.L -(SP)
CLR.L -(SP)
MOVE.L #$7FFF0000,-(SP) ; PUSH INFINITY
; POOR MAN'S CASE TABLE WITH MOST COMMON FIRST:
CMPI.B #$20,D1 ; FDIV?
BEQ.S FDIV040 ; YES, BRANCH: FDIV
CMPI.B #$24,D1 ; FSGLDIV?
BEQ.S FDIV040 ; YES, BRANCH: FDIV
CMPI.B #$06,D1 ; FLOGNP1?
BEQ.S FLOGx040 ; YES, BRANCH: FLOGx
CMPI.B #$14,D1 ; FLOGN?
BEQ.S FLOGx040 ; YES, BRANCH: FLOGx
CMPI.B #$15,D1 ; FLOG10?
BEQ.S FLOGx040 ; YES, BRANCH: FLOGx
CMPI.B #$16,D1 ; FLOG2?
BEQ.S FLOGx040 ; YES, BRANCH: FLOGx
CMPI.B #$0D,D1 ; FATANH?
BEQ.S FATANH040 ; YES, BRANCH: FATANH
LEA 12(SP),SP ; POP INFINITY
BRA STDTAIL040 ; OTHER? GO FINISH UP
FDIV040:
MOVE.L -24(A1),D1 ; D1 := first longword of extended DST
MOVE.L -12(A1),D2 ; D2 := first longword of extended zero SRC
EOR.L D1,D2 ; XOR SIGNS OF SRC AND DST TOGETHER
BPL.S @1 ; XOR'D SIGNS POSITIVE? IF SO, SKIP NEXT INSTR.
BSET #7,(SP) ; NEGATE INFINITY
@1:
BSR WRITEFPU ; WRITE +-INFINITY TO DST
BRA STDTAIL040 ; AND GET OUT
FLOGx040:
BSET #7,(SP) ; NEGATE INFINITY
BSR WRITEFPU ; WRITE -INFINITY TO DST
BRA STDTAIL040 ; AND GET OUT
FATANH040:
BTST.B #7,-12(A1) ; IS SOURCE NEGATIVE?
BEQ.S @1 ; IF NOT, SKIP NEXT INSTR.
BSET #7,(SP) ; NEGATE INFINITY
@1:
BSR WRITEFPU ; WRITE +-INFINITY TO DST
BRA STDTAIL040 ; AND GET OUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SNAN FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also quiets SNAN when delivering to FP registers
;; (for SNAN trap enabled situations, the FPU doesn't modify the FP registers). See 6.1.2
;; Signaling Not-a-Number, p. 6-7 of the 881/2 Manual for futher details for trap
;; enabled/disabled results; Figures 6-4 & 6-5 (881/2 State Frame Formats) are a help, too.
;;
;; Note: 4.5.4 NANS, p. 4-17 of 881/2 Manual, says in case of two NaNs, the dest NaN is picked;
;; Note: p. 6-9 of 881/2 Manual, "When an SNAN TRAP occurs, the exceptional operand is the
;; source input argument converted to extended precision."
;; Ancient History: the Mac+ and IIGS SANEs always delivered the NaN with the higher NaN code
;; when both inputs were NaNs; as of the MacII, this archaic practice was stopped.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SNANHANDLER040:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BEQ.S @0 ; If so, branch: null 040 frame
TST.B 1(SP) ; IDLE 040 frame?
BNE.S @1 ; no
@0: ; null or idle 040 frame: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@1: ; BUSY or UNIMPLEMENTED frame case: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; SAVE FPU CONTROL REGS FOR TRAPS USE
MOVEQ #4,D0 ; A1 <- addr just beyond ETEMP in FSAVE frame
ADD.B 1+8*4(SP),D0
LEA 8*4(SP),A1
ADDA.L D0,A1
*
* Is the destination a FPU register? If so, we've got work to do.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL040 ; IF NOT, GET OUT VIA STANDARD TAIL
BFEXTU D2{16:3},D0 ; D0 := OPCLASS (SEE TABLE 4-11, 882 MANUAL)
BEQ.S @2 ; OPCLASS 000? BRANCH: FPn DESTINATION
SUBQ #2,D0 ; D0 := OPCLASS - 2
BEQ.S @2 ; OPCLASS 010? BRANCH: FPn DESTINATION
BRA STDTAIL040 ; OPCLASS XXX? BRANCH: DO NOTHING SPECIAL
*
* One (or more) of src or dst is SNAN. Which is it so we can quiet it and write it back.
*
@2: ; FPn DESTINATION CASE:
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
*
* Is the SRC extended NAN?
*
LEA -12(A1),A0 ; A0 points to ETEMP (extended SRC) in FSAVE frame
BFEXTU -40(A1){0:3},D1 ; D1 <- STAG
CMPI.B #3,D1 ; NaN SRC?
BEQ.B @3 ; yes
ADDA #-12,A0 ; no, point A0 to FPTEMP (extended DST) in FSAVE frame
@3:
MOVE.L 8(A0),D1 ; push last longword of NaN
MOVE.L D1,-(SP)
MOVE.L 4(A0),D1 ; push middle longword of NaN after setting quiet bit
BSET #30,D1
MOVE.L D1,-(SP)
MOVE.L (A0),-(SP) ; push first longword of NaN
BSR WRITEFPU ; AND WRITE IT BACK
BRA STDTAIL040 ; AND GET OUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OPERR FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also writes back SANE invalid answers since
;; the FPU writes a default NaN for operand error exceptions. See 6.1.3 Operand Error,
;; Trap Enabled Results, p. 6-8 of the 881/2 Manual for futher details. Table 6-2
;; (Possible Operand Errors) on p. 6-8 is also instructive, as well as Table 4-13
;; (Extension Filed Encoding for Arithmetic Operations), p. 4-128. SANE NaN codes
;; can be found in Table 5-1 of the Apple Numerics Manual, 2nd Edition, p. 41.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OPERRHANDLER040:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BEQ.S @0 ; If so, branch: null 040 frame
TST.B 1(SP) ; IDLE 040 frame?
BNE.S @1 ; no
@0: ; null or idle 040 frame: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@1: ; BUSY or UNIMPLEMENTED frame case: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; SAVE FPU CONTROL REGS FOR TRAPS USE
MOVEQ #4,D0 ; A1 <- addr just beyond ETEMP in FSAVE frame
ADD.B 1+8*4(SP),D0
LEA 8*4(SP),A1
ADDA.L D0,A1
*
* Write-back answer.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL040 ; IF NOT, GET OUT VIA STANDARD TAIL
BFEXTU D2{16:3},D0 ; D0 := OPCLASS (SEE TABLE 4-11, 882 MANUAL)
BEQ.S FPUDEST040 ; OPCLASS 000? BRANCH: FPn DESTINATION
SUBQ #2,D0 ; D0 := OPCLASS - 2
BEQ.S FPUDEST040 ; OPCLASS 010? BRANCH: FPn DESTINATION
BRA STDTAIL040 ; OPCLASS XXX? BRANCH: DO NOTHING SPECIAL
; NOTE: QX2{W,L} WILL PEG 881/2 STYLE, NOT MAC+!
FPUDEST040: ; FPn DESTINATION CASE:
BFEXTU D2{25,7},D1 ; extract command extension word
BPL.S @2 ; leading bit clear; not single/double precision
BCLR #6,D1 ; clear leading bit (range now $00-$3f)
BCLR #2,D1 ; clear bit 2
CMPI.B #1,D1 ; if result is 1, operation is FSSQRT or FDSQRT
BNE.S @2 ; otherwise, treat like 881/882 operation
MOVEQ #4,D1
@2:
MOVE.B NANMAP(D1),D1 ; D1.B := MAP TO SANE NAN CODE (SEE TABLE 5-1,ANM2)
; Create SANE NaN on stack from code in D1.B
BEQ.S FSINCOS040 ; ZERO FLAG? BRANCH: WRITE TWO NANS TO FPU
; WRITE ONE NAN TO FPU CASE:
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
BSR NAN2FPU ; FPn := NAN(D1.B), n = D0.W
BRA.S STDTAIL040 ; GO FINISH UP
FSINCOS040: ; WRITE TWO NANS TO FPU CASE: (SEE FSINCOS, 882 MAN)
MOVE.B #NANTRIG,D1 ; D1 := NANTRIG NAN CODE
BFEXTU D2{22:3},D0 ; D0 := s, DESTINATION REGISTER FPs, 0 THRU 7
BSR NAN2FPU ; FPs := NAN(D1.B), s = D0.W
BFEXTU D2{29:3},D0 ; D0 := c, DESTINATION REGISTER FPc, 0 THRU 7
BSR NAN2FPU ; FPc := NAN(D1.B), c = D0.W
BRA.S STDTAIL040 ; GO FINISH UP
*
* For a given F-line instruction, return the corresponding SANE NaN code if the
* instruction can signal OPERR, otherwise return NaN(255), NANINIT.
*
* This table is the cross between
*
* Table 4-13 (Extension Field Encoding for Arithmetic Operations), p.4-128, 882 Manual,
*
* and
*
* Table 5-1 (SANE NaN codes), p.41, Apple Numerics Manual, Second Edition,
*
* with a little help thrown in from
*
* Table 6-2 (Possible Operand Errors), p.6-8, 882 Manual.
*
NANMAP:
* $00 $01 $02 $03 $04 $05 $06 $07
* FMOVE, FINT, FSINH, FINTRZ, FSQRT, undef, FLOGNP1,undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANSQRT,NANINIT,NANLOG, NANINIT
* $08 $09 $0A $0B $0C $0D $0E $0F
* FETOXM1,FTANH, FATAN, undef, FASIN, FATANH, FSIN, FTAN
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINVTRIG,NANLOG,NANTRIG,NANTRIG
* $10 $11 $12 $13 $14 $15 $16 $17
* FETOX, FTWOTOX,FTENTOX,undef, FLOGN, FLOG10, FLOG2, undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANLOG, NANLOG, NANLOG, NANINIT
* $18 $19 $1A $1B $1C $1D $1E $1F
* FABS, FCOSH, FNEG, undef, FACOS, FCOS, FGETEXP,FGETMAN
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINVTRIG,NANTRIG,NANINIT,NANINIT
* $20 $21 $22 $23 $24 $25 $26 $27
* FDIV, FMOD, FADD, FMUL, FSGLDIV,FREM, FSCALE, FSGLMUL
dc.b NANDIV, NANREM, NANADD, NANMUL, NANDIV, NANREM, NANINIT,NANMUL
* $28 $29 $2A $2B $2C $2D $2E $2F
* FSUB, undef, undef, undef, undef, undef, undef, undef
dc.b NANADD, NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT
* $30 $31 $32 $33 $34 $35 $36 $37
* FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS
dc.b 0, 0, 0, 0, 0, 0, 0, 0; FSINCOS FLAGS
* $38 $39 $3A $3B $3C $3D $3E $3F
* FCMP, undef, FTST, undef, undef, undef, undef, undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT
OMEGABOUNDS dc.w OMEGA881BASE-QADDX, OMEGA881END-QADDX
BSUNHANDLER040: ; "The third methodÉ", p.6-6 882 Manual, disable BSUN.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STANDARD TRAP HANDLER FOR FLOATING-POINT EXCEPTIONS BSUN, OVERFLOW, UNDERFLOW, and INEXACT
;;
;; Squirrels away information for emulating SANE's halt mechanism by catching
;; exceptional SANE operations and tail patching them to return to the HALTEMULATOR
;; before returning to the user's code. Creates an image of the SANE stack arguments
;; inside the SANE operation's own local stack frame, places other pertinent information
;; there, disables further trapping, re-directions A6 and the return address, then lets
;; the SANE operation resume executing with the image. The exceptional SANE operation
;; eventually executes a 'UNLK A6' and 'RTD' which takes it surreptitiously to the
;; HALTEMULATOR which then does the final return and stack cleanup.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STDHANDLER040:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BEQ.S @0 ; If so, branch: null 040 frame
TST.B 1(SP) ; idle 040 frame?
BNE.S @1 ; no, busy frame
@0: ; null or idle 040 frame: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@1: ; NON-NULL/IDLE FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; SAVE FPU CONTROL REGS FOR TRAPS USE
MOVEQ #4,D0 ; A1 <- addr just beyond ETEMP in FSAVE frame
ADD.B 1+8*4(SP),D0
LEA 8*4(SP),A1
ADDA.L D0,A1
STDTAIL040:
MOVEM.L (SP),D1/D2 ; D1 := FPCR
; D2 := FPSR
*
* Make the exception no longer pending. (See Figure 9-7, 68040 Manual, p. 9-31.)
* Always clear E3 bit first in FSAVE frame. If it was already clear, clear E1 bit.
*
BCLR.B #1,-28(A1) ; clr E3 bit
; BNE.S @2 ; if it was set, clear exception enables---WRONG dest <12/20/90, JPO>
BNE.S @0 ; if it was set, check FPIAR <12/20/90, JPO>
BCLR.B #2,-28(A1) ; otherwise, clr E1 bit
*
* Are we being called from PACK4? If not, get out; otherwise, squirrel away info
* into the SANE operation's local stack frame.
*
@0: ; added label <12/20/90, JPO>
MOVEA.L 8(SP),A0 ; A0 := FPIAR
SUBA.L $0B6E,A0 ; A0 := FPIAR'S RELATIVE DISTANCE FROM &QADDX
; USING QADDX'S JMP ISLAND AT $0B6C
; TECHNOTE #213 says _StripAddress(s) NOT NEEDED???
CMP2 OMEGABOUNDS,A0 ; ARE WE INSIDE PACK4?
BCS STDEXIT ; IF NOT, GET OUT; OTHERWISE PROCEED <T2>
; NOW KNOW WE GOT HERE FROM PACK4, SO A6 IS OURS!
*
* Reserve space for the user's scratch registers lest their halthandler (invoked at the
* end of the SANE routine) trashes non-trashable registers. Note: SANE has always
* preserved all the address & data registers, but is allowed to trash FP0 & FP1.
*
SUBA #24,A6 ; SKIP OVER POPCOUNT/OPCODE LONG & D0-D2/A0-A1
FMOVEM.L FPCR/FPSR/FPIAR,-(A6) ; SAVE FPU CONTROL REGS FOR HALTEMULATOR
SUBA #12,A6 ; ROOM FOR FP3 SCRATCH REGISTER FOR HALTEMULATOR
*
* Disable traps lest we trap again. (We'll restore them later.)
*
MOVE.L D1,D0 ; D0 := FRCR
BFCLR D0{16:8} ; CLEAR FPCR EXCEPTION ENABLES (FIG.1-1, 881/2 MAN.)
FMOVEM D0,FPCR
*
* Compute the intersection of the previous operation flags and the trap enables.
* All bits are kept on the FPU. The user's invalid halt enable bit is kept as
* (BSUN or SNAN) so OPERR trapping can always remain on, allowing us to override
* the FPU's default OPERR behavior.
*
MOVE.L D1,D0 ; D0 := FPCR
BFCLR D0{16:3} ; PREPARE TO MAP INVALID ENABLE ONTO BSUN,SNAN,OPERR
BFTST D1{16:2} ; HALT ON INVALID IFF (BSUN OR SNAN) IS SET
BEQ.S @3 ; IF NOT, LEAVE BSUN,SNAN,OPERR BITS CLEARED
BFSET D0{16:3} ; OTHERWISE, SET BSUN,SNAN,OPERR BITS
@3: AND D2,D0 ; D0 := INTERSECTION FPSR & FPCR
BFTST D0{16:2} ; BEGIN MAP'N 8 TO 5 BY OR'N BSUN,SNAN ONTO OPERR
BEQ.S @31 ; IF (BSUN OR SNAN) NOT SET, LEAVE OPERR ALONE
BSET #13,D0 ; OTHERWISE, SET OPERR BIT
@31: BFEXTU D0{18:5},D0 ; GRAB 5 HALT ENABLES
MOVE.B (STICKYMAP,PC,D0),D0 ; MAP TO SANE ORDERING; D0.W := HALT_EXCPTNS
*
* Begin constructing the SANE halt stack frame.
* (See Figure 23-1, p.169, Apple Numerics Manual, 2nd Ed.)
*
LEA LKA6+48(A6),A0 ; A0 := ADDRESS OF ORIGINAL SAVED A6 VALUE
SUBQ #8,A6 ; ROOM FOR MISC REC IN FRAME FOR HALTEMULATOR
MOVE.W D0,(A6) ; COPY HALT_EXCPTNS INTO FRAME FOR HALTEMULATOR
MOVE.L A6,-(A6) ; COPY MISC ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKSRC2(A0),-(A6) ; COPY SRC2 ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKSRC(A0),-(A6) ; COPY SRC ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKDST(A0),-(A6) ; COPY DST ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.W LKOPW(A0),-(A6) ; COPY OPCODE WORD INTO FRAME FOR HALTEMULATOR
*
* Compute #args - 2 , where #args is the number of SANE addresses pushed:
* #args - 2 (-1,0,or 1) = LKCNT/4 - 4
*
MOVE LKCNT(A0),D0 ; D0 := LKCNT (HOW MUCH TO POP FOR MANUAL RTD)
LSR #2,D0 ; D0 := D0 / 4
SUBQ #4,D0 ; D0 := LKCNT / 4 - 4
*
* Construct image of SANE addresses in local frame.
*
BEQ.S @2 ; ZERO? BRANCH: TWO SANE ARGUMENTS
BMI.S @1 ; NEG? BRANCH: ONE SANE ARGUMENT
; THREE SANE ARGUMENTS CASE:
MOVE.L LKSRC2(A0),-(A6) ; SRC2 ADDRESS IMAGE FOR RESUMING SANE OP
@2:
MOVE.L LKSRC(A0),-(A6) ; SRC ADDRESS IMAGE FOR RESUMING SANE OP
@1:
MOVE.L LKDST(A0),-(A6) ; DST ADDRESS IMAGE FOR RESUMING SANE OP
; (ADDS {4,8,12} BYTES TO LOCAL FRAME SIZE) ***
*
* Tail patch the user's SANE routine image to return to HALTEMULATOR.
*
LEA HALTEMULATOR,A1 ; A1 := &HALTEMULATOR
MOVE.L A1,-(A6) ; USER'S NEW RETURN ADDRESS := &HALTEMULATOR
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
*
* Adjust A6 so SANE code will UNLK and RTD the stack image just created.
*
MOVE.L LKA6(A0),-(A6) ; BOGUS SAVED A6 VALUE
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
MOVE.L LKOP(A0),-(A6) ; REPLICATE POPCOUNT AND OPCODE WORDS
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
ADDQ #4,A6 ; POINT A6 AT BOGUS SAVED A6
*
* Restore FPU state and return from exception. Restore D0_D2/A0_A1, too.
*
BRA STDEXIT ; <T2>
;STDEXIT040: LEA 12(SP),SP ; POP FPCR/FPSR/FPIAR <T2>
; MOVEM.L (SP)+,D0-D2/A0-A1 ; RESTORE REGISTERS FOR RESUMING SANE OP <T2>
; FRESTORE (SP)+ ; RESTORE FPU STATE <T2>
; RTE ; RETURN FROM EXCEPTION resumes exceptional operation <T2>
; with traps disabled <T2>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 888888888888 888888888888 1111
; 88 88 88 88 11 11
; 88 88 88 88 11 11
; 88 88 88 88 11
; 888888888888 888888888888 11
; 88 88 88 88 11
; 88 88 88 88 11
; 88 88 88 88 11
; 888888888888 888888888888 1111111111
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The code that follows applies to the 881/882 exception handling model.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PUSHFPn writes extended FPn to -(SP), where n = D0.W. TRASHES: A0.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PUSHFPn:
MOVEA.L (SP)+,A0 ; POP RETURN ADDRESS
JMP READFP0(D0*8) ; SKIP 2 FOR JMP'S EXTENSION WORD (PC POINTS THERE)
READFP0: FMOVEM FP0,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP0
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP1,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP1
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP2,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP2
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP3,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP3
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP4,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP4
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP5,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP5
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP6,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP6
BRA.W @1 ; 4 BYTE INSTRUCTION (DON'T CHANGE TO BRA.B)
FMOVEM FP7,-(SP) ; 4 BYTE INSTRUCTION, -(SP) := FP7
@1:
JMP (A0) ; RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DIVIDE BY ZERO FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also writes back an infinite result from
;; finite operands because the FPU by default does nothing in the trap enabled case;
;; See 6.1.6 Divide-by-Zero, Trap Enabled Results, p. 6-14 of the 881/2 Manual for futher
;; details. Table 6-3 (Possible Operand Errors) on p. 6-14 is also instructive, as well as
;; Table 4-13 (Extension Filed Encoding for Arithmetic Operations), p. 4-128.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DZHANDLER:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BNE.S @0 ; IF NOT, BRANCH: NON-NULL FRAME
; NULL FRAME CASE: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@0: ; NON-NULL FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP); SAVE FPU CONTROL REGS FOR TRAPS USE
*
* Write-back answer depending on FDIV & FSGLDIV, FLOGx, FATANH.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
MOVEQ #$3F,D1
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL ; IF NOT, GET OUT VIA STANDARD TAIL
AND D2,D1 ; D1 := EXTENSION FIELD (SEE TABLE 4-13, 882 MANUAL)
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
CLR D2
MOVE.B 1+8*4(SP),D2 ; D2 := STATE FRAME SIZE (SEE FIG. 5-7 882 MANUAL)
MOVE.L -16+8*4(SP,D2),D2 ; D2 := THE FIRST LONGWORD OF THE EXCEPTIONAL OPERAND
CLR.L -(SP)
CLR.L -(SP)
MOVE.L #$7FFF0000,-(SP) ; PUSH INFINITY
; POOR MAN'S CASE TABLE WITH MOST COMMON FIRST:
CMPI.B #$20,D1 ; FDIV?
BEQ.S FDIV ; YES, BRANCH: FDIV
CMPI.B #$24,D1 ; FSGLDIV?
BEQ.S FDIV ; YES, BRANCH: FDIV
CMPI.B #$06,D1 ; FLOGNP1?
BEQ.S FLOGx ; YES, BRANCH: FLOGx
CMPI.B #$14,D1 ; FLOGN?
BEQ.S FLOGx ; YES, BRANCH: FLOGx
CMPI.B #$15,D1 ; FLOG10?
BEQ.S FLOGx ; YES, BRANCH: FLOGx
CMPI.B #$16,D1 ; FLOG2?
BEQ.S FLOGx ; YES, BRANCH: FLOGx
CMPI.B #$0D,D1 ; FATANH?
BEQ.S FATANH ; YES, BRANCH: FATANH
LEA 12(SP),SP ; POP INFINITY
BRA STDTAIL ; OTHER? GO FINISH UP
FDIV: BSR.S PUSHFPn ; PUSH FPn, WHERE n = DO.W
MOVE.L (SP)+,D1 ; D1 := FIRST LONGWORD OF DST EXTENDED
ADDQ #8,SP ; POP REST OF DST EXTENDED
EOR.L D1,D2 ; XOR SIGNS OF SRC AND DST TOGETHER
BPL.S @1 ; XOR'D SIGNS POSITIVE? IF SO, SKIP NEXT INSTR.
BSET #7,(SP) ; NEGATE INFINITY
@1: BSR.S WRITEFPU ; WRITE +-INFINITY TO DST
BRA STDTAIL ; AND GET OUT
FLOGx: BSET #7,(SP) ; NEGATE INFINITY
BSR.S WRITEFPU ; WRITE -INFINITY TO DST
BRA STDTAIL ; AND GET OUT
FATANH: TST.L D2 ; IS SOURCE NEGATIVE?
; BMI.S @1 ; IF SO, SKIP NEXT INSTR. - deleted <12/17/90, JPO>
BPL.S @1 ; if not, skip next instruction <12/17/90, JPO>
BSET #7,(SP) ; NEGATE INFINITY
@1: BSR.S WRITEFPU ; WRITE +-INFINITY TO DST
BRA STDTAIL ; AND GET OUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SNAN FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also quiets SNAN when delivering to FP registers
;; (for SNAN trap enabled situations, the FPU doesn't modify the FP registers). See 6.1.2
;; Signaling Not-a-Number, p. 6-7 of the 881/2 Manual for futher details for trap
;; enabled/disabled results; Figures 6-4 & 6-5 (881/2 State Frame Formats) are a help, too.
;;
;; Note: 4.5.4 NANS, p. 4-17 of 881/2 Manual, says in case of two NaNs, the dest NaN is picked;
;; Note: p. 6-9 of 881/2 Manual, "When an SNAN TRAP occurs, the exceptional operand is the
;; source input argument converted to extended precision."
;; Ancient History: the Mac+ and IIGS SANEs always delivered the NaN with the higher NaN code
;; when both inputs were NaNs; as of the MacII, this archaic practice was stopped.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SNANHANDLER:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BNE.S @0 ; IF NOT, BRANCH: NON-NULL FRAME
; NULL FRAME CASE: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@0: ; NON-NULL FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP); SAVE FPU CONTROL REGS FOR TRAPS USE
*
* Is the destination a FPU register? If so, we've got work to do.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL ; IF NOT, GET OUT VIA STANDARD TAIL
BFEXTU D2{16:3},D0 ; D0 := OPCLASS (SEE TABLE 4-11, 882 MANUAL)
BEQ.S @1 ; OPCLASS 000? BRANCH: FPn DESTINATION
SUBQ #2,D0 ; D0 := OPCLASS - 2
BEQ.S @1 ; OPCLASS 010? BRANCH: FPn DESTINATION
BRA STDTAIL ; OPCLASS XXX? BRANCH: DO NOTHING SPECIAL
*
* One (or more) of src or dst is SNAN. Which is it so we can quiet it and write it back.
*
@1: ; FPn DESTINATION CASE:
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
BSR.S PUSHFPn ; -(SP) := FPn, n = D0.W
LEA (SP),A1 ; A1 := &COPY OF FPn
*
* Is the dst extended NAN?
*
MOVE.L (A1)+,D1 ; D1 := FIRST LONG OF FPn
NOT.L D1 ; TOGGLE EXPONENT BITS <5/21/91-S.McD.> <T7>
BFTST D1{1:15} ; ARE THEY ALL ZERO? <5/21/91-S.McD.> <T7>
BNE.S @2 ; IF NOT ALL ONES, BRANCH: SRC MUST BE NAN
MOVE.L (A1)+,D1 ; D1 := SECOND LONG OF FPn
BCLR #31,D1 ; CLEAR DON'T CARE BIT
OR.L (A1),D1 ; D1 := 2ND AND 3RD LONGS OF FPn OR'D TOGETHER
BEQ.S @2 ; IF SIGNIFICAND ZERO, BRANCH: SRC MUST BE NAN
; DST IS NAN CASE:
BSET #6,-(A1) ; QUIET IT
BSR.S WRITEFPU ; AND WRITE IT BACK
BRA STDTAIL ; AND GET OUT
@2: ; SRC MUST BE NAN CASE:
LEA 12(SP),SP ; POP DST PUSHED EARLIER
*
* Push the exceptional operand from the state frame (see Figure 5-7, 881/2 Manual, p. 5-13),
* quiet it, and write it back to the destination register.
*
CLR D1 ; D0 := 0
MOVE.B 1+8*4(SP),D1 ; D0 := STATE FRAME SIZE
LEA -8+8*4(SP,D1),A1 ; A1 := ADDR LEAST SIG. LONG OF EXCEPTIONAL OPERAND
MOVE.L (A1),-(SP) ; PUSH LOW LONG OF EXCEPTIONAL OPERAND
MOVE.L -(A1),-(SP) ; PUSH MID. LONG OF EXCEPTIONAL OPERAND
BSET #6,(SP) ; QUIET IT
MOVE.L -(A1),-(SP) ; PUSH HIGH LONG OF EXCEPTIONAL OPERAND
BSR.S WRITEFPU ; WRITE IT BACK
BRA STDTAIL ; AND GET OUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OPERR FLOATING-POINT TRAP HANDLER. (See STDHANDLER's comments for more details.)
;; Does the same stuff as STDHANDLER, but also writes back invalid answers since
;; the FPU doesn't write them for operand error exceptions. See 6.1.3 Operand Error,
;; Trap Enabled Results, p. 6-8 of the 881/2 Manual for futher details. Table 6-2
;; (Possible Operand Errors) on p. 6-8 is also instructive, as well as Table 4-13
;; (Extension Filed Encoding for Arithmetic Operations), p. 4-128. SANE NaN codes
;; can be found in Table 5-1 of the Apple Numerics Manual, 2nd Edition, p. 41.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OPERRHANDLER:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BNE.S @0 ; IF NOT, BRANCH: NON-NULL FRAME
; NULL FRAME CASE: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@0: ; NON-NULL FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP); SAVE FPU CONTROL REGS FOR TRAPS USE
*
* Write-back answer.
*
MOVE.L 8(SP),A0 ; A0 := FPIAR (ADDRESS OF F-LINE OPERATION)
MOVE.L (A0),D2 ; D2.W := 2ND WORD OF F-LINE OP, THE COMMAND WORD
BFTST D2{7:3} ; GENERAL INSTR. TYPE? (SEE 4.7 INSTR. ENCODING DETAILS)
BNE STDTAIL ; IF NOT, GET OUT VIA STANDARD TAIL
BFEXTU D2{16:3},D0 ; D0 := OPCLASS (SEE TABLE 4-11, 882 MANUAL)
BEQ.S FPUDEST ; OPCLASS 000? BRANCH: FPn DESTINATION
SUBQ #2,D0 ; D0 := OPCLASS - 2
BEQ.S FPUDEST ; OPCLASS 010? BRANCH: FPn DESTINATION
BRA STDTAIL ; OPCLASS XXX? BRANCH: DO NOTHING SPECIAL
; NOTE: QX2{W,L} WILL PEG 881/2 STYLE, NOT MAC+!
FPUDEST: ; FPn DESTINATION CASE:
MOVE D2,D1 ; D1 := COMMAND WORD
ANDI #$3F,D1 ; D1 := EXTENSION FIELD (SEE TABLE 4-13, 882 MAN)
MOVE.B NANMAP040(D1),D1 ; D1.B := MAP TO SANE NAN CODE (SEE TABLE 5-1,ANM2)
BEQ.S FSINCOS ; ZERO FLAG? BRANCH: WRITE TWO NANS TO FPU
; WRITE ONE NAN TO FPU CASE:
BFEXTU D2{22:3},D0 ; D0 := n, DESTINATION REGISTER FIELD, 0 THRU 7
BSR.S NAN2FPU ; FPn := NAN(D1.B), n = D0.W
BRA.S STDTAIL ; GO FINISH UP
FSINCOS: ; WRITE TWO NANS TO FPU CASE: (SEE FSINCOS, 882 MAN)
MOVE.B #NANTRIG,D1 ; D1 := NANTRIG NAN CODE
BFEXTU D2{22:3},D0 ; D0 := s, DESTINATION REGISTER FPs, 0 THRU 7
BSR.S NAN2FPU ; FPs := NAN(D1.B), s = D0.W
BFEXTU D2{29:3},D0 ; D0 := c, DESTINATION REGISTER FPc, 0 THRU 7
BSR.S NAN2FPU ; FPc := NAN(D1.B), c = D0.W
BRA.S STDTAIL ; GO FINISH UP
*
* For a given F-line instruction, return the corresponding SANE NaN code if the
* instruction can signal OPERR, otherwise return NaN(255), NANINIT.
*
* This table is the cross between
*
* Table 4-13 (Extension Field Encoding for Arithmetic Operations), p.4-128, 882 Manual,
*
* and
*
* Table 5-1 (SANE NaN codes), p.41, Apple Numerics Manual, Second Edition,
*
* with a little help thrown in from
*
* Table 6-2 (Possible Operand Errors), p.6-8, 882 Manual.
*
NANMAP040:
* $00 $01 $02 $03 $04 $05 $06 $07
* FMOVE, FINT, FSINH, FINTRZ, FSQRT, undef, FLOGNP1,undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANSQRT,NANINIT,NANLOG, NANINIT
* $08 $09 $0A $0B $0C $0D $0E $0F
* FETOXM1,FTANH, FATAN, undef, FASIN, FATANH, FSIN, FTAN
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINVTRIG,NANLOG,NANTRIG,NANTRIG
* $10 $11 $12 $13 $14 $15 $16 $17
* FETOX, FTWOTOX,FTENTOX,undef, FLOGN, FLOG10, FLOG2, undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANLOG, NANLOG, NANLOG, NANINIT
* $18 $19 $1A $1B $1C $1D $1E $1F
* FABS, FCOSH, FNEG, undef, FACOS, FCOS, FGETEXP,FGETMAN
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINVTRIG,NANTRIG,NANINIT,NANINIT
* $20 $21 $22 $23 $24 $25 $26 $27
* FDIV, FMOD, FADD, FMUL, FSGLDIV,FREM, FSCALE, FSGLMUL
dc.b NANDIV, NANREM, NANADD, NANMUL, NANDIV, NANREM, NANINIT,NANMUL
* $28 $29 $2A $2B $2C $2D $2E $2F
* FSUB, undef, undef, undef, undef, undef, undef, undef
dc.b NANADD, NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT
* $30 $31 $32 $33 $34 $35 $36 $37
* FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS,FSINCOS
dc.b 0, 0, 0, 0, 0, 0, 0, 0; FSINCOS FLAGS
* $38 $39 $3A $3B $3C $3D $3E $3F
* FCMP, undef, FTST, undef, undef, undef, undef, undef
dc.b NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT,NANINIT
; We don't need to define this twice, right? <T2>
; OMEGABOUNDS dc.w OMEGA881BASE-QADDX, OMEGA881END-QADDX <T2>
PRIVTRAPBOUNDS dc.w $0000,$0080 ; size of PrivTrap <6/21/91, JPO> <T8>
PrivTrapAddr EQU $65C ; dispatch table addr for PrivTrap <6/21/91, JPO> <T8>
BSUNHANDLER: ; "The third methodÉ", p.6-6 882 Manual, disable BSUN.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STANDARD TRAP HANDLER FOR FLOATING-POINT EXCEPTIONS OVERFLOW, UNDERFLOW, INEXACT, BSUN.
;;
;; Squirrels away information for emulating SANE's halt mechanism by catching
;; exceptional SANE operations and tail patching them to return to the HALTEMULATOR
;; before returning to the user's code. Creates an image of the SANE stack arguments
;; inside the SANE operation's own local stack frame, places other pertinent information
;; there, disables further trapping, re-directions A6 and the return address, then lets
;; the SANE operation resume executing with the image. The exceptional SANE operation
;; eventually executes a 'UNLK A6' and 'RTD' which takes it surreptitiously to the
;; HALTEMULATOR which then does the final return and stack cleanup.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STDHANDLER:
FSAVE -(SP) ; SAVE INTERNAL STATE (MUST BE FIRST FPU INSTRUCTION)
TST.B (SP) ; NULL FRAME?
BNE.S @0 ; IF NOT, BRANCH: NON-NULL FRAME
; NULL FRAME CASE: (NEVER HAPPENS, BUT BE SAFE)
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; GET OUT
@0: ; NON-NULL FRAME CASE: (ALWAYS HAPPENS)
MOVEM.L D0-D2/A0-A1,-(SP) ; SAVE REGISTERS FOR TRAPS USE
FMOVEM.L FPCR/FPSR/FPIAR,-(SP); SAVE FPU CONTROL REGS FOR TRAPS USE
STDTAIL: MOVEM.L (SP),D1/D2 ; D1 := FPCR
; D2 := FPSR
*
* Make the exception no longer pending. (See Figure 5-6, 881/2 Manual, p. 5-11.)
*
CLR D0 ; D0 := 0
MOVE.B 1+8*4(SP),D0 ; D0 := STATE FRAME SIZE
BSET #3,8*4(SP,D0) ; SET BIT 27 OF BIU
*
* Are we being called from PACK4? If not, get out; otherwise, squirrel away info
* into the SANE operation's local stack frame.
*
MOVEA.L 8(SP),A0 ; A0 := FPIAR
SUBA.L $0B6E,A0 ; A0 := FPIAR'S RELATIVE DISTANCE FROM &QADDX
; USING QADDX'S JMP ISLAND AT $0B6C
; TECHNOTE #213 says _StripAddress(s) NOT NEEDED???
CMP2 OMEGABOUNDS,A0 ; ARE WE INSIDE PACK4?
; BCS.S STDEXIT ; IF NOT, GET OUT; OTHERWISE PROCEED - deleted <6/21/91, JPO><T8>
BCC.B @4 ; yes <6/21/91, JPO> <T8>
; Although exception did not occur within PACK4, it may have been caused by PrivTrap881
MOVEA.L 8(SP),A0 ; A0 <- FPIAR <6/21/91, JPO> <T8>
SUBA.L PrivTrapAddr,A0 ; A0 <- FPIAR's relative distance from <T8>
; PrivTrap881 entry point <6/21/91, JPO> <T8>
CMP2 PRIVTRAPBOUNDS,A0 ; are we inside PrivTrap881? <6/21/91, JPO> <T8>
BCS.B STDEXIT ; no. get out <6/21/91, JPO> <T8>
; NOW KNOW WE GOT HERE FROM PACK4 (or PrivTrap881), SO A6 IS OURS!
*
* Reserve space for the user's scratch registers lest their halthandler (invoked at the
* end of the SANE routine) trashes non-trashable registers. Note: SANE has always
* preserved all the address & data registers, but is allowed to trash FP0 & FP1.
*
@4: ; label added <6/21/91, JPO>
SUBA #24,A6 ; SKIP OVER POPCOUNT/OPCODE LONG & D0-D2/A0-A1
FMOVEM.L FPCR/FPSR/FPIAR,-(A6); SAVE FPU CONTROL REGS FOR HALTEMULATOR
SUBA #12,A6 ; ROOM FOR FP3 SCRATCH REGISTER FOR HALTEMULATOR
*
* Disable traps lest we trap again. (We'll restore them later.)
*
MOVE.L D1,D0 ; D0 := FRCR
BFCLR D0{16:8} ; CLEAR FPCR EXCEPTION ENABLES (FIG.1-1, 881/2 MAN.)
FMOVEM D0,FPCR
*
* Compute the intersection of the previous operation flags and the trap enables.
* All bits are kept on the FPU. The user's invalid halt enable bit is kept as
* (BSUN or SNAN) so OPERR trapping can always remain on, allowing us to override
* the FPU's default OPERR behavior.
*
MOVE.L D1,D0 ; D0 := FPCR
BFCLR D0{16:3} ; PREPARE TO MAP INVALID ENABLE ONTO BSUN,SNAN,OPERR
BFTST D1{16:2} ; HALT ON INVALID IFF (BSUN OR SNAN) IS SET
BEQ.S @3 ; IF NOT, LEAVE BSUN,SNAN,OPERR BITS CLEARED
BFSET D0{16:3} ; OTHERWISE, SET BSUN,SNAN,OPERR BITS
@3: AND D2,D0 ; D0 := INTERSECTION FPSR & FPCR
BFTST D0{16:2} ; BEGIN MAP'N 8 TO 5 BY OR'N BSUN,SNAN ONTO OPERR
BEQ.S @31 ; IF (BSUN OR SNAN) NOT SET, LEAVE OPERR ALONE
BSET #13,D0 ; OTHERWISE, SET OPERR BIT
@31: BFEXTU D0{18:5},D0 ; GRAB 5 HALT ENABLES
MOVE.B (STICKYMAP,PC,D0),D0; MAP TO SANE ORDERING; D0.W := HALT_EXCPTNS
*
* Begin constructing the SANE halt stack frame.
* (See Figure 23-1, p.169, Apple Numerics Manual, 2nd Ed.)
*
LEA LKA6+48(A6),A0 ; A0 := ADDRESS OF ORIGINAL SAVED A6 VALUE
SUBQ #8,A6 ; ROOM FOR MISC REC IN FRAME FOR HALTEMULATOR
MOVE.W D0,(A6) ; COPY HALT_EXCPTNS INTO FRAME FOR HALTEMULATOR
MOVE.L A6,-(A6) ; COPY MISC ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKSRC2(A0),-(A6) ; COPY SRC2 ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKSRC(A0),-(A6) ; COPY SRC ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.L LKDST(A0),-(A6) ; COPY DST ADDRESS INTO FRAME FOR HALTEMULATOR
MOVE.W LKOPW(A0),-(A6) ; COPY OPCODE WORD INTO FRAME FOR HALTEMULATOR
*
* Compute #args - 2 , where #args is the number of SANE addresses pushed:
* #args - 2 (-1,0,or 1) = LKCNT/4 - 4
*
MOVE LKCNT(A0),D0 ; D0 := LKCNT (HOW MUCH TO POP FOR MANUAL RTD)
LSR #2,D0 ; D0 := D0 / 4
SUBQ #4,D0 ; D0 := LKCNT / 4 - 4
*
* Construct image of SANE addresses in local frame.
*
BEQ.S @2 ; ZERO? BRANCH: TWO SANE ARGUMENTS
BMI.S @1 ; NEG? BRANCH: ONE SANE ARGUMENT
; THREE SANE ARGUMENTS CASE:
MOVE.L LKSRC2(A0),-(A6) ; SRC2 ADDRESS IMAGE FOR RESUMING SANE OP
@2:
MOVE.L LKSRC(A0),-(A6) ; SRC ADDRESS IMAGE FOR RESUMING SANE OP
@1:
MOVE.L LKDST(A0),-(A6) ; DST ADDRESS IMAGE FOR RESUMING SANE OP
; (ADDS {4,8,12} BYTES TO LOCAL FRAME SIZE) ***
*
* Tail patch the user's SANE routine image to return to HALTEMULATOR.
*
LEA HALTEMULATOR,A1 ; A1 := &HALTEMULATOR
MOVE.L A1,-(A6) ; USER'S NEW RETURN ADDRESS := &HALTEMULATOR
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
*
* Adjust A6 so SANE code will UNLK and RTD the stack image just created.
*
MOVE.L LKA6(A0),-(A6) ; BOGUS SAVED A6 VALUE
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
MOVE.L LKOP(A0),-(A6) ; REPLICATE POPCOUNT AND OPCODE WORDS
; (ADDS 4 BYTES TO LOCAL FRAME SIZE) **
ADDQ #4,A6 ; POINT A6 AT BOGUS SAVED A6
*
* Restore FPU state and return from exception. Restore D0_D2/A0_A1, too.
*
; NOTE - this is a COMMON exit point for both the 881/2 and the 040 exception <T2>
; handlers. If you change anything here, make sure it's ok with the <T2>
; STDEXIT040 code. <T2>
STDEXIT: LEA 12(SP),SP ; POP FPCR/FPSR/FPIAR
MOVEM.L (SP)+,D0-D2/A0-A1 ; RESTORE REGISTERS FOR RESUMING SANE OP
FRESTORE (SP)+ ; RESTORE FPU STATE
RTE ; RETURN FROM EXCEPTION
*
* HALTEMULATOR: Exceptional, trapping, SANE routines are tail patched by the above
* code to RTS to this routine before returning to the user's code. The
* stack looks like the following before HALTEMULATOR pops everything.
*
* [HALT_FRAME] (18 local frame bytes)
* STACK: [Opcode.W< &DST< &SRC< &SRC2< &MISC]<
*
* [MISC_REC] ( 8 local frame bytes)
* < [Halt_excpt.W< PendingCCR.W< PendingD0.L]<
*
* [REGS] (44 local frame bytes)
* < [FP3.X< FPCR.L< FPSR.L< FPIAR.L< D0.L< D1.L< D2.L< A0.L< A1.L]<
*
* [OLD_STACK] ( 4 local frame bytes)
* < [POPCOUNT.W< OPCODE.W< A6.L< &RETURN< &DST< &SRC< &SRC2]
* (< &SRC< &SRC2, NOT ALWAYS)
*
* 74 total frame bytes +
* 12 prior " " [see **] =
* ------------------
* 86 = LKSIZE, local frame size
* +{4,8, or 12} bytes [see ***]=
* ={LK1SIZE, LK2SIZE, LK3SIZE}
*
* NOTE: D0 and CCR have been set by remainder and comparison, so we must be careful
* not to trash D0 or affect the CCRs. See pp.168-169 of Numerics Manual, 2nd Ed.
*
HALTEMULATOR:
FMOVEM FP3,26(SP) ; SAVE SCRATCH FP3 LEST HANDLER TRASHES IT
MOVEM.L D0-D2/A0-A1,50(SP) ; SAVE SCRATCH ADDRESS & DATA REGISTERS
LEA 20(SP),A0 ; A0 := &PENDING_CCR.W
MOVE CCR,(A0)+ ; PendingCCR.W := CCR
MOVE.L D0,(A0) ; PendingD0.L := D0
TST -4(A0) ; DO WE REALLY NEED TO CALL USER'S HANDLER?
BEQ.S @0 ; IF NOT, BRANCH: NO INTERSECTIONS
; INTERSECTIONS CASE:
*
* Call the user's halt handler.
*
MOVE.L FPSTATE+2,A0 ; A0 := USER'S HALT ROUTINE ADDRESS
JSR (A0) ; CALL USER'S HALT HANDLER, POPPING HALT_FRAME
BRA.S @1 ; BRANCH: DONE POPPING HALT_FRAME
@0: ; NO INTERSECTIONS CASE:
ADDA #18,SP ; POP HALT_FRAME
@1:
*
* Prepare for a manual RTD by copying &RETURN onto last SANE address.
*
; DONE POPPING HALT_FRAME CASE:
LEA 52(SP),A6 ; A6 := &OLD_STACK ( = &POPCOUNT)
MOVE (A6),D1 ; D1 := POPCOUNT
MOVE.L 8(A6),0(A6,D1) ; COPY &RETURN ON TOP OF LAST OLD_STACK ADDRESS
ADDQ #2,SP ; POP HALT_EXCPT.W
MOVE.L 2(SP),30(SP) ; SET D0.L IN REGS TO USER'S PREFERENCE
MOVE (SP),CCR ; SET CCR TO USER'S PREFERENCE
ADDQ #6,SP ; POP PENDING_CCR.W AND PENDING_D0.L
; DONE POPPING MISC_REC
FMOVEM.X (SP)+,FP3 ; RESTORE FPU SCRATCH REGISTERS
FMOVEM.L (SP)+,FPCR/FPSR/FPIAR ; RESTORE FPU CONTROL REGISERS
MOVEM.L (SP)+,D0-D2/A0-A1 ; RESTORE CPU SCRATCH REGISTERS
; DONE POPPING REGS
MOVEA.L 4(A6),A6 ; RESTORE FINAL A6
ADDA (SP),SP ; MANUAL UNLINK
RTS ; POP OLD_STACK AND RETURN TO USER'S CODE
tFPPriv EQU $A097 ; privileged instruction trap number
tUnimplemented EQU $A89F ; _Unimplemented trap number
_FPPriv OPWORD tFPPriv
IF NOT forROM THEN ; if being built for a System Disk
******************************************************************************************
*
* THE FOLLOWING CODE IS DIRECTLY LIFTED FROM MPW3.2'S CSANELIBRT881.A SOURCE CODE,
* WRITTEN BY PAUL FINLAYSON, BRIAN MCGHIE, JON OKADA AND STUART MCDONALD.
*
* IF THIS CODE IS ROMMED, tFPPriv TRAP ($A097) SHOULD BE ROMMED, TOO! THEN WE
* WON'T BE CONTINUALLY INSTALLING IT ON THE FLY. A/UX & VM PEOPLE, ARE YOU LISTENING???
* THIS ISOLATION OF PRIVILEGED INSTRUCTIONS TO A SINGLE TRAP WAS FOR YOUR BENEFIT.
* WHY, AS OF THE MAC IICI, HAS NO ONE BURNT tFPPriv TRAP INTO ROM? INSTALLING IT
* ON THE FLY IS SURELY A NO-NO IN THE A/UX WORLD AND I BET THE A/UX FOLKS AREN'T
* OVERRIDDING IT... HOW COULD THEY IF INSTALLING IT IS A NO-NO?
*
******************************************************************************************
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; privileged instruction trap
;; This routine calls trap code containing privileged instructions. If the trap
;; has not been installed it installs it. The purpose of this routine is to provide
;; compatability with future architectures which will not allow user-mode library
;; code to execute privileged instructions. TO BE ADDED: FSAVE/FRESTORE ENTRIES?
;;
;; Trap conventions:
;; Registers D1,D2,A0,A1,A2 are restored to their pre-call values after the
;; trap call. Registers D0,A0,A1 are visible to the trap code and provide the
;; mechanism for input values to the trap code. D0 is the only register that
;; can be changed by the trap code (after return to the caller). TST.W D0 is
;; the last instruction before return to the program calling the trap.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 888888888888 888888888888 1111
; 88 88 88 88 11 11
; 88 88 88 88 11 11
; 88 88 88 88 11
; 888888888888 888888888888 11
; 88 88 88 88 11
; 88 88 88 88 11
; 88 88 88 88 11
; 888888888888 888888888888 1111111111
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ALIGN 16 ; align on nearest cache line boundary <T3>
PrivTrap881
CMP.W #0,D0
BEQ.S SetExcept881 ; Set the exceptions contained in A0 <T3>
CMP.W #1,D0
BEQ.S GetTrapVec881 ; GetTrapVector code <T3>
CMP.W #2,D0
BEQ.S SetTrapVec881 ; SetTrapVector code <T3>
_SysBreak ; Error in selector code
SkipMarkRel dc.w SkipMark-QADDX ; offset to SkipMark from QADDX <9/30/90-S.McD.>
SetExcept881 ; <T3>
FNOP ; Ensure 881 is idle
MOVE.L A0,D1 ; Copy exceptions into D1
FSAVE -(SP) ; Save 881 environment
FMOVE.L FPSR,D0 ; D0 <- FPSR
AND.W #$00FF,D0 ; Clear previous op flags <5/12/90-S.McD.>
OR.W D1,D0 ; Set proper exceptions
FMOVE.L D0,FPSR ; Move results back to FPSR
FMOVE.L FPCR,D0 ; D0 <- FPCR
AND.W D1,D0 ; Find exception intersection
ANDI.L #$FF00,D0 ; Mask off low byte and high word
BEQ.S SkipMark ; If no intersection, then don't
; mark exception pending bit
*
* LEA SkipMark,A0 ; A0 := @FRESTORE <8/31/90-S.McD.>
* FMOVEM.L A0,FPIAR ; FPIAR := A0 <8/31/90-S.McD.>
*
* Alas, once tFPPriv trap has installed itself, SkipMark is no longer in PACK4!
* Since we want FPIAR to always point to something inside PACK4, we must be more
* careful how we set it up. Here's how using QADDX's JMP island at $0B6C:
*
MOVEA.L $0B6E,A0 ; A0 := &QADDX <9/30/90-S.McD.>
ADDA.W SkipMarkRel,A0 ; A0 := &SkipMark in PACK4 <9/30/90-S.McD.>
FMOVEM.L A0,FPIAR ; FPIAR := A0 <12/12/90-S.McD.> <T7>
CLR.L D0
MOVE.B 1(SP),D0 ; Load state frame size
BCLR #3,(SP,D0) ; Clear bit 27 of BIU
SkipMark
FRESTORE (SP)+ ; Restore 881 environment
RTS
GetTrapVec881 ; <T3>
MOVE.L #$0C0,A1 ; A1 <- &Unordered vector in table
MOVE.L (A1)+,(A0)+ ; Traps.Unordered <- &Unordered vector
MOVE.L (A1)+,(A0)+ ; Traps.Inexact <- &Inexact vector
MOVE.L (A1)+,(A0)+ ; Traps.DivByZero <- &DivByZero vector
MOVE.L (A1)+,(A0)+ ; Traps.Underflow <- &Underflow vector
MOVE.L (A1)+,(A0)+ ; Traps.OpError <- &OpError vector
MOVE.L (A1)+,(A0)+ ; Traps.Overflow <- &Overflow vector
MOVE.L (A1)+,(A0)+ ; Traps.SigNaN <- &SigNaN vector
RTS
SetTrapVec881 ; <T3>
MOVE.L #$0C0,A1 ; A1 <- &Unordered vector in table
MOVE.L (A0)+,(A1)+ ; &Unordered vector <- Traps.Unordered
MOVE.L (A0)+,(A1)+ ; &Inexact vector <- Traps.Inexact
MOVE.L (A0)+,(A1)+ ; &DivByZero vector <- Traps.DivByZero
MOVE.L (A0)+,(A1)+ ; &Underflow vector <- Traps.Underflow
MOVE.L (A0)+,(A1)+ ; &OpError vector <- Traps.OpError
MOVE.L (A0)+,(A1)+ ; &Overflow vector <- Traps.Overflow
MOVE.L (A0)+,(A1)+ ; &SigNaN vector <- Traps.SigNaN
RTS
EndPt881 EQU * ; <T6>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; <T3> thru next <T3>
; 000000000000 444444 000000000000
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 44 44 00 00
; 00 00 444444444444444 00 00
; 00 00 44 00 00
; 00 00 44 00 00
; 000000000000 44 000000000000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FPBSUN_VEC040 EQU $1FCC ; special FP exception vector addresses <12/03/90, JPO>
FPUNFL_VEC040 EQU $1FD0
FPOPERR_VEC040 EQU $1FD4
FPOVFL_VEC040 EQU $1FD8
FPSNAN_VEC040 EQU $1FDC
ALIGN 16 ; align on nearest cache line boundary
PrivTrap040
CMP.W #0,D0
BEQ.S SetExcept040 ; Set the exceptions contained in A0
CMP.W #1,D0
BEQ.S GetTrapVec040 ; GetTrapVector code
CMP.W #2,D0
BEQ.S SetTrapVec040 ; SetTrapVector code
_SysBreak ; Error in selector code
GetTrapVec040 ; 040-style
MOVE.L #$0C4,A1 ; A1 <- &Inexact vector in table
MOVE.L (FPBSUN_VEC040).W,(A0)+ ; Traps.Unordered <- &Unordered vector
MOVE.L (A1)+,(A0)+ ; Traps.Inexact <- &Inexact vector
MOVE.L (A1),(A0)+ ; Traps.DivByZero <- &DivByZero vector
MOVE.L (FPUNFL_VEC040).W,(A0)+ ; Traps.Underflow <- &Underflow vector
MOVE.L (FPOPERR_VEC040).W,(A0)+; Traps.OpError <- &OpError vector
MOVE.L (FPOVFL_VEC040).W,(A0)+ ; Traps.Overflow <- &Overflow vector
MOVE.L (FPSNAN_VEC040).W,(A0)+ ; Traps.SigNaN <- &SigNaN vector
RTS
SetTrapVec040
MOVE.L #$0C4,A1 ; A1 <- &Inexact vector in table
MOVE.L (A0)+,(FPBSUN_VEC040).W ; &Unordered vector <- Traps.Unordered
MOVE.L (A0)+,(A1)+ ; &Inexact vector <- Traps.Inexact
MOVE.L (A0)+,(A1) ; &DivByZero vector <- Traps.DivByZero
MOVE.L (A0)+,(FPUNFL_VEC040).W ; &Underflow vector <- Traps.Underflow
MOVE.L (A0)+,(FPOPERR_VEC040).W; &OpError vector <- Traps.OpError
MOVE.L (A0)+,(FPOVFL_VEC040).W ; &Overflow vector <- Traps.Overflow
MOVE.L (A0)+,(FPSNAN_VEC040).W ; &SigNaN vector <- Traps.SigNaN
RTS
SetExcept040
FNOP ; Ensure the 040 FP is idle
MOVE.L A0,D1 ; Copy exceptions into D1
FMOVE.L FPSR,D0 ; D0 <- FPSR
AND.W #$00FF,D0 ; Clear previous op flags <5/12/90-S.McD.>
OR.W D1,D0 ; Set proper exceptions
FMOVE.L D0,FPSR ; Move results back to FPSR
FMOVE.L FPCR,D0 ; D0 <- FPCR
AND.W D0,D1 ; Find exception intersection
ANDI.L #$FF00,D1 ; Mask off low byte and high word
BNE.S @1 ; Force vectoring to highest priority exception handler
RTS ; Return if none enabled
@1:
BTST #15,D1 ; BSUN handler?
BEQ.S @2 ; No
FMOVE.S #"$7FFFFFFF",FP1 ; Yes; set NaN condition code
FBGT.W @done ; BSUN set on unordered branch condition
FNOP
RTS
@2:
BTST #14,D1 ; SNaN?
BEQ.S @3 ; No
FCMP.S #"$7FBFFFFF",FP1 ; Yes; compare FP1 with signaling NaN
BRA.S @done
@3:
BTST #13,D1 ; Operror?
BEQ.S @4 ; No
FMOVE.S #"$7F800000",FP1 ; Yes; do INF - INF
FSUB.X FP1,FP1
BRA.S @done
@4:
BTST #12,D1 ; Overflow?
BEQ.S @5 ; No
FMOVE.S #"$7F000000",FP1 ; Yes; load large single-precision value
FSMUL.X FP1,FP1 ; and square it
@done:
FNOP ; Flush pending exceptions
RTS ; Return
@5:
BTST #11,D1 ; Underflow?
BEQ.S @6 ; No
FMOVE.S #"$1F000000",FP1 ; Yes; load small single-precision value
FSMUL.X FP1,FP1 ; and square it (result is subnormal/exact)
BRA.S @done
@6:
BTST #10,D1 ; Divide-by-zero?
BEQ.S @7 ; No. Inexact
FMOVE.B #1,FP1 ; Yes; divide 1.0 by 0.0
FDIV.B #0,FP1
BRA.S @done
@7:
FMOVE.B #1,FP1 ; 040 can trap only on INEX2 condition
FADD.S #"$00800000",FP1 ; add 1.0 to 2.0**-126
BRA.S @done
EndPT040
ENDIF ; {NOT forROM}
; ------------------------------------------------------------------------------------
;
; Check if the _FPPriv trap is installed and EXECUTE it, one way or another.
;
; If it is installed, execute it.
; If not, install it, THEN execute it.
;
; ------------------------------------------------------------------------------------
PrivTrap%
; Check if the privileged instruction trap is installed
IF NOT forROM THEN ; the code lives in PrivTrap.a in ROM
MOVEM.L D0/D1/A0/A1,-(SP) ; Save registers
MOVE.W #tFPPriv,D0 ; is _FPPriv implemented?
_GetTrapAddress ,NEWOS
MOVE.L A0,A1 ; Save off address
MOVE.W #tUnimplemented,D0
_GetTrapAddress ,NEWOS
CMPA.L A0,A1
BNE.S @SkipInstall ; If A0<>A1 then trap is implemented, branch out
; Trap is not installed, install privileged instruction trap
cmp.b #cpu68040,CPUFlag ; are we on an 040 or 050
blt.s @881PrivSize ; IF CPU >= 040 THEN
lea PrivTrap040,a1 ; A1 <- address of trap code
move.l #EndPT040-PrivTrap040,D0; D0 <- size of trap code
bra.s @createOnSysHeap ; ELSE
@881PrivSize
lea PrivTrap881,a1 ; A1 <- address of trap code
move.l #EndPT881-PrivTrap881,D0; D0 <- size of trap code
@createOnSysHeap ; ENDIF
move.l d0,d1 ; save "size of trap code" for later _BlockMove
_NewPtr ,SYS ; Get a block from the system heap
BMI.S @Error ; Check for error
exg a0,a1 ; A0 <- address of trap code; A1 -< address of heap block
move.l d1,d0 ; D0 <- size of trap code
_BlockMove ; Move copy of code into system heap
MOVE.L A1,A0 ; A0 <- address of trap code in system heap
MOVE.W #tFPPriv,D0
_SetTrapAddress ,NEWOS ; Install new trap
@SkipInstall
MOVEM.L (SP)+,D0/D1/A0/A1 ; Restore registers
ENDIF ; { NOT forROM }
_FPPriv ; privileged instruction trap
RTS
IF NOT forROM THEN ; ... continued from above
@Error _SysBreak ; Crash and burn in a Big Way
RTS ; return to caller?
ENDIF ; { NOT forROM }