mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +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.
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
|
|
|
|
|