supermario/base/SuperMarioProj.1994-02-09/Toolbox/InSANE/FPHWNonArith.a
2019-06-29 23:17:50 +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 }