; ; File: FPSPMain.a ; ; Contains: Main entry point for the FPU Emulation Package ; ; Originally Written by: Motorola Inc. ; Adapted to Apple/MPW: Jon Okada ; ; Copyright: © 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 ;