mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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 }
|