| | | |
| | round.sa 3.4 7/29/91 | |
| | | |
| | handle rounding and normalization tasks | |
| | | |
| | | |
| | | |
| | Copyright (C) Motorola, Inc. 1990 | |
| | All Rights Reserved | |
| | | |
| | For details on the license for this file, please see the | |
| | file, README, in this same directory. | |
| |ROUND idnt 2,1 | Motorola 040 Floating Point Software Package | |
| |section 8 | |
| #include "fpsp.h" | |
| | | |
| | 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). | |
| | | |
| .global round | |
| round: | |
| | If g=r=s=0 then result is exact and round is done, else set | |
| | the inex flag in status reg and continue. | |
| | | |
| bsrs ext_grs |this subroutine looks at the | |
| | :rounding precision and sets | |
| | ;the appropriate g-r-s bits. | |
| tstl %d0 |if grs are zero, go force | |
| bne rnd_cont |lower bits to zero for size | |
| swap %d1 |set up d1.w for round prec. | |
| bra truncate | |
| rnd_cont: | |
| | | |
| | Use rounding mode as an index into a jump table for these modes. | |
| | | |
| orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex | |
| lea mode_tab,%a1 | |
| movel (%a1,%d1.w*4),%a1 | |
| jmp (%a1) | |
| | | |
| | Jump table indexed by rounding mode in d1.w. All following assumes | |
| | grs != 0. | |
| | | |
| mode_tab: | |
| .long rnd_near | |
| .long rnd_zero | |
| .long rnd_mnus | |
| .long rnd_plus | |
| | | |
| | 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. | |
| tstb LOCAL_SGN(%a0) |check for sign | |
| bmi truncate |if positive then truncate | |
| movel #0xffffffff,%d0 |force g,r,s to be all f's | |
| lea add_to_l,%a1 | |
| movel (%a1,%d1.w*4),%a1 | |
| 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. | |
| tstb LOCAL_SGN(%a0) |check for sign | |
| bpl truncate |if negative then truncate | |
| movel #0xffffffff,%d0 |force g,r,s to be all f's | |
| lea add_to_l,%a1 | |
| movel (%a1,%d1.w*4),%a1 | |
| jmp (%a1) | |
| | | |
| | ROUND ZERO | |
| | | |
| | Always truncate. | |
| rnd_zero: | |
| swap %d1 |set up d1 for round prec. | |
| bra 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. | |
| asll #1,%d0 |shift g-bit to c-bit | |
| bcc truncate |if (g=1) then | |
| lea add_to_l,%a1 | |
| movel (%a1,%d1.w*4),%a1 | |
| 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 | |
| cmpiw #0,%d1 | |
| bnes sgl_or_dbl | |
| bras end_ext_grs | |
| sgl_or_dbl: | |
| moveml %d2/%d3,-(%a7) |make some temp registers | |
| cmpiw #1,%d1 | |
| bnes grs_dbl | |
| grs_sgl: | |
| bfextu LOCAL_HI(%a0){#24:#2},%d3 |sgl prec. g-r are 2 bits right | |
| movel #30,%d2 |of the sgl prec. limits | |
| lsll %d2,%d3 |shift g-r bits to MSB of d3 | |
| movel LOCAL_HI(%a0),%d2 |get word 2 for s-bit test | |
| andil #0x0000003f,%d2 |s bit is the or of all other | |
| bnes st_stky |bits to the right of g-r | |
| tstl LOCAL_LO(%a0) |test lower mantissa | |
| bnes st_stky |if any are set, set sticky | |
| tstl %d0 |test original g,r,s | |
| bnes st_stky |if any are set, set sticky | |
| bras 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 | |
| movel #30,%d2 |of the dbl prec. limits | |
| lsll %d2,%d3 |shift g-r bits to the MSB of d3 | |
| movel LOCAL_LO(%a0),%d2 |get lower mantissa for s-bit test | |
| andil #0x000001ff,%d2 |s bit is the or-ing of all | |
| bnes st_stky |other bits to the right of g-r | |
| tstl %d0 |test word original g,r,s | |
| bnes st_stky |if any are set, set sticky | |
| bras end_sd |if clear, exit | |
| st_stky: | |
| bset #rnd_stky_bit,%d3 | |
| end_sd: | |
| movel %d3,%d0 |return grs to d0 | |
| moveml (%a7)+,%d2/%d3 |restore scratch registers | |
| end_ext_grs: | |
| swap %d1 |restore d1 to original | |
| rts | |
| |******************* Local Equates | |
| .set ad_1_sgl,0x00000100 | constant to add 1 to l-bit in sgl prec | |
| .set ad_1_dbl,0x00000800 | 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: | |
| .long add_ext | |
| .long add_sgl | |
| .long add_dbl | |
| .long add_dbl | |
| | | |
| | ADD SINGLE | |
| | | |
| add_sgl: | |
| addl #ad_1_sgl,LOCAL_HI(%a0) | |
| bccs scc_clr |no mantissa overflow | |
| roxrw LOCAL_HI(%a0) |shift v-bit back in | |
| roxrw LOCAL_HI+2(%a0) |shift v-bit back in | |
| addw #0x1,LOCAL_EX(%a0) |and incr exponent | |
| scc_clr: | |
| tstl %d0 |test for rs = 0 | |
| bnes sgl_done | |
| andiw #0xfe00,LOCAL_HI+2(%a0) |clear the l-bit | |
| sgl_done: | |
| andil #0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit | |
| clrl LOCAL_LO(%a0) |clear d2 | |
| rts | |
| | | |
| | ADD EXTENDED | |
| | | |
| add_ext: | |
| addql #1,LOCAL_LO(%a0) |add 1 to l-bit | |
| bccs xcc_clr |test for carry out | |
| addql #1,LOCAL_HI(%a0) |propagate carry | |
| bccs xcc_clr | |
| roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit | |
| roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit | |
| roxrw LOCAL_LO(%a0) | |
| roxrw LOCAL_LO+2(%a0) | |
| addw #0x1,LOCAL_EX(%a0) |and inc exp | |
| xcc_clr: | |
| tstl %d0 |test rs = 0 | |
| bnes add_ext_done | |
| andib #0xfe,LOCAL_LO+3(%a0) |clear the l bit | |
| add_ext_done: | |
| rts | |
| | | |
| | ADD DOUBLE | |
| | | |
| add_dbl: | |
| addl #ad_1_dbl,LOCAL_LO(%a0) | |
| bccs dcc_clr | |
| addql #1,LOCAL_HI(%a0) |propagate carry | |
| bccs dcc_clr | |
| roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit | |
| roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit | |
| roxrw LOCAL_LO(%a0) | |
| roxrw LOCAL_LO+2(%a0) | |
| addw #0x1,LOCAL_EX(%a0) |incr exponent | |
| dcc_clr: | |
| tstl %d0 |test for rs = 0 | |
| bnes dbl_done | |
| andiw #0xf000,LOCAL_LO+2(%a0) |clear the l-bit | |
| dbl_done: | |
| andil #0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit | |
| rts | |
| error: | |
| rts | |
| | | |
| | Truncate all other bits | |
| | | |
| trunct: | |
| .long end_rnd | |
| .long sgl_done | |
| .long dbl_done | |
| .long dbl_done | |
| truncate: | |
| lea trunct,%a1 | |
| movel (%a1,%d1.w*4),%a1 | |
| 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 | |
| | | |
| .global nrm_zero | |
| nrm_zero: | |
| movew LOCAL_EX(%a0),%d0 | |
| cmpw #64,%d0 |see if exp > 64 | |
| bmis d0_less | |
| bsr nrm_set |exp > 64 so exp won't exceed 0 | |
| rts | |
| d0_less: | |
| moveml %d2/%d3/%d5/%d6,-(%a7) | |
| movel LOCAL_HI(%a0),%d1 | |
| movel LOCAL_LO(%a0),%d2 | |
| bfffo %d1{#0:#32},%d3 |get the distance to the first 1 | |
| | ;in ms mant | |
| beqs ms_clr |branch if no bits were set | |
| cmpw %d3,%d0 |of X>Y | |
| bmis greater |then exp will go past 0 (neg) if | |
| | ;it is just shifted | |
| bsr nrm_set |else exp won't go past 0 | |
| moveml (%a7)+,%d2/%d3/%d5/%d6 | |
| rts | |
| greater: | |
| movel %d2,%d6 |save ls mant in d6 | |
| lsll %d0,%d2 |shift ls mant by count | |
| lsll %d0,%d1 |shift ms mant by count | |
| movel #32,%d5 | |
| subl %d0,%d5 |make op a denorm by shifting bits | |
| lsrl %d5,%d6 |by the number in the exp, then | |
| | ;set exp = 0. | |
| orl %d6,%d1 |shift the ls mant bits into the ms mant | |
| movel #0,%d0 |same as if decremented exp to 0 | |
| | ;while shifting | |
| movew %d0,LOCAL_EX(%a0) | |
| movel %d1,LOCAL_HI(%a0) | |
| movel %d2,LOCAL_LO(%a0) | |
| moveml (%a7)+,%d2/%d3/%d5/%d6 | |
| rts | |
| ms_clr: | |
| bfffo %d2{#0:#32},%d3 |check if any bits set in ls mant | |
| beqs all_clr |branch if none set | |
| addw #32,%d3 | |
| cmpw %d3,%d0 |if X>Y | |
| bmis greater |then branch | |
| bsr nrm_set |else exp won't go past 0 | |
| moveml (%a7)+,%d2/%d3/%d5/%d6 | |
| rts | |
| all_clr: | |
| movew #0,LOCAL_EX(%a0) |no mantissa bits set. Set exp = 0. | |
| moveml (%a7)+,%d2/%d3/%d5/%d6 | |
| rts | |
| | | |
| | NRM_SET | |
| | | |
| .global nrm_set | |
| nrm_set: | |
| movel %d7,-(%a7) | |
| bfffo LOCAL_HI(%a0){#0:#32},%d7 |find first 1 in ms mant to d7) | |
| beqs lower |branch if ms mant is all 0's | |
| movel %d6,-(%a7) | |
| subw %d7,LOCAL_EX(%a0) |sub exponent by count | |
| movel LOCAL_HI(%a0),%d0 |d0 has ms mant | |
| movel LOCAL_LO(%a0),%d1 |d1 has ls mant | |
| lsll %d7,%d0 |shift first 1 to j bit position | |
| movel %d1,%d6 |copy ls mant into d6 | |
| lsll %d7,%d6 |shift ls mant by count | |
| movel %d6,LOCAL_LO(%a0) |store ls mant into memory | |
| moveql #32,%d6 | |
| subl %d7,%d6 |continue shift | |
| lsrl %d6,%d1 |shift off all bits but those that will | |
| | ;be shifted into ms mant | |
| orl %d1,%d0 |shift the ls mant bits into the ms mant | |
| movel %d0,LOCAL_HI(%a0) |store ms mant into memory | |
| moveml (%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: | |
| movew LOCAL_EX(%a0),%d0 |d0 has exponent | |
| movel LOCAL_LO(%a0),%d1 |d1 has ls mant | |
| subw #32,%d0 |account for ms mant being all zeros | |
| bfffo %d1{#0:#32},%d7 |find first 1 in ls mant to d7) | |
| subw %d7,%d0 |subtract shift count from exp | |
| lsll %d7,%d1 |shift first 1 to integer bit in ms mant | |
| movew %d0,LOCAL_EX(%a0) |store ms mant | |
| movel %d1,LOCAL_HI(%a0) |store exp | |
| clrl LOCAL_LO(%a0) |clear ls mant | |
| movel (%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. | |
| | | |
| .global denorm | |
| denorm: | |
| btstb #6,LOCAL_EX(%a0) |check for exponents between $7fff-$4000 | |
| beqs no_sgn_ext | |
| bsetb #7,LOCAL_EX(%a0) |sign extend if it is so | |
| no_sgn_ext: | |
| cmpib #0,%d0 |if 0 then extended precision | |
| bnes not_ext |else branch | |
| clrl %d1 |load d1 with ext threshold | |
| clrl %d0 |clear the sticky flag | |
| bsr dnrm_lp |denormalize the number | |
| tstb %d1 |check for inex | |
| beq no_inex |if clr, no inex | |
| bras dnrm_inex |if set, set inex | |
| not_ext: | |
| cmpil #1,%d0 |if 1 then single precision | |
| beqs load_sgl |else must be 2, double prec | |
| load_dbl: | |
| movew #dbl_thresh,%d1 |put copy of threshold in d1 | |
| movel %d1,%d0 |copy d1 into d0 | |
| subw LOCAL_EX(%a0),%d0 |diff = threshold - exp | |
| cmpw #67,%d0 |if diff > 67 (mant + grs bits) | |
| bpls chk_stky |then branch (all bits would be | |
| | ; shifted off in denorm routine) | |
| clrl %d0 |else clear the sticky flag | |
| bsr dnrm_lp |denormalize the number | |
| tstb %d1 |check flag | |
| beqs no_inex |if clr, no inex | |
| bras dnrm_inex |if set, set inex | |
| load_sgl: | |
| movew #sgl_thresh,%d1 |put copy of threshold in d1 | |
| movel %d1,%d0 |copy d1 into d0 | |
| subw LOCAL_EX(%a0),%d0 |diff = threshold - exp | |
| cmpw #67,%d0 |if diff > 67 (mant + grs bits) | |
| bpls chk_stky |then branch (all bits would be | |
| | ; shifted off in denorm routine) | |
| clrl %d0 |else clear the sticky flag | |
| bsr dnrm_lp |denormalize the number | |
| tstb %d1 |check flag | |
| beqs no_inex |if clr, no inex | |
| bras dnrm_inex |if set, set inex | |
| chk_stky: | |
| tstl LOCAL_HI(%a0) |check for any bits set | |
| bnes set_stky | |
| tstl LOCAL_LO(%a0) |check for any bits set | |
| bnes set_stky | |
| bras clr_mant | |
| set_stky: | |
| orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex | |
| movel #0x20000000,%d0 |set sticky bit in return value | |
| clr_mant: | |
| movew %d1,LOCAL_EX(%a0) |load exp with threshold | |
| movel #0,LOCAL_HI(%a0) |set d1 = 0 (ms mantissa) | |
| movel #0,LOCAL_LO(%a0) |set d2 = 0 (ms mantissa) | |
| rts | |
| dnrm_inex: | |
| orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex | |
| no_inex: | |
| rts | |
| | | |
| | dnrm_lp --- normalize exponent/mantissa to specified threshold | |
| | | |
| | 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_SCR2 | |
| | 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. | |
| | | |
| .global dnrm_lp | |
| dnrm_lp: | |
| movel %d2,-(%sp) |save d2 for temp use | |
| btstb #E3,E_BYTE(%a6) |test for type E3 exception | |
| beqs not_E3 |not type E3 exception | |
| bfextu WBTEMP_GRS(%a6){#6:#3},%d2 |extract guard,round, sticky bit | |
| movel #29,%d0 | |
| lsll %d0,%d2 |shift g,r,s to their positions | |
| movel %d2,%d0 | |
| not_E3: | |
| movel (%sp)+,%d2 |restore d2 | |
| movel LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6) | |
| movel %d0,FP_SCR2+LOCAL_GRS(%a6) | |
| movel %d1,%d0 |copy the denorm threshold | |
| subw LOCAL_EX(%a0),%d1 |d1 = threshold - uns exponent | |
| bles no_lp |d1 <= 0 | |
| cmpw #32,%d1 | |
| blts case_1 |0 = d1 < 32 | |
| cmpw #64,%d1 | |
| blts case_2 |32 <= d1 < 64 | |
| bra case_3 |d1 >= 64 | |
| | | |
| | No normalization necessary | |
| | | |
| no_lp: | |
| clrb %d1 |set no inex2 reported | |
| movel FP_SCR2+LOCAL_GRS(%a6),%d0 |restore original g,r,s | |
| rts | |
| | | |
| | case (0<d1<32) | |
| | | |
| case_1: | |
| movel %d2,-(%sp) | |
| movew %d0,LOCAL_EX(%a0) |exponent = denorm threshold | |
| movel #32,%d0 | |
| subw %d1,%d0 |d0 = 32 - d1 | |
| bfextu LOCAL_EX(%a0){%d0:#32},%d2 | |
| bfextu %d2{%d1:%d0},%d2 |d2 = new LOCAL_HI | |
| bfextu LOCAL_HI(%a0){%d0:#32},%d1 |d1 = new LOCAL_LO | |
| bfextu FP_SCR2+LOCAL_LO(%a6){%d0:#32},%d0 |d0 = new G,R,S | |
| movel %d2,LOCAL_HI(%a0) |store new LOCAL_HI | |
| movel %d1,LOCAL_LO(%a0) |store new LOCAL_LO | |
| clrb %d1 | |
| bftst %d0{#2:#30} | |
| beqs c1nstky | |
| bsetl #rnd_stky_bit,%d0 | |
| st %d1 | |
| c1nstky: | |
| movel FP_SCR2+LOCAL_GRS(%a6),%d2 |restore original g,r,s | |
| andil #0xe0000000,%d2 |clear all but G,R,S | |
| tstl %d2 |test if original G,R,S are clear | |
| beqs grs_clear | |
| orl #0x20000000,%d0 |set sticky bit in d0 | |
| grs_clear: | |
| andil #0xe0000000,%d0 |clear all but G,R,S | |
| movel (%sp)+,%d2 | |
| rts | |
| | | |
| | case (32<=d1<64) | |
| | | |
| case_2: | |
| movel %d2,-(%sp) | |
| movew %d0,LOCAL_EX(%a0) |unsigned exponent = threshold | |
| subw #32,%d1 |d1 now between 0 and 32 | |
| movel #32,%d0 | |
| subw %d1,%d0 |d0 = 32 - d1 | |
| bfextu LOCAL_EX(%a0){%d0:#32},%d2 | |
| bfextu %d2{%d1:%d0},%d2 |d2 = new LOCAL_LO | |
| bfextu LOCAL_HI(%a0){%d0:#32},%d1 |d1 = new G,R,S | |
| bftst %d1{#2:#30} | |
| bnes c2_sstky |bra if sticky bit to be set | |
| bftst FP_SCR2+LOCAL_LO(%a6){%d0:#32} | |
| bnes c2_sstky |bra if sticky bit to be set | |
| movel %d1,%d0 | |
| clrb %d1 | |
| bras end_c2 | |
| c2_sstky: | |
| movel %d1,%d0 | |
| bsetl #rnd_stky_bit,%d0 | |
| st %d1 | |
| end_c2: | |
| clrl LOCAL_HI(%a0) |store LOCAL_HI = 0 | |
| movel %d2,LOCAL_LO(%a0) |store LOCAL_LO | |
| movel FP_SCR2+LOCAL_GRS(%a6),%d2 |restore original g,r,s | |
| andil #0xe0000000,%d2 |clear all but G,R,S | |
| tstl %d2 |test if original G,R,S are clear | |
| beqs clear_grs | |
| orl #0x20000000,%d0 |set sticky bit in d0 | |
| clear_grs: | |
| andil #0xe0000000,%d0 |get rid of all but G,R,S | |
| movel (%sp)+,%d2 | |
| rts | |
| | | |
| | d1 >= 64 Force the exponent to be the denorm threshold with the | |
| | correct sign. | |
| | | |
| case_3: | |
| movew %d0,LOCAL_EX(%a0) | |
| tstw LOCAL_SGN(%a0) | |
| bges c3con | |
| c3neg: | |
| orl #0x80000000,LOCAL_EX(%a0) | |
| c3con: | |
| cmpw #64,%d1 | |
| beqs sixty_four | |
| cmpw #65,%d1 | |
| beqs sixty_five | |
| | | |
| | Shift value is out of range. Set d1 for inex2 flag and | |
| | return a zero with the given threshold. | |
| | | |
| clrl LOCAL_HI(%a0) | |
| clrl LOCAL_LO(%a0) | |
| movel #0x20000000,%d0 | |
| st %d1 | |
| rts | |
| sixty_four: | |
| movel LOCAL_HI(%a0),%d0 | |
| bfextu %d0{#2:#30},%d1 | |
| andil #0xc0000000,%d0 | |
| bras c3com | |
| sixty_five: | |
| movel LOCAL_HI(%a0),%d0 | |
| bfextu %d0{#1:#31},%d1 | |
| andil #0x80000000,%d0 | |
| lsrl #1,%d0 |shift high bit into R bit | |
| c3com: | |
| tstl %d1 | |
| bnes c3ssticky | |
| tstl LOCAL_LO(%a0) | |
| bnes c3ssticky | |
| tstb FP_SCR2+LOCAL_GRS(%a6) | |
| bnes c3ssticky | |
| clrb %d1 | |
| bras c3end | |
| c3ssticky: | |
| bsetl #rnd_stky_bit,%d0 | |
| st %d1 | |
| c3end: | |
| clrl LOCAL_HI(%a0) | |
| clrl LOCAL_LO(%a0) | |
| rts | |
| |end |