mac-rom/OS/FPUEmulation/Round.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

712 lines
20 KiB
Plaintext

;
; File: Round.a
;
; Contains: Rounding and normalization routines governed by rounding
; precision and direction
;
; 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):
;
; <3> 7/11/91 BG Fixed bug in "case_1" of "dnrm_lp" which could lead to loss of
; meaningful sticky bit prior to rounding.
; <1+> 6/24/91 BG Modified subroutine 'dnrm_lp' to use FP_SCR6 as scratch
; storage instead of FP_SCR2, whose address is in A0 when
; 'dnrm_lp' is called (via 'sintdo') by 'bindec'.
; <1> 3/30/91 BG First checked into TERROR/BBS.
;
; round.a
; Based upon Motorola file 'round.sa'.
; CHANGE LOG:
; 07 Jan 91 JPO Changed tables "mode_tab", "add_to_l", and "trunct"
; to contain 16-bit offsets relative to table tops.
; Renamed label "not_ext" to "den_notext". Deleted
; "error: rts" (not referenced).
; 04 Feb 91 JPO Modified subroutine 'dnrm_lp' to initialize G,R,S bits
; prior to shifting and to check for sticky bit resulting
; from shift out of original G,R,S [for E3 exceptions].
; fixed bug in evaluating proper G,R bits when shift
; is 65 bits.
; 25 Apr 91 JPO Modified subroutine 'dnrm_lp' to use FP_SCR6 as scratch
; storage instead of FP_SCR2, whose address is in A0 when
; 'dnrm_lp' is called (via 'sintdo') by 'bindec'.
; 10 Jul 91 JPO Fixed bug in "case_1" of "dnrm_lp" which could lead to
; loss of meaningful sticky bit prior to rounding.
;
*
* round.sa 3.1 12/10/90
*
* handle rounding and normalization tasks
*
*
*
* 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.
* ROUND IDNT 2,1 Motorola 040 Floating Point Software Package
*
* round --- round result according to precision/mode
*
* a0 points to the input operand in the internal extended format
* d1(high word) contains rounding precision:
* ext = $0000xxxx
* sgl = $0001xxxx
* dbl = $0002xxxx
* d1(low word) contains rounding mode:
* RN = $xxxx0000
* RZ = $xxxx0001
* RM = $xxxx0010
* RP = $xxxx0011
* d0{31:29} contains the g,r,s bits (extended)
*
* On return the value pointed to by a0 is correctly rounded,
* a0 is preserved and the g-r-s bits in d0 are cleared.
* The result is not typed - the tag field is invalid. The
* result is still in the internal extended format.
*
* The INEX bit of USER_FPSR will be set if the rounded result was
* inexact (i.e. if any of the g-r-s bits were set).
*
round:
* If g=r=s=0 then result is exact and round is done, else set
* the inex flag in status reg and continue.
*
bsr.b ext_grs ;this subroutine looks at the
* :rounding precision and sets
* ;the appropriate g-r-s bits.
tst.l d0 ;if grs are zero, go force
bne.b rnd_cont ;lower bits to zero for size
swap d1 ;set up d1.w for round prec.
bra.w truncate
rnd_cont:
*
* Use rounding mode as an index into a jump table for these modes.
*
or.l #inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
lea mode_tab,a1
; move.l (a1,d1.w*4),a1 ; deleted <1/7/91, JPO>
adda.w (a1,d1.w*2),a1 ; <1/7/91, JPO>
jmp (a1)
*
* Jump table indexed by rounding mode in d1.w. All following assumes
* grs != 0.
*
mode_tab: ; table modified <1/7/91, JPO>
dc.w rnd_near-mode_tab
dc.w rnd_zero-mode_tab
dc.w rnd_mnus-mode_tab
dc.w rnd_plus-mode_tab
*
* ROUND PLUS INFINITY
*
* If sign of fp number = 0 (positive), then add 1 to l.
*
rnd_plus:
swap d1 ;set up d1 for round prec.
tst.b LOCAL_SGN(a0) ;check for sign
bmi.w truncate ;if positive then truncate
move.l #$ffffffff,d0 ;force g,r,s to be all f's
lea add_to_l,a1
; move.l (a1,d1.w*4),a1 ; deleted <1/7/91, JPO>
adda.w (a1,d1.w*2),a1 ; <1/7/91, JPO>
jmp (a1)
*
* ROUND MINUS INFINITY
*
* If sign of fp number = 1 (negative), then add 1 to l.
*
rnd_mnus:
swap d1 ;set up d1 for round prec.
tst.b LOCAL_SGN(a0) ;check for sign
bpl.w truncate ;if negative then truncate
move.l #$ffffffff,d0 ;force g,r,s to be all f's
lea add_to_l,a1
; move.l (a1,d1.w*4),a1 ; deleted <1/7/91, JPO>
adda.w (a1,d1.w*2),a1 ; <1/7/91, JPO>
jmp (a1)
*
* ROUND ZERO
*
* Always truncate.
rnd_zero:
swap d1 ;set up d1 for round prec.
bra.w truncate
*
*
* ROUND NEAREST
*
* If (g=1), then add 1 to l and if (r=s=0), then clear l
* Note that this will round to even in case of a tie.
*
rnd_near:
swap d1 ;set up d1 for round prec.
asl.l #1,d0 ;shift g-bit to c-bit
bcc.w truncate ;if (g=1) then
lea add_to_l,a1
; move.l (a1,d1.w*4),a1 ; deleted <1/7/91, JPO>
adda.w (a1,d1.w*2),a1 ; <1/7/91, JPO>
jmp (a1)
*
* ext_grs --- extract guard, round and sticky bits
*
* Input: d1 = PREC:ROUND
* Output: d0{31:29}= guard, round, sticky
*
* The ext_grs extract the guard/round/sticky bits according to the
* selected rounding precision. It is called by the round subroutine
* only. All registers except d0 are kept intact. d0 becomes an
* updated guard,round,sticky in d0{31:29}
*
* Notes: the ext_grs uses the round PREC, and therefore has to swap d1
* prior to usage, and needs to restore d1 to original.
*
ext_grs:
swap d1 ;have d1.w point to round precision
cmpi.w #0,d1
bne.b sgl_or_dbl
bra.b end_ext_grs
sgl_or_dbl:
movem.l d2/d3,-(a7) ;make some temp registers
cmpi.w #1,d1
bne.b grs_dbl
grs_sgl:
bfextu LOCAL_HI(a0){24:2},d3 ;sgl prec. g-r are 2 bits right
move.l #30,d2 ;of the sgl prec. limits
lsl.l d2,d3 ;shift g-r bits to MSB of d3
move.l LOCAL_HI(a0),d2 ;get word 2 for s-bit test
andi.l #$0000003f,d2 ;s bit is the or of all other
bne.b st_stky ;bits to the right of g-r
tst.l LOCAL_LO(a0) ;test lower mantissa
bne.b st_stky ;if any are set, set sticky
tst.l d0 ;test original g,r,s
bne.b st_stky ;if any are set, set sticky
bra.b end_sd ;if words 3 and 4 are clr, exit
grs_dbl:
bfextu LOCAL_LO(a0){21:2},d3 ;dbl-prec. g-r are 2 bits right
move.l #30,d2 ;of the dbl prec. limits
lsl.l d2,d3 ;shift g-r bits to the MSB of d3
move.l LOCAL_LO(a0),d2 ;get lower mantissa for s-bit test
andi.l #$000001ff,d2 ;s bit is the or-ing of all
bne.b st_stky ;other bits to the right of g-r
tst.l d0 ;test word original g,r,s
bne.b st_stky ;if any are set, set sticky
bra.b end_sd ;if clear, exit
st_stky:
bset #rnd_stky_bit,d3
end_sd:
move.l d3,d0 ;return grs to d0
movem.l (a7)+,d2/d3 ;restore scratch registers
end_ext_grs:
swap d1 ;restore d1 to original
rts
******************** Local Equates
ad_1_sgl equ $00000100 constant to add 1 to l-bit in sgl prec
ad_1_dbl equ $00000800 constant to add 1 to l-bit in dbl prec
*Jump table for adding 1 to the l-bit indexed by rnd prec
add_to_l: ; table modified <1/7/91, JPO>
dc.w add_ext-add_to_l
dc.w add_sgl-add_to_l
dc.w add_dbl-add_to_l
dc.w add_dbl-add_to_l
*
* ADD SINGLE
*
add_sgl:
add.l #ad_1_sgl,LOCAL_HI(a0)
bcc.b scc_clr ;no mantissa overflow
roxr.w LOCAL_HI(a0) ;shift v-bit back in
roxr.w LOCAL_HI+2(a0) ;shift v-bit back in
add.w #$1,LOCAL_EX(a0) ;and incr exponent
scc_clr:
tst.l d0 ;test for rs = 0
bne.b sgl_done
andi.w #$fe00,LOCAL_HI+2(a0) ;clear the l-bit
sgl_done:
andi.l #$ffffff00,LOCAL_HI(a0) ;truncate bits beyond sgl limit
clr.l LOCAL_LO(a0) ;clear d2
rts
*
* ADD EXTENDED
*
add_ext:
addq.l #1,LOCAL_LO(a0) ;add 1 to l-bit
bcc.b xcc_clr ;test for carry out
addq.l #1,LOCAL_HI(a0) ;propogate carry
bcc.b xcc_clr
roxr.w LOCAL_HI(a0) ;mant is 0 so restore v-bit
roxr.w LOCAL_HI+2(a0) ;mant is 0 so restore v-bit
roxr.w LOCAL_LO(a0)
roxr.w LOCAL_LO+2(a0)
add.w #$1,LOCAL_EX(a0) ;and inc exp
xcc_clr:
tst.l d0 ;test rs = 0
bne.b add_ext_done
andi.b #$fe,LOCAL_LO+3(a0) ;clear the l bit
add_ext_done:
rts
*
* ADD DOUBLE
*
add_dbl:
add.l #ad_1_dbl,LOCAL_LO(a0)
bcc.b dcc_clr
addq.l #1,LOCAL_HI(a0) ;propogate carry
bcc.b dcc_clr
roxr.w LOCAL_HI(a0) ;mant is 0 so restore v-bit
roxr.w LOCAL_HI+2(a0) ;mant is 0 so restore v-bit
roxr.w LOCAL_LO(a0)
roxr.w LOCAL_LO+2(a0)
add.w #$1,LOCAL_EX(a0) ;incr exponent
dcc_clr:
tst.l d0 ;test for rs = 0
bne.b dbl_done
andi.w #$f000,LOCAL_LO+2(a0) ;clear the l-bit
dbl_done:
andi.l #$fffff800,LOCAL_LO(a0) ;truncate bits beyond dbl limit
rts
;error: ; deleted <1/7/91, JPO>
; rts ; deleted <1/7/91, JPO>
*
* Truncate all other bits
*
trunct: ; table modified <1/7/91, JPO>
dc.w end_rnd-trunct
dc.w sgl_done-trunct
dc.w dbl_done-trunct
dc.w dbl_done-trunct
truncate:
lea trunct,a1
; move.l (a1,d1.w*4),a1 ; deleted <1/7/91, JPO>
adda.w (a1,d1.w*2),a1 ; <1/7/91, JPO>
jmp (a1)
end_rnd:
rts
*
* NORMALIZE
*
* These routines (nrm_zero & nrm_set) normalize the unnorm. This
* is done by shifting the mantissa left while decrementing the
* exponent.
*
* NRM_SET shifts and decrements until there is a 1 set in the integer
* bit of the mantissa (msb in d1).
*
* NRM_ZERO shifts and decrements until there is a 1 set in the integer
* bit of the mantissa (msb in d1) unless this would mean the exponent
* would go less than 0. In that case the number becomes a denorm - the
* exponent (d0) is set to 0 and the mantissa (d1 & d2) is not
* normalized.
*
* Note that both routines have been optimized (for the worst case) and
* therefore do not have the easy to follow decrement/shift loop.
*
* NRM_ZERO
*
* Distance to first 1 bit in mantissa = X
* Distance to 0 from exponent = Y
* If X < Y
* Then
* nrm_set
* Else
* shift mantissa by Y
* set exponent = 0
*
*input:
* FP_SCR1 = exponent, ms mantissa part, ls mantissa part
*output:
* L_SCR1{4} = fpte15 or ete15 bit
*
nrm_zero:
move.w LOCAL_EX(a0),d0
cmp.w #64,d0 ;see if exp > 64
bmi.b d0_less
bsr.b nrm_set ;exp > 64 so exp won't exceed 0
rts
d0_less:
movem.l d2/d3/d5/d6,-(a7)
move.l LOCAL_HI(a0),d1
move.l LOCAL_LO(a0),d2
bfffo d1{0:32},d3 ;get the distance to the first 1
* ;in ms mant
beq.b ms_clr ;branch if no bits were set
cmp.w d3,d0 ;of X>Y
bmi.b greater ;then exp will go past 0 (neg) if
* ;it is just shifted
bsr.b nrm_set ;else exp won't go past 0
movem.l (a7)+,d2/d3/d5/d6
rts
greater:
move.l d2,d6 ;save ls mant in d6
lsl.l d0,d2 ;shift ls mant by count
lsl.l d0,d1 ;shift ms mant by count
move.l #32,d5
sub.l d0,d5 ;make op a denorm by shifting bits
lsr.l d5,d6 ;by the number in the exp, then
* ;set exp = 0.
or.l d6,d1 ;shift the ls mant bits into the ms mant
move.l #0,d0 ;same as if decremented exp to 0
* ;while shifting
move.w d0,LOCAL_EX(a0)
move.l d1,LOCAL_HI(a0)
move.l d2,LOCAL_LO(a0)
movem.l (a7)+,d2/d3/d5/d6
rts
ms_clr:
bfffo d2{0:32},d3 ;check if any bits set in ls mant
beq.b all_clr ;branch if none set
add.w #32,d3
cmp.w d3,d0 ;if X>Y
bmi.b greater ;then branch
bsr.b nrm_set ;else exp won't go past 0
movem.l (a7)+,d2/d3/d5/d6
rts
all_clr:
move.w #0,LOCAL_EX(a0) ;no mantissa bits set. Set exp = 0.
movem.l (a7)+,d2/d3/d5/d6
rts
*
* NRM_SET
*
nrm_set:
move.l d7,-(a7)
bfffo LOCAL_HI(a0){0:32},d7 ;find first 1 in ms mant to d7)
beq.b lower ;branch if ms mant is all 0's
move.l d6,-(a7)
sub.w d7,LOCAL_EX(a0) ;sub exponent by count
move.l LOCAL_HI(a0),d0 ;d0 has ms mant
move.l LOCAL_LO(a0),d1 ;d1 has ls mant
lsl.l d7,d0 ;shift first 1 to j bit position
move.l d1,d6 ;copy ls mant into d6
lsl.l d7,d6 ;shift ls mant by count
move.l d6,LOCAL_LO(a0) ;store ls mant into memory
moveq.l #32,d6
sub.l d7,d6 ;continue shift
lsr.l d6,d1 ;shift off all bits but those that will
* ;be shifted into ms mant
or.l d1,d0 ;shift the ls mant bits into the ms mant
move.l d0,LOCAL_HI(a0) ;store ms mant into memory
movem.l (a7)+,d7/d6 ;restore registers
rts
*
* We get here if ms mant was = 0, and we assume ls mant has bits
* set (otherwise this would have been tagged a zero not a denorm).
*
lower:
move.w LOCAL_EX(a0),d0 ;d0 has exponent
move.l LOCAL_LO(a0),d1 ;d1 has ls mant
sub.w #32,d0 ;account for ms mant being all zeros
bfffo d1{0:32},d7 ;find first 1 in ls mant to d7)
sub.w d7,d0 ;subtract shift count from exp
lsl.l d7,d1 ;shift first 1 to integer bit in ms mant
move.w d0,LOCAL_EX(a0) ;store ms mant
move.l d1,LOCAL_HI(a0) ;store exp
clr.l LOCAL_LO(a0) ;clear ls mant
move.l (a7)+,d7
rts
*
* denorm --- denormalize an intermediate result
*
* Used by underflow.
*
* Input:
* a0 points to the operand to be denormalized
* (in the internal extended format)
*
* d0: rounding precision
* Output:
* a0 points to the denormalized result
* (in the internal extended format)
*
* d0 is guard,round,sticky
*
* d0 comes into this routine with the rounding precision. It
* is then loaded with the denormalized exponent threshold for the
* rounding precision.
*
denorm:
btst.b #6,LOCAL_EX(a0) ;check for exponents between $7fff-$4000
beq.b no_sgn_ext
bset.b #7,LOCAL_EX(a0) ;sign extend if it is so
no_sgn_ext:
cmpi.b #0,d0 ;if 0 then extended precision
bne.b den_notext ;else branch - label renamed <1/7/91, JPO>
clr.l d1 ;load d1 with ext threshold
clr.l d0 ;clear the sticky flag
bsr.b dnrm_lp ;denormalize the number
tst.b d1 ;check for inex
beq.b no_inex ;if clr, no inex
bra.b dnrm_inex ;if set, set inex
den_notext: ; label renamed <1/7/91, JPO>
cmpi.l #1,d0 ;if 1 then single precision
beq.b load_sgl ;else must be 2, double prec
load_dbl:
move.w #dbl_thresh,d1 ;put copy of threshold in d1
move.l d1,d0 ;copy d1 into d0
sub.w LOCAL_EX(a0),d0 ;diff = threshold - exp
cmp.w #67,d0 ;if diff > 67 (mant + grs bits)
bpl.b chk_stky ;then branch (all bits would be
* ; shifted off in denorm routine)
clr.l d0 ;else clear the sticky flag
bsr.b dnrm_lp ;denormalize the number
tst.b d1 ;check flag
beq.b no_inex ;if clr, no inex
bra.b dnrm_inex ;if set, set inex
load_sgl:
move.w #sgl_thresh,d1 ;put copy of threshold in d1
move.l d1,d0 ;copy d1 into d0
sub.w LOCAL_EX(a0),d0 ;diff = threshold - exp
cmp.w #67,d0 ;if diff > 67 (mant + grs bits)
bpl.b chk_stky ;then branch (all bits would be
* ; shifted off in denorm routine)
clr.l d0 ;else clear the sticky flag
bsr.b dnrm_lp ;denormalize the number
tst.b d1 ;check flag
beq.b no_inex ;if clr, no inex
bra.b dnrm_inex ;if set, set inex
chk_stky:
tst.l LOCAL_HI(a0) ;check for any bits set
bne.b set_stky
tst.l LOCAL_LO(a0) ;check for any bits set
bne.b set_stky
bra.b clr_mant
set_stky:
or.l #inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
move.l #$20000000,d0 ;set sticky bit in return value
clr_mant:
move.w d1,LOCAL_EX(a0) ;load exp with threshold
move.l #0,LOCAL_HI(a0) ;set d1 = 0 (ms mantissa)
move.l #0,LOCAL_LO(a0) ;set d2 = 0 (ms mantissa)
rts
dnrm_inex:
or.l #inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
no_inex:
rts
*
* dnrm_lp --- normalize exponent/mantissa to specified threshhold
; - use FP_SCR6 instead of FP_SCR2 as scratch storage
; to avoid collision with caller "bindec" <4/25/91, JPO>
*
* Input:
* a0 points to the operand to be denormalized
* d0{31:29} initial guard,round,sticky
* d1{15:0} denormalization threshold
* Output:
* a0 points to the denormalized operand
* d0{31:29} final guard,round,sticky
* d1.b inexact flag: all ones means inexact result
*
* The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR6
* so that bfext can be used to extract the new low part of the mantissa.
* Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there
* is no LOCAL_GRS scratch word following it on the fsave frame.
*
dnrm_lp:
; move.l LOCAL_LO(a0),FP_SCR2+LOCAL_LO(a6) ; DELETED <4/25/91, JPO> <T2>
move.l LOCAL_LO(a0),FP_SCR6+LOCAL_LO(a6) ; <4/25/91, JPO> <T2>
clr.l d0 ; zero GRS bits
btst.b #E3,E_BYTE(a6) ; WBTEMP to be denormalized? <2/4/91, JPO>
beq.b @1 ; no. g,r,s remain clear <2/4/91, JPO>
move.l STAG(a6),d0 ; yes. initialize g,r,s in d0 bits 29-31
lsl.l #6,d0 ; <2/4/91, JPO>
and.l #$E0000000,d0 ; <2/4/91, JPO>
@1: ; <2/4/91, JPO>
; move.l d0,FP_SCR2+LOCAL_GRS(a6) ; DELETED <4/25/91, JPO> <T2>
move.l d0,FP_SCR6+LOCAL_GRS(a6) ; <4/25/91, JPO> <T2>
move.l d1,d0 ;copy the denorm threshold
sub.w LOCAL_EX(a0),d1 ;d1 = threshold - uns exponent
beq.b no_lp ;d1 = 0
cmp.w #32,d1
blt.b case_1 ;0 = d1 < 32
cmp.w #64,d1
blt.b case_2 ;32 <= d1 < 64
bra.w case_3 ;d1 >= 64
*
* No normalization necessary
*
no_lp:
clr.b d1 ;set no inex2 reported
; move.l FP_SCR2+LOCAL_GRS(a6),d0 ; restore original g,r,s - DELETED <4/25/91, JPO> <T2>
move.l FP_SCR6+LOCAL_GRS(a6),d0 ; restore original g,r,s <4/25/91, JPO> <T2>
rts
*
* case (0<d1<32)
*
case_1:
move.l d2,-(sp)
move.w d0,LOCAL_EX(a0) ;exponent = denorm threshold
move.l #32,d0
sub.w d1,d0 ;d0 = 32 - d1
; bfextu LOCAL_EX(a0){d0:32},d2 ; DELETED <2/4/91, JPO>
; bfextu d2{d1:d0},d2 ;d2 = new LOCAL_HI - DELETED <2/4/91, JPO>
; bfextu LOCAL_HI(a0){d0:32},d1 ;d1 = new LOCAL_LO - DELETED <2/4/91, JPO>
; bfextu FP_SCR2+LOCAL_LO(a6){d0:32},d0 ;d0 = new G,R,S - DELETED <2/4/91, JPO>
; move.l d2,LOCAL_HI(a0) ;store new LOCAL_HI - DELETED <2/4/91, JPO>
; move.l d1,LOCAL_LO(a0) ;store new LOCAL_LO - DELETED <2/4/91, JPO>
bfextu LOCAL_HI(a0){d0:32},d2 ; extract and store new LOCAL_LO <2/4/91, JPO>
move.l d2,LOCAL_LO(a0) ; <2/4/91, JPO>
bfextu LOCAL_HI(a0){0:d0},d2 ; extract and store new LOCAL_HI <2/4/91, JPO>
move.l d2,LOCAL_HI(a0) ; <2/4/91, JPO>
; bfextu FP_SCR2+LOCAL_GRS(a6){d0:d1},d2 ; d2 = shift out of G,R,S <2/4/91, JPO> - DELETED <4/25/91, JPO> <T2>
; bfextu FP_SCR2+LOCAL_LO(a6){d0:32},d0 ; d0 = new G,R,S <2/4/91, JPO> - DELETED <4/25/91, JPO> <T2>
bfextu FP_SCR6+LOCAL_GRS(a6){d0:d1},d2 ; d2 = shift out of G,R,S <4/25/91, JPO> <T2>
bfextu FP_SCR6+LOCAL_LO(a6){d0:32},d0 ; d0 = new G,R,S <4/25/91, JPO> <T2>
tst.l d2 ; any stickies shifted out? <2/4/91, JPO>
; sne.b d0 ; yes. set stickies <2/4/91, JPO> - DELETED <7/10/91, JPO> <T3>
beq.b @1 ; no stickies shifted out <7/10/91, JPO> <T3>
st.b d0 ; yes. set low stickies in d0 <7/10/91, JPO> <T3>
@1: ; label added <7/10/91, JPO> <T3>
clr.b d1
bftst d0{2:30}
beq.b c1nstky
bset.l #rnd_stky_bit,d0
st.b d1
c1nstky:
andi.l #$e0000000,d0 ;clear all but G,R,S
move.l (sp)+,d2
rts
*
* case (32<=d1<64)
*
case_2:
move.l d2,-(sp)
move.w d0,LOCAL_EX(a0) ;unsigned exponent = threshold
sub.w #32,d1 ;d1 now between 0 and 32
move.l #32,d0
sub.w d1,d0 ;d0 = 32 - d1
; bfextu LOCAL_EX(a0){d0:32},d2 ; DELETED <2/4/91, JPO>
; bfextu d2{d1:d0},d2 ;d2 = new LOCAL_LO - DELETED <2/4/91, JPO>
bfextu LOCAL_HI(a0){0:d0},d2 ; d2 = new LOCAL_LO <2/4/91, JPO>
bfextu LOCAL_HI(a0){d0:32},d1 ;d1 = new G,R,S
bftst d1{2:30}
bne.b c2_sstky ;bra if sticky bit to be set
; bftst FP_SCR2+LOCAL_LO(a6){d0:32} ; DELETED <4/25/91, JPO> <T2>
bftst FP_SCR6+LOCAL_LO(a6){d0:32} ; <4/25/91, JPO> <T2>
bne.b c2_sstky ;bra if sticky bit to be set
; tst.l FP_SCR2+LOCAL_GRS(a6) ; final possibly redundant check - DELETED <4/25/91, JPO> <T2>
tst.l FP_SCR6+LOCAL_GRS(a6) ; final possibly redundant check <4/25/91, JPO> <T2>
bne.b c2_sstky ; of extreme stickies
move.l d1,d0
clr.b d1
bra.b end_c2
c2_sstky:
move.l d1,d0
bset.l #rnd_stky_bit,d0
st.b d1
end_c2:
clr.l LOCAL_HI(a0) ;store LOCAL_HI = 0
move.l d2,LOCAL_LO(a0) ;store LOCAL_LO
andi.l #$e0000000,d0 ;get rid of all but G,R,S
move.l (sp)+,d2
rts
*
* d1 >= 64 Force the exponent to be the denorm threshold with the
* correct sign.
*
case_3:
move.w d0,LOCAL_EX(a0)
tst.w LOCAL_SGN(a0)
bge.b c3con
c3neg:
or.l #$80000000,LOCAL_EX(a0)
c3con:
cmp.w #64,d1
beq.b sixty_four
cmp.w #65,d1
beq.b sixty_five
*
* Shift value is out of range. Set d1 for inex2 flag and
* return a zero with the given threshold.
*
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
move.l #$20000000,d0
st.b d1
rts
sixty_four:
move.l LOCAL_HI(a0),d0
bfextu d0{2:30},d1
andi.l #$c0000000,d0
bra.b c3com
sixty_five:
move.l LOCAL_HI(a0),d0
bfextu d0{1:31},d1
andi.l #$80000000,d0
lsr.l #1,d0 ; shift G bit into R bit <2/4/91, JPO>
c3com:
tst.l d1
bne.b c3ssticky
tst.l LOCAL_LO(a0)
bne.b c3ssticky
; tst.b FP_SCR2+LOCAL_GRS(a6) ; DELETED <4/25/91, JPO> <T2>
tst.b FP_SCR6+LOCAL_GRS(a6) ; <4/25/91, JPO> <T2>
bne.b c3ssticky
clr.b d1
bra.b c3end
c3ssticky:
bset.l #rnd_stky_bit,d0
st.b d1
c3end:
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
rts