mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
486 lines
12 KiB
Plaintext
486 lines
12 KiB
Plaintext
|
;
|
|||
|
; File: FPSPMain.a
|
|||
|
;
|
|||
|
; Contains: Main entry point for the FPU Emulation Package
|
|||
|
;
|
|||
|
; Originally Written by: Motorola Inc.
|
|||
|
; Adapted to Apple/MPW: Jon Okada
|
|||
|
;
|
|||
|
; Copyright: <09> 1990, 1991 by Apple Computer, Inc., all rights reserved.
|
|||
|
;
|
|||
|
; This file is used in these builds: Mac32
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <2> 3/30/91 BG Rolling in Jon Okada's latest changes.
|
|||
|
; <1> 12/14/90 BG First checked into TERROR/BBS.
|
|||
|
|
|||
|
;
|
|||
|
|
|||
|
; fpspmain.a
|
|||
|
|
|||
|
; Based upon Motorola file 'skeleton.sa'.
|
|||
|
|
|||
|
; Main entry points to FPSP functionality: ovfl, unfl, snan, operr, bsun, fline,
|
|||
|
; and unsupp.
|
|||
|
|
|||
|
; CHANGE LOG:
|
|||
|
; 03 Jan 91 JPO Removed branches to emulator routines and moved entry point
|
|||
|
; labels to appropriate emulator routines. Removed dummy
|
|||
|
; user exception routines 'real_XXX'. Removed routine
|
|||
|
; 'fpsp_done' (RTE done in-line). Modified and flattened
|
|||
|
; structure of 'mem_write' function. Removed 'mem_read'
|
|||
|
; routine (to be done in-line).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
*
|
|||
|
* skeleton.sa 3.1 12/10/90
|
|||
|
*
|
|||
|
* This file contains code that is system dependent and will
|
|||
|
* need to be modified to install the FPSP.
|
|||
|
*
|
|||
|
* Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'.
|
|||
|
* Put any target system specific handling that must be done immediately
|
|||
|
* before the jump instruction. If there no handling necessary, then
|
|||
|
* the 'fpsp_xxxx' handler entry point should be placed in the exception
|
|||
|
* table so that the 'jmp' can be eliminated. If the FPSP determines that the
|
|||
|
* exception is one that must be reported then there will be a
|
|||
|
* return from the package by a 'jmp real_xxxx'. At that point
|
|||
|
* the machine state will be identical to the state before
|
|||
|
* the FPSP was entered. In particular, whatever condition
|
|||
|
* that caused the exception will still be pending when the FPSP
|
|||
|
* package returns. Thus, there will be system specific code
|
|||
|
* to handle the exception.
|
|||
|
*
|
|||
|
* If the exception was completely handled by the package, then
|
|||
|
* the return will be via a 'jmp fpsp_done'. Unless there is
|
|||
|
* OS specific work to be done (such as handling a context switch or
|
|||
|
* interrupt) the user program can be resumed via 'rte'.
|
|||
|
*
|
|||
|
* In the following skeleton code, some typical 'real_xxxx' handling
|
|||
|
* code is shown. This code may need to be moved to an appropriate
|
|||
|
* place in the target system, or rewritten.
|
|||
|
*
|
|||
|
|
|||
|
* Copyright (C) Motorola, Inc. 1990
|
|||
|
* All Rights Reserved
|
|||
|
*
|
|||
|
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
|
|||
|
* The copyright notice above does not evidence any
|
|||
|
* actual or intended publication of such source code.
|
|||
|
|
|||
|
* SKELETON IDNT 2,1 Motorola 040 Floating Point Software Package
|
|||
|
|
|||
|
; section 15
|
|||
|
*
|
|||
|
* The following counters are used for standalone testing - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
;sigunimp dc.l 0
|
|||
|
;sigbsun dc.l 0
|
|||
|
;siginex dc.l 0
|
|||
|
;sigdz dc.l 0
|
|||
|
;sigunfl dc.l 0
|
|||
|
;sigovfl dc.l 0
|
|||
|
;sigoperr dc.l 0
|
|||
|
;sigsnan dc.l 0
|
|||
|
;sigunsupp dc.l 0
|
|||
|
|
|||
|
; section 8
|
|||
|
|
|||
|
; include fpsp.h
|
|||
|
|
|||
|
*
|
|||
|
* Divide by Zero exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* All dz exceptions are 'real', hence no fpsp_dz entry point.
|
|||
|
*
|
|||
|
|
|||
|
;dz:
|
|||
|
;real_dz:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E1,E_BYTE(a6)
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
;
|
|||
|
; add.l #1,sigdz ;for standalone testing
|
|||
|
;
|
|||
|
; rte
|
|||
|
|
|||
|
|
|||
|
*
|
|||
|
* Inexact exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* All inexact exceptions are real, but the 'real' handler
|
|||
|
* will probably want to clear the pending exception.
|
|||
|
* The provided code will clear the E3 exception (if pending),
|
|||
|
* otherwise clear the E1 exception. The frestore is not really
|
|||
|
* necessary for E1 exceptions.
|
|||
|
*
|
|||
|
* Code following the 'inex' label is to handle bug #1232. In this
|
|||
|
* bug, if an E1 snan, ovfl, or unfl occured, and the process was
|
|||
|
* swapped out before taking the exception, the exception taken on
|
|||
|
* return was inex, rather than the correct exception. The snan, ovfl,
|
|||
|
* and unfl exception to be taken must not have been enabled. The
|
|||
|
* fix is to check for E1, and the existence of one of snan, ovfl,
|
|||
|
* or unfl bits set in the fpsr. If any of these are set, branch
|
|||
|
* to the appropriate handler for the exception in the fpsr. Note
|
|||
|
* that this fix is only for d43b parts, and is skipped if the
|
|||
|
* version number is not $40.
|
|||
|
*
|
|||
|
*
|
|||
|
|
|||
|
;inex:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; cmpi.b #VER_40,(sp) ;test version number
|
|||
|
; bne.b real_inex
|
|||
|
; fmove.l fpsr,-(sp)
|
|||
|
; btst.b #E1,E_BYTE(a6) ;test for E1 set
|
|||
|
; beq.b not_b1232
|
|||
|
; btst.b #snan_bit,2(sp) ;test for snan
|
|||
|
; beq inex_ckofl
|
|||
|
; add.l #4,sp
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; bra snan
|
|||
|
;inex_ckofl:
|
|||
|
; btst.b #ovfl_bit,2(sp) ;test for ovfl
|
|||
|
; beq inex_ckufl
|
|||
|
; add.l #4,sp
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; bra ovfl
|
|||
|
;inex_ckufl:
|
|||
|
; btst.b #unfl_bit,2(sp) ;test for unfl
|
|||
|
; beq not_b1232
|
|||
|
; add.l #4,sp
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; bra unfl
|
|||
|
|
|||
|
*
|
|||
|
* We do not have the bug 1232 case. Clean up the stack and call
|
|||
|
* real_inex.
|
|||
|
*
|
|||
|
;not_b1232:
|
|||
|
; add.l #4,sp
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
|
|||
|
;real_inex:
|
|||
|
|
|||
|
; add.l #1,siginex ;for standalone testing
|
|||
|
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E3,E_BYTE(a6) ;clear and test E3 flag
|
|||
|
; beq.b inex_cke1
|
|||
|
*
|
|||
|
* Clear dirty bit on dest register in the frame before branching
|
|||
|
* to b1238_fix.
|
|||
|
*
|
|||
|
; movem.l d0/d1,USER_DA(a6)
|
|||
|
; bfextu CMDREG1B(a6){6:3},d0 ;get dest reg no
|
|||
|
; bclr.b d0,FPR_DIRTY_BITS(a6) ;clr dest dirty bit
|
|||
|
; bsr b1238_fix ;test for bug1238 case
|
|||
|
; movem.l USER_DA(a6),d0/d1
|
|||
|
; bra.b inex_done
|
|||
|
;inex_cke1:
|
|||
|
; bclr.b #E1,E_BYTE(a6)
|
|||
|
;inex_done:
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Overflow exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;ovfl:
|
|||
|
; jmp fpsp_ovfl
|
|||
|
;real_ovfl:
|
|||
|
|
|||
|
; add.l #1,sigovfl ;for standalone testing
|
|||
|
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E3,E_BYTE(a6) ;clear and test E3 flag
|
|||
|
; bne.b ovfl_done
|
|||
|
; bclr.b #E1,E_BYTE(a6)
|
|||
|
;ovfl_done:
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Underflow exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;unfl:
|
|||
|
; jmp fpsp_unfl
|
|||
|
;real_unfl:
|
|||
|
|
|||
|
; add.l #1,sigunfl ;for standalone testing
|
|||
|
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E3,E_BYTE(a6) ;clear and test E3 flag
|
|||
|
; bne.b unfl_done
|
|||
|
; bclr.b #E1,E_BYTE(a6)
|
|||
|
;unfl_done:
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Signalling NAN exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;snan:
|
|||
|
; jmp fpsp_snan
|
|||
|
;real_snan:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E1,E_BYTE(a6) ;snan is always an E1 exception
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
|
|||
|
; add.l #1,sigsnan ;for standalone testing
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Operand Error exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;operr:
|
|||
|
; jmp fpsp_operr
|
|||
|
;real_operr:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E1,E_BYTE(a6) ;operr is always an E1 exception
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
|
|||
|
; add.l #1,sigoperr ;for standalone testing
|
|||
|
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* BSUN exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* This sample handler simply clears the nan bit in the FPSR.
|
|||
|
*
|
|||
|
|
|||
|
;bsun:
|
|||
|
; jmp fpsp_bsun
|
|||
|
;real_bsun:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E1,E_BYTE(a6) ;bsun is always an E1 exception
|
|||
|
; fmove.l FPSR,-(sp)
|
|||
|
; bclr.b #nan_bit,(sp)
|
|||
|
; fmove.l (sp)+,FPSR
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
|
|||
|
; add.l #1,sigbsun ;for standalone testing
|
|||
|
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* F-line exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* A 'real' F-line exception is one that the FPSP isn't supposed to
|
|||
|
* handle. E.g. an instruction with a co-processor ID that is not 1.
|
|||
|
*
|
|||
|
*
|
|||
|
|
|||
|
;fline:
|
|||
|
; jmp fpsp_fline
|
|||
|
;real_fline:
|
|||
|
|
|||
|
; add.l #1,sigunimp ;for standalone testing
|
|||
|
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Unsupported data type exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;unsupp:
|
|||
|
; jmp fpsp_unsupp
|
|||
|
;real_unsupp:
|
|||
|
; link a6,#-LOCAL_SIZE
|
|||
|
; fsave -(sp)
|
|||
|
; bclr.b #E1,E_BYTE(a6) ;unsupp is always an E1 exception
|
|||
|
; frestore (sp)+
|
|||
|
; unlk a6
|
|||
|
|
|||
|
; add.l #1,sigunsupp ;for standalone testing
|
|||
|
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* Trace exception - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
|
|||
|
;real_trace:
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* fpsp_fmt_error --- exit point for frame format error
|
|||
|
*
|
|||
|
* The fpu stack frame does not match the frames existing
|
|||
|
* or planned at the time of this writing. The fpsp is
|
|||
|
* unable to handle frame sizes not in the following
|
|||
|
* version:size pairs:
|
|||
|
*
|
|||
|
* {4060, 4160} - busy frame
|
|||
|
* {4028, 4130} - unimp frame
|
|||
|
* {4000, 4100} - idle frame
|
|||
|
*
|
|||
|
* This entry point simply holds an f-line illegal value.
|
|||
|
* Replace this with a call to your kernel panic code or
|
|||
|
* code to handle future revisions of the fpu.
|
|||
|
*
|
|||
|
|
|||
|
fpsp_fmt_error:
|
|||
|
|
|||
|
dc.l $f27f0000 ;f-line illegal
|
|||
|
|
|||
|
*
|
|||
|
* fpsp_done --- FPSP exit point
|
|||
|
*
|
|||
|
* The exception has been handled by the package and we are ready
|
|||
|
* to return to user mode, but there may be OS specific code
|
|||
|
* to execute before we do. If there is, do it now.
|
|||
|
*
|
|||
|
*
|
|||
|
|
|||
|
;fpsp_done:
|
|||
|
; rte
|
|||
|
|
|||
|
*
|
|||
|
* mem_write --- write to user or supervisor address space - MODIFIED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* Writes to memory while in supervisor mode. copyout accomplishes
|
|||
|
* this via a 'moves' instruction. copyout is a UNIX SVR3 (and later) function.
|
|||
|
* If you don't have copyout, use the local copy of the function below.
|
|||
|
*
|
|||
|
* a0 - supervisor source address
|
|||
|
* a1 - user destination address
|
|||
|
* d0 - number of bytes to write (maximum count is 12)
|
|||
|
*
|
|||
|
* The supervisor source address is guaranteed to point into the supervisor
|
|||
|
* stack. The result is that a UNIX
|
|||
|
* process is allowed to sleep as a consequence of a page fault during
|
|||
|
* copyout. The probability of a page fault is exceedingly small because
|
|||
|
* the 68040 always reads the destination address and thus the page
|
|||
|
* faults should have already been handled.
|
|||
|
*
|
|||
|
* If the EXC_SR shows that the exception was from supervisor space,
|
|||
|
* then just do a dumb (and slow) memory move. In a UNIX environment
|
|||
|
* there shouldn't be any supervisor mode floating point exceptions.
|
|||
|
*
|
|||
|
|
|||
|
mem_write:
|
|||
|
; btst.b #5,EXC_SR(a6) ;check for supervisor state
|
|||
|
; beq.b user_write
|
|||
|
;super_write:
|
|||
|
;moreout:
|
|||
|
; move.b (a0)+,(a1)+
|
|||
|
; subq.l #1,d0
|
|||
|
; bne.b super_write
|
|||
|
|
|||
|
sub.l #1,d0 ; dec count by 1 for 'dbf' below <1/3/91, JPO>
|
|||
|
moreout: ; <1/3/91, JPO>
|
|||
|
move.b (a0)+,(a1)+ ; copy 1 byte <1/3/91, JPO>
|
|||
|
dbf d0,moreout ; loop until done <1/3/91, JPO>
|
|||
|
|
|||
|
rts
|
|||
|
|
|||
|
;user_write:
|
|||
|
; move.l d1,-(sp) ;preserve d1 just in case
|
|||
|
; move.l d0,-(sp)
|
|||
|
; move.l a1,-(sp)
|
|||
|
; move.l a0,-(sp)
|
|||
|
; jsr copyout
|
|||
|
; add.w #12,sp
|
|||
|
; move.l (sp)+,d1
|
|||
|
; rts
|
|||
|
*
|
|||
|
* mem_read --- read from user or supervisor address space - DELETED <1/3/91, JPO>
|
|||
|
*
|
|||
|
* Reads from memory while in supervisor mode. copyin accomplishes
|
|||
|
* this via a 'moves' instruction. copyin is a UNIX SVR3 (and later) function.
|
|||
|
* If you don't have copyin, use the local copy of the function below.
|
|||
|
*
|
|||
|
* The FPSP calls mem_read to read the original F-line instruction in order
|
|||
|
* to extract the data register number when the 'Dn' addressing mode is
|
|||
|
* used.
|
|||
|
*
|
|||
|
*Input:
|
|||
|
* a0 - user source address
|
|||
|
* a1 - supervisor destination address
|
|||
|
* d0 - number of bytes to read (maximum count is 12)
|
|||
|
*
|
|||
|
* Like mem_write, mem_read always reads with a supervisor
|
|||
|
* destination address on the supervisor stack. Also like mem_write,
|
|||
|
* the EXC_SR is checked and a simple memory copy is done if reading
|
|||
|
* from supervisor space is indicated.
|
|||
|
*
|
|||
|
|
|||
|
;mem_read:
|
|||
|
; btst.b #5,EXC_SR(a6) ;check for supervisor state
|
|||
|
; beq.b user_read
|
|||
|
;super_read:
|
|||
|
; move.b (a0)+,(a1)+
|
|||
|
; subq.l #1,d0
|
|||
|
; bne.b super_read
|
|||
|
; rts
|
|||
|
;user_read:
|
|||
|
; move.l d1,-(sp) ;preserve d1 just in case
|
|||
|
; move.l d0,-(sp)
|
|||
|
; move.l a1,-(sp)
|
|||
|
; move.l a0,-(sp)
|
|||
|
; jsr copyin
|
|||
|
; add.w #12,sp
|
|||
|
; move.l (sp)+,d1
|
|||
|
; rts
|
|||
|
|
|||
|
*
|
|||
|
* Use these routines if your kernel doesn't have copyout/copyin equivalents.
|
|||
|
* Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC,
|
|||
|
* and copyin overwrites SFC.
|
|||
|
*
|
|||
|
;copyout: ; DELETED <1/3/91, JPO>
|
|||
|
; move.l 4(sp),a0 ; source
|
|||
|
; move.l 8(sp),a1 ; destination
|
|||
|
; move.l 12(sp),d0 ; count
|
|||
|
; sub.l #1,d0 ; dec count by 1 for dbra
|
|||
|
; move.l #1,d1
|
|||
|
; movec d1,DFC ; set dfc for user data space
|
|||
|
;moreout:
|
|||
|
; move.b (a0)+,d1 ; fetch supervisor byte
|
|||
|
; moves.b d1,(a1)+ ; write user byte
|
|||
|
; dbf.w d0,moreout
|
|||
|
; rts
|
|||
|
;
|
|||
|
;copyin: ; DELETED <1/3/91, JPO>
|
|||
|
; move.l 4(sp),a0 ; source
|
|||
|
; move.l 8(sp),a1 ; destination
|
|||
|
; move.l 12(sp),d0 ; count
|
|||
|
; sub.l #1,d0 ; dec count by 1 for dbra
|
|||
|
; move.l #1,d1
|
|||
|
; movec d1,SFC ; set sfc for user space
|
|||
|
;morein:
|
|||
|
; moves.b (a0)+,d1 ; fetch user byte
|
|||
|
; move.b d1,(a1)+ ; write supervisor byte
|
|||
|
; dbf.w d0,morein
|
|||
|
; rts
|
|||
|
;
|
|||
|
|
|||
|
|