mac-rom/OS/FPUEmulation/XUnfl.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
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.
2017-12-26 09:52:23 +08:00

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