mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-22 04:31:30 +00:00
297 lines
7.7 KiB
Plaintext
297 lines
7.7 KiB
Plaintext
|
;
|
||
|
; File: XUnfl.a
|
||
|
;
|
||
|
; Contains: Routines to handle the FP UnderFlow exception
|
||
|
;
|
||
|
; 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.
|
||
|
|
||
|
; xunfl.a
|
||
|
|
||
|
; Based upon Motorola file 'x_unfl.sa'.
|
||
|
|
||
|
; CHANGE LOG:
|
||
|
; 09 Jan 91 JPO Inserted label "unfl" at start of code. Deleted
|
||
|
; unreferenced labels "take_inex" and "opc011".
|
||
|
; Modified branching to user handlers for UNFL
|
||
|
; and INEX. Changed "bra fpsp_done" to "rte".
|
||
|
; 20 Mar 91 JPO Fixed bug for underflow FMOVE out to double or single
|
||
|
; where rounding produces a normal result.
|
||
|
;
|
||
|
|
||
|
*
|
||
|
* x_unfl.sa 3.1 12/10/90
|
||
|
*
|
||
|
* fpsp_unfl --- FPSP handler for underflow exception
|
||
|
*
|
||
|
* Trap disabled results
|
||
|
* For 881/2 compatibility, sw must denormalize the intermediate
|
||
|
* result, then store the result. Denormalization is accomplished
|
||
|
* by taking the intermediate result (which is always normalized) and
|
||
|
* shifting the mantissa right while incrementing the exponent until
|
||
|
* it is equal to the denormalized exponent for the destination
|
||
|
* format. After denormalizatoin, the result is rounded to the
|
||
|
* destination format.
|
||
|
*
|
||
|
* Trap enabled results
|
||
|
* All trap disabled code applies. In addition the exceptional
|
||
|
* operand needs to made available to the user with a bias of $6000
|
||
|
* added to the exponent.
|
||
|
*
|
||
|
|
||
|
* 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.
|
||
|
|
||
|
|
||
|
|
||
|
unfl: ; label inserted <1/9/91, JPO>
|
||
|
fpsp_unfl:
|
||
|
link a6,#-LOCAL_SIZE
|
||
|
fsave -(a7)
|
||
|
movem.l d0-d1/a0-a1,USER_DA(a6)
|
||
|
fmovem.x fp0-fp3,USER_FP0(a6)
|
||
|
fmovem.l fpcr/fpsr/fpiar,USER_FPCR(a6)
|
||
|
*
|
||
|
bsr unf_res ;denormalize, round & store interm op
|
||
|
*
|
||
|
* If underflow exceptions are not enabled, check for inexact
|
||
|
* exception
|
||
|
*
|
||
|
btst.b #unfl_bit,FPCR_ENABLE(a6)
|
||
|
beq.b ck_inex
|
||
|
|
||
|
btst.b #E3,E_BYTE(a6)
|
||
|
beq.b no_e3_1
|
||
|
*
|
||
|
* Clear dirty bit on dest register in the frame before branching
|
||
|
* to b1238_fix.
|
||
|
*
|
||
|
bfextu CMDREG3B(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
|
||
|
move.l USER_FPSR(a6),FPSR_SHADOW(a6)
|
||
|
or.l #sx_mask,E_BYTE(a6)
|
||
|
no_e3_1:
|
||
|
movem.l USER_DA(a6),d0-d1/a0-a1
|
||
|
fmovem.x USER_FP0(a6),fp0-fp3
|
||
|
fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
|
||
|
frestore (a7)+
|
||
|
unlk a6
|
||
|
; bra.l real_unfl ; DELETED <1/9/91, JPO>
|
||
|
|
||
|
move.l (FPUNFL_VEC040).W,-(sp) ; push vector to user UNFL handler <1/9/91, JPO>
|
||
|
rts ; execute user handler <1/9/91, JPO>
|
||
|
*
|
||
|
* It is possible to have either inex2 or inex1 exceptions with the
|
||
|
* unfl. If the inex enable bit is set in the FPCR, and either
|
||
|
* inex2 or inex1 occured, we must clean up and branch to the
|
||
|
* real inex handler.
|
||
|
*
|
||
|
ck_inex:
|
||
|
move.b FPCR_ENABLE(a6),d0
|
||
|
and.b FPSR_EXCEPT(a6),d0
|
||
|
andi.b #$3,d0
|
||
|
beq.b unfl_done
|
||
|
|
||
|
*
|
||
|
* Inexact enabled and reported, and we must take an inexact exception
|
||
|
*
|
||
|
;take_inex: ; label DELETED <1/9/91, JPO>
|
||
|
btst.b #E3,E_BYTE(a6)
|
||
|
beq.b no_e3_2
|
||
|
*
|
||
|
* Clear dirty bit on dest register in the frame before branching
|
||
|
* to b1238_fix.
|
||
|
*
|
||
|
bfextu CMDREG3B(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
|
||
|
move.l USER_FPSR(a6),FPSR_SHADOW(a6)
|
||
|
or.l #sx_mask,E_BYTE(a6)
|
||
|
no_e3_2:
|
||
|
move.b #INEX_VEC,EXC_VEC+1(a6)
|
||
|
movem.l USER_DA(a6),d0-d1/a0-a1
|
||
|
fmovem.x USER_FP0(a6),fp0-fp3
|
||
|
fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
|
||
|
frestore (a7)+
|
||
|
unlk a6
|
||
|
; bra.l real_inex ; DELETED <1/9/91, JPO>
|
||
|
|
||
|
move.l ($00C4).W,-(sp) ; push vector to user INEX handler <1/9/91, JPO>
|
||
|
rts ; execute user handler <1/9/91, JPO>
|
||
|
|
||
|
unfl_done:
|
||
|
bclr.b #E3,E_BYTE(a6)
|
||
|
beq.b e1_set ;if set then branch
|
||
|
*
|
||
|
* Clear dirty bit on dest resister in the frame before branching
|
||
|
* to b1238_fix.
|
||
|
*
|
||
|
bfextu CMDREG3B(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
|
||
|
move.l USER_FPSR(a6),FPSR_SHADOW(a6)
|
||
|
or.l #sx_mask,E_BYTE(a6)
|
||
|
movem.l USER_DA(a6),d0-d1/a0-a1
|
||
|
fmovem.x USER_FP0(a6),fp0-fp3
|
||
|
fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
|
||
|
frestore (a7)+
|
||
|
unlk a6
|
||
|
|
||
|
; bra.l fpsp_done ; DELETED <1/9/91, JPO>
|
||
|
|
||
|
rte ; <1/9/91, JPO>
|
||
|
|
||
|
e1_set:
|
||
|
movem.l USER_DA(a6),d0-d1/a0-a1
|
||
|
fmovem.x USER_FP0(a6),fp0-fp3
|
||
|
fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
|
||
|
unlk a6
|
||
|
|
||
|
; bra.l fpsp_done ; DELETED <1/9/91, JPO>
|
||
|
|
||
|
rte ; <1/9/91, JPO>
|
||
|
|
||
|
*
|
||
|
* unf_res --- underflow result calculation
|
||
|
*
|
||
|
unf_res:
|
||
|
bsr g_rndpr ;returns RND_PREC in d0 0=ext,
|
||
|
* ;1=sgl, 2=dbl
|
||
|
* ;we need the RND_PREC in the
|
||
|
* ;upper word for round
|
||
|
move.w #0,-(a7)
|
||
|
move.w d0,-(a7) ;copy RND_PREC to stack
|
||
|
*
|
||
|
*
|
||
|
* If the exception bit set is E3, the exceptional operand from the
|
||
|
* fpu is in WBTEMP; else it is in FPTEMP.
|
||
|
*
|
||
|
btst.b #E3,E_BYTE(a6)
|
||
|
beq.b unf_E1
|
||
|
unf_E3:
|
||
|
lea WBTEMP(a6),a0 ;a0 now points to operand
|
||
|
*
|
||
|
* Test for fsgldiv and fsglmul. If the inst was one of these, then
|
||
|
* force the precision to extended for the denorm routine. Use
|
||
|
* the user's precision for the round routine.
|
||
|
*
|
||
|
move.w CMDREG3B(a6),d1 ;check for fsgldiv or fsglmul
|
||
|
andi.w #$7f,d1
|
||
|
cmpi.w #$30,d1 ;check for sgldiv
|
||
|
beq.b unf_sgl
|
||
|
cmpi.w #$33,d1 ;check for sglmul
|
||
|
bne.b unf_cont ;if not, use fpcr prec in round
|
||
|
unf_sgl:
|
||
|
clr.l d0
|
||
|
move.w #$1,(a7) ;override g_rndpr precision
|
||
|
* ;force single
|
||
|
bra.b unf_cont
|
||
|
unf_E1:
|
||
|
lea FPTEMP(a6),a0 ;a0 now points to operand
|
||
|
unf_cont:
|
||
|
bclr.b #sign_bit,LOCAL_EX(a0) ;clear sign bit
|
||
|
sne LOCAL_SGN(a0) ;store sign
|
||
|
|
||
|
bsr denorm ;returns denorm, a0 points to it
|
||
|
*
|
||
|
* WARNING:
|
||
|
* ;d0 has guard,round sticky bit
|
||
|
* ;make sure that it is not corrupted
|
||
|
* ;before it reaches the round subroutine
|
||
|
* ;also ensure that a0 isn't corrupted
|
||
|
|
||
|
*
|
||
|
* Set up d1 for round subroutine d1 contains the PREC/MODE
|
||
|
* information respectively on upper/lower register halves.
|
||
|
*
|
||
|
bfextu FPCR_MODE(a6){2:2},d1 ;get mode from FPCR
|
||
|
* ;mode in lower d1
|
||
|
add.l (a7)+,d1 ;merge PREC/MODE
|
||
|
*
|
||
|
* WARNING: a0 and d0 are assumed to be intact between the denorm and
|
||
|
* round subroutines. All code between these two subroutines
|
||
|
* must not corrupt a0 and d0.
|
||
|
*
|
||
|
*
|
||
|
* Perform Round
|
||
|
* Input: a0 points to input operand
|
||
|
* d0{31:29} has guard, round, sticky
|
||
|
* d1{01:00} has rounding mode
|
||
|
* d1{17:16} has rounding precision
|
||
|
* Output: a0 points to rounded operand
|
||
|
*
|
||
|
|
||
|
bsr round ;returns rounded denorm at (a0)
|
||
|
*
|
||
|
* Differentiate between store to memory vs. store to register
|
||
|
*
|
||
|
unf_store:
|
||
|
bsr g_opcls ;returns opclass in d0{2:0}
|
||
|
cmpi.b #$3,d0
|
||
|
bne.b not_opc011
|
||
|
*
|
||
|
* At this point, a store to memory is pending
|
||
|
*
|
||
|
;opc011: ; label DELETED <1/9/91, JPO>
|
||
|
bsr g_dfmtou
|
||
|
tst.b d0
|
||
|
beq.b ext_opc011 ;If extended, do not subtract
|
||
|
* ;If destination format is sgl/dbl,
|
||
|
tst.b LOCAL_HI(a0) ; If round yielded normal, don't subtract <3/20/91, JPO>
|
||
|
bmi.b ext_opc011 ; <3/20/91, JPO>
|
||
|
subq.w #1,LOCAL_EX(a0) ;account for denorm bias vs.
|
||
|
* ;normalized bias
|
||
|
* ; normalized denormalized
|
||
|
* ;single $7f $7e
|
||
|
* ;double $3ff $3fe
|
||
|
*
|
||
|
ext_opc011:
|
||
|
bsr store ;stores to memory
|
||
|
bra.b unf_done ;finish up
|
||
|
|
||
|
*
|
||
|
* At this point, a store to a float register is pending
|
||
|
*
|
||
|
not_opc011:
|
||
|
bsr store ;stores to float register
|
||
|
* ;a0 is not corrupted on a store to a
|
||
|
* ;float register.
|
||
|
*
|
||
|
* Set the condition codes according to result
|
||
|
*
|
||
|
tst.l LOCAL_HI(a0) ;check upper mantissa
|
||
|
bne.b ck_sgn
|
||
|
tst.l LOCAL_LO(a0) ;check lower mantissa
|
||
|
bne.b ck_sgn
|
||
|
bset.b #z_bit,FPSR_CC(a6) ;set condition codes if zero
|
||
|
ck_sgn:
|
||
|
btst.b #sign_bit,LOCAL_EX(a0) ;check the sign bit
|
||
|
beq.b unf_done
|
||
|
bset.b #neg_bit,FPSR_CC(a6)
|
||
|
|
||
|
*
|
||
|
* Finish.
|
||
|
*
|
||
|
unf_done:
|
||
|
btst.b #inex2_bit,FPSR_EXCEPT(a6)
|
||
|
beq.b no_aunfl
|
||
|
bset.b #aunfl_bit,FPSR_AEXCEPT(a6)
|
||
|
no_aunfl:
|
||
|
rts
|
||
|
|
||
|
|