mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 20:49:19 +00:00
2077 lines
83 KiB
Plaintext
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 := © 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 }
|