Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:48

0001 #include "fpsp-namespace.h"
0002 //
0003 //
0004 //  round.sa 3.4 7/29/91
0005 //
0006 //  handle rounding and normalization tasks
0007 //
0008 //
0009 //
0010 //      Copyright (C) Motorola, Inc. 1990
0011 //          All Rights Reserved
0012 //
0013 //  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
0014 //  The copyright notice above does not evidence any
0015 //  actual or intended publication of such source code.
0016 
0017 //ROUND idnt    2,1 | Motorola 040 Floating Point Software Package
0018 
0019     |section    8
0020 
0021 #include "fpsp.defs"
0022 
0023 //
0024 //  round --- round result according to precision/mode
0025 //
0026 //  a0 points to the input operand in the internal extended format
0027 //  d1(high word) contains rounding precision:
0028 //      ext = $0000xxxx
0029 //      sgl = $0001xxxx
0030 //      dbl = $0002xxxx
0031 //  d1(low word) contains rounding mode:
0032 //      RN  = $xxxx0000
0033 //      RZ  = $xxxx0001
0034 //      RM  = $xxxx0010
0035 //      RP  = $xxxx0011
0036 //  d0{31:29} contains the g,r,s bits (extended)
0037 //
0038 //  On return the value pointed to by a0 is correctly rounded,
0039 //  a0 is preserved and the g-r-s bits in d0 are cleared.
0040 //  The result is not typed - the tag field is invalid.  The
0041 //  result is still in the internal extended format.
0042 //
0043 //  The INEX bit of USER_FPSR will be set if the rounded result was
0044 //  inexact (i.e. if any of the g-r-s bits were set).
0045 //
0046 
0047     .global round
0048 round:
0049 // If g=r=s=0 then result is exact and round is done, else set
0050 // the inex flag in status reg and continue.
0051 //
0052     bsrs    ext_grs         //this subroutine looks at the
0053 //                  :rounding precision and sets
0054 //                  ;the appropriate g-r-s bits.
0055     tstl    %d0         //if grs are zero, go force
0056     bne rnd_cont        //lower bits to zero for size
0057 
0058     swap    %d1         //set up d1.w for round prec.
0059     bra truncate
0060 
0061 rnd_cont:
0062 //
0063 // Use rounding mode as an index into a jump table for these modes.
0064 //
0065     orl #inx2a_mask,USER_FPSR(%a6) //set inex2/ainex
0066     lea mode_tab,%a1
0067     movel   (%a1,%d1.w*4),%a1
0068     jmp (%a1)
0069 //
0070 // Jump table indexed by rounding mode in d1.w.  All following assumes
0071 // grs != 0.
0072 //
0073 mode_tab:
0074     .long   rnd_near
0075     .long   rnd_zero
0076     .long   rnd_mnus
0077     .long   rnd_plus
0078 //
0079 //  ROUND PLUS INFINITY
0080 //
0081 //  If sign of fp number = 0 (positive), then add 1 to l.
0082 //
0083 rnd_plus:
0084     swap    %d1         //set up d1 for round prec.
0085     tstb    LOCAL_SGN(%a0)      //check for sign
0086     bmi truncate        //if positive then truncate
0087     movel   #0xffffffff,%d0     //force g,r,s to be all f's
0088     lea add_to_l,%a1
0089     movel   (%a1,%d1.w*4),%a1
0090     jmp (%a1)
0091 //
0092 //  ROUND MINUS INFINITY
0093 //
0094 //  If sign of fp number = 1 (negative), then add 1 to l.
0095 //
0096 rnd_mnus:
0097     swap    %d1         //set up d1 for round prec.
0098     tstb    LOCAL_SGN(%a0)      //check for sign
0099     bpl truncate        //if negative then truncate
0100     movel   #0xffffffff,%d0     //force g,r,s to be all f's
0101     lea add_to_l,%a1
0102     movel   (%a1,%d1.w*4),%a1
0103     jmp (%a1)
0104 //
0105 //  ROUND ZERO
0106 //
0107 //  Always truncate.
0108 rnd_zero:
0109     swap    %d1         //set up d1 for round prec.
0110     bra truncate
0111 //
0112 //
0113 //  ROUND NEAREST
0114 //
0115 //  If (g=1), then add 1 to l and if (r=s=0), then clear l
0116 //  Note that this will round to even in case of a tie.
0117 //
0118 rnd_near:
0119     swap    %d1         //set up d1 for round prec.
0120     asll    #1,%d0          //shift g-bit to c-bit
0121     bcc truncate        //if (g=1) then
0122     lea add_to_l,%a1
0123     movel   (%a1,%d1.w*4),%a1
0124     jmp (%a1)
0125 
0126 //
0127 //  ext_grs --- extract guard, round and sticky bits
0128 //
0129 // Input:   d1 =        PREC:ROUND
0130 // Output:      d0{31:29}=  guard, round, sticky
0131 //
0132 // The ext_grs extract the guard/round/sticky bits according to the
0133 // selected rounding precision. It is called by the round subroutine
0134 // only.  All registers except d0 are kept intact. d0 becomes an
0135 // updated guard,round,sticky in d0{31:29}
0136 //
0137 // Notes: the ext_grs uses the round PREC, and therefore has to swap d1
0138 //   prior to usage, and needs to restore d1 to original.
0139 //
0140 ext_grs:
0141     swap    %d1         //have d1.w point to round precision
0142     cmpiw   #0,%d1
0143     bnes    sgl_or_dbl
0144     bras    end_ext_grs
0145 
0146 sgl_or_dbl:
0147     moveml  %d2/%d3,-(%a7)      //make some temp registers
0148     cmpiw   #1,%d1
0149     bnes    grs_dbl
0150 grs_sgl:
0151     bfextu  LOCAL_HI(%a0){#24:#2},%d3   //sgl prec. g-r are 2 bits right
0152     movel   #30,%d2         //of the sgl prec. limits
0153     lsll    %d2,%d3         //shift g-r bits to MSB of d3
0154     movel   LOCAL_HI(%a0),%d2       //get word 2 for s-bit test
0155     andil   #0x0000003f,%d2     //s bit is the or of all other
0156     bnes    st_stky         //bits to the right of g-r
0157     tstl    LOCAL_LO(%a0)       //test lower mantissa
0158     bnes    st_stky         //if any are set, set sticky
0159     tstl    %d0         //test original g,r,s
0160     bnes    st_stky         //if any are set, set sticky
0161     bras    end_sd          //if words 3 and 4 are clr, exit
0162 grs_dbl:
0163     bfextu  LOCAL_LO(%a0){#21:#2},%d3   //dbl-prec. g-r are 2 bits right
0164     movel   #30,%d2         //of the dbl prec. limits
0165     lsll    %d2,%d3         //shift g-r bits to the MSB of d3
0166     movel   LOCAL_LO(%a0),%d2       //get lower mantissa  for s-bit test
0167     andil   #0x000001ff,%d2     //s bit is the or-ing of all
0168     bnes    st_stky         //other bits to the right of g-r
0169     tstl    %d0         //test word original g,r,s
0170     bnes    st_stky         //if any are set, set sticky
0171     bras    end_sd          //if clear, exit
0172 st_stky:
0173     bset    #rnd_stky_bit,%d3
0174 end_sd:
0175     movel   %d3,%d0         //return grs to d0
0176     moveml  (%a7)+,%d2/%d3      //restore scratch registers
0177 end_ext_grs:
0178     swap    %d1         //restore d1 to original
0179     rts
0180 
0181 //*******************  Local Equates
0182     .set    ad_1_sgl,0x00000100 //  constant to add 1 to l-bit in sgl prec
0183     .set    ad_1_dbl,0x00000800 //  constant to add 1 to l-bit in dbl prec
0184 
0185 
0186 //Jump table for adding 1 to the l-bit indexed by rnd prec
0187 
0188 add_to_l:
0189     .long   add_ext
0190     .long   add_sgl
0191     .long   add_dbl
0192     .long   add_dbl
0193 //
0194 //  ADD SINGLE
0195 //
0196 add_sgl:
0197     addl    #ad_1_sgl,LOCAL_HI(%a0)
0198     bccs    scc_clr         //no mantissa overflow
0199     roxrw  LOCAL_HI(%a0)        //shift v-bit back in
0200     roxrw  LOCAL_HI+2(%a0)      //shift v-bit back in
0201     addw    #0x1,LOCAL_EX(%a0)  //and incr exponent
0202 scc_clr:
0203     tstl    %d0         //test for rs = 0
0204     bnes    sgl_done
0205     andiw  #0xfe00,LOCAL_HI+2(%a0)  //clear the l-bit
0206 sgl_done:
0207     andil   #0xffffff00,LOCAL_HI(%a0) //truncate bits beyond sgl limit
0208     clrl    LOCAL_LO(%a0)       //clear d2
0209     rts
0210 
0211 //
0212 //  ADD EXTENDED
0213 //
0214 add_ext:
0215     addql  #1,LOCAL_LO(%a0)     //add 1 to l-bit
0216     bccs    xcc_clr         //test for carry out
0217     addql  #1,LOCAL_HI(%a0)     //propagate carry
0218     bccs    xcc_clr
0219     roxrw  LOCAL_HI(%a0)        //mant is 0 so restore v-bit
0220     roxrw  LOCAL_HI+2(%a0)      //mant is 0 so restore v-bit
0221     roxrw   LOCAL_LO(%a0)
0222     roxrw   LOCAL_LO+2(%a0)
0223     addw    #0x1,LOCAL_EX(%a0)  //and inc exp
0224 xcc_clr:
0225     tstl    %d0         //test rs = 0
0226     bnes    add_ext_done
0227     andib   #0xfe,LOCAL_LO+3(%a0)   //clear the l bit
0228 add_ext_done:
0229     rts
0230 //
0231 //  ADD DOUBLE
0232 //
0233 add_dbl:
0234     addl    #ad_1_dbl,LOCAL_LO(%a0)
0235     bccs    dcc_clr
0236     addql   #1,LOCAL_HI(%a0)        //propagate carry
0237     bccs    dcc_clr
0238     roxrw   LOCAL_HI(%a0)       //mant is 0 so restore v-bit
0239     roxrw   LOCAL_HI+2(%a0)     //mant is 0 so restore v-bit
0240     roxrw   LOCAL_LO(%a0)
0241     roxrw   LOCAL_LO+2(%a0)
0242     addw    #0x1,LOCAL_EX(%a0)  //incr exponent
0243 dcc_clr:
0244     tstl    %d0         //test for rs = 0
0245     bnes    dbl_done
0246     andiw   #0xf000,LOCAL_LO+2(%a0) //clear the l-bit
0247 
0248 dbl_done:
0249     andil   #0xfffff800,LOCAL_LO(%a0) //truncate bits beyond dbl limit
0250     rts
0251 
0252 error:
0253     rts
0254 //
0255 // Truncate all other bits
0256 //
0257 trunct:
0258     .long   end_rnd
0259     .long   sgl_done
0260     .long   dbl_done
0261     .long   dbl_done
0262 
0263 truncate:
0264     lea trunct,%a1
0265     movel   (%a1,%d1.w*4),%a1
0266     jmp (%a1)
0267 
0268 end_rnd:
0269     rts
0270 
0271 //
0272 //  NORMALIZE
0273 //
0274 // These routines (nrm_zero & nrm_set) normalize the unnorm.  This
0275 // is done by shifting the mantissa left while decrementing the
0276 // exponent.
0277 //
0278 // NRM_SET shifts and decrements until there is a 1 set in the integer
0279 // bit of the mantissa (msb in d1).
0280 //
0281 // NRM_ZERO shifts and decrements until there is a 1 set in the integer
0282 // bit of the mantissa (msb in d1) unless this would mean the exponent
0283 // would go less than 0.  In that case the number becomes a denorm - the
0284 // exponent (d0) is set to 0 and the mantissa (d1 & d2) is not
0285 // normalized.
0286 //
0287 // Note that both routines have been optimized (for the worst case) and
0288 // therefore do not have the easy to follow decrement/shift loop.
0289 //
0290 //  NRM_ZERO
0291 //
0292 //  Distance to first 1 bit in mantissa = X
0293 //  Distance to 0 from exponent = Y
0294 //  If X < Y
0295 //  Then
0296 //    nrm_set
0297 //  Else
0298 //    shift mantissa by Y
0299 //    set exponent = 0
0300 //
0301 //input:
0302 //  FP_SCR1 = exponent, ms mantissa part, ls mantissa part
0303 //output:
0304 //  L_SCR1{4} = fpte15 or ete15 bit
0305 //
0306     .global nrm_zero
0307 nrm_zero:
0308     movew   LOCAL_EX(%a0),%d0
0309     cmpw   #64,%d0          //see if exp > 64
0310     bmis    d0_less
0311     bsr nrm_set     //exp > 64 so exp won't exceed 0
0312     rts
0313 d0_less:
0314     moveml  %d2/%d3/%d5/%d6,-(%a7)
0315     movel   LOCAL_HI(%a0),%d1
0316     movel   LOCAL_LO(%a0),%d2
0317 
0318     bfffo   %d1{#0:#32},%d3 //get the distance to the first 1
0319 //              ;in ms mant
0320     beqs    ms_clr      //branch if no bits were set
0321     cmpw    %d3,%d0     //of X>Y
0322     bmis    greater     //then exp will go past 0 (neg) if
0323 //              ;it is just shifted
0324     bsr nrm_set     //else exp won't go past 0
0325     moveml  (%a7)+,%d2/%d3/%d5/%d6
0326     rts
0327 greater:
0328     movel   %d2,%d6     //save ls mant in d6
0329     lsll    %d0,%d2     //shift ls mant by count
0330     lsll    %d0,%d1     //shift ms mant by count
0331     movel   #32,%d5
0332     subl    %d0,%d5     //make op a denorm by shifting bits
0333     lsrl    %d5,%d6     //by the number in the exp, then
0334 //              ;set exp = 0.
0335     orl %d6,%d1     //shift the ls mant bits into the ms mant
0336     movel   #0,%d0      //same as if decremented exp to 0
0337 //              ;while shifting
0338     movew   %d0,LOCAL_EX(%a0)
0339     movel   %d1,LOCAL_HI(%a0)
0340     movel   %d2,LOCAL_LO(%a0)
0341     moveml  (%a7)+,%d2/%d3/%d5/%d6
0342     rts
0343 ms_clr:
0344     bfffo   %d2{#0:#32},%d3 //check if any bits set in ls mant
0345     beqs    all_clr     //branch if none set
0346     addw    #32,%d3
0347     cmpw    %d3,%d0     //if X>Y
0348     bmis    greater     //then branch
0349     bsr nrm_set     //else exp won't go past 0
0350     moveml  (%a7)+,%d2/%d3/%d5/%d6
0351     rts
0352 all_clr:
0353     movew   #0,LOCAL_EX(%a0)    //no mantissa bits set. Set exp = 0.
0354     moveml  (%a7)+,%d2/%d3/%d5/%d6
0355     rts
0356 //
0357 //  NRM_SET
0358 //
0359     .global nrm_set
0360 nrm_set:
0361     movel   %d7,-(%a7)
0362     bfffo   LOCAL_HI(%a0){#0:#32},%d7 //find first 1 in ms mant to d7)
0363     beqs    lower       //branch if ms mant is all 0's
0364 
0365     movel   %d6,-(%a7)
0366 
0367     subw    %d7,LOCAL_EX(%a0)   //sub exponent by count
0368     movel   LOCAL_HI(%a0),%d0   //d0 has ms mant
0369     movel   LOCAL_LO(%a0),%d1 //d1 has ls mant
0370 
0371     lsll    %d7,%d0     //shift first 1 to j bit position
0372     movel   %d1,%d6     //copy ls mant into d6
0373     lsll    %d7,%d6     //shift ls mant by count
0374     movel   %d6,LOCAL_LO(%a0)   //store ls mant into memory
0375     moveql  #32,%d6
0376     subl    %d7,%d6     //continue shift
0377     lsrl    %d6,%d1     //shift off all bits but those that will
0378 //              ;be shifted into ms mant
0379     orl %d1,%d0     //shift the ls mant bits into the ms mant
0380     movel   %d0,LOCAL_HI(%a0)   //store ms mant into memory
0381     moveml  (%a7)+,%d7/%d6  //restore registers
0382     rts
0383 
0384 //
0385 // We get here if ms mant was = 0, and we assume ls mant has bits
0386 // set (otherwise this would have been tagged a zero not a denorm).
0387 //
0388 lower:
0389     movew   LOCAL_EX(%a0),%d0   //d0 has exponent
0390     movel   LOCAL_LO(%a0),%d1   //d1 has ls mant
0391     subw    #32,%d0     //account for ms mant being all zeros
0392     bfffo   %d1{#0:#32},%d7 //find first 1 in ls mant to d7)
0393     subw    %d7,%d0     //subtract shift count from exp
0394     lsll    %d7,%d1     //shift first 1 to integer bit in ms mant
0395     movew   %d0,LOCAL_EX(%a0)   //store ms mant
0396     movel   %d1,LOCAL_HI(%a0)   //store exp
0397     clrl    LOCAL_LO(%a0)   //clear ls mant
0398     movel   (%a7)+,%d7
0399     rts
0400 //
0401 //  denorm --- denormalize an intermediate result
0402 //
0403 //  Used by underflow.
0404 //
0405 // Input:
0406 //  a0   points to the operand to be denormalized
0407 //       (in the internal extended format)
0408 //
0409 //  d0:      rounding precision
0410 // Output:
0411 //  a0   points to the denormalized result
0412 //       (in the internal extended format)
0413 //
0414 //  d0  is guard,round,sticky
0415 //
0416 // d0 comes into this routine with the rounding precision. It
0417 // is then loaded with the denormalized exponent threshold for the
0418 // rounding precision.
0419 //
0420 
0421     .global denorm
0422 denorm:
0423     btstb   #6,LOCAL_EX(%a0)    //check for exponents between $7fff-$4000
0424     beqs    no_sgn_ext
0425     bsetb   #7,LOCAL_EX(%a0)    //sign extend if it is so
0426 no_sgn_ext:
0427 
0428     cmpib   #0,%d0      //if 0 then extended precision
0429     bnes    not_ext     //else branch
0430 
0431     clrl    %d1     //load d1 with ext threshold
0432     clrl    %d0     //clear the sticky flag
0433     bsr dnrm_lp     //denormalize the number
0434     tstb    %d1     //check for inex
0435     beq no_inex     //if clr, no inex
0436     bras    dnrm_inex   //if set, set inex
0437 
0438 not_ext:
0439     cmpil   #1,%d0      //if 1 then single precision
0440     beqs    load_sgl    //else must be 2, double prec
0441 
0442 load_dbl:
0443     movew   #dbl_thresh,%d1 //put copy of threshold in d1
0444     movel   %d1,%d0     //copy d1 into d0
0445     subw    LOCAL_EX(%a0),%d0   //diff = threshold - exp
0446     cmpw    #67,%d0     //if diff > 67 (mant + grs bits)
0447     bpls    chk_stky    //then branch (all bits would be
0448 //              ; shifted off in denorm routine)
0449     clrl    %d0     //else clear the sticky flag
0450     bsr dnrm_lp     //denormalize the number
0451     tstb    %d1     //check flag
0452     beqs    no_inex     //if clr, no inex
0453     bras    dnrm_inex   //if set, set inex
0454 
0455 load_sgl:
0456     movew   #sgl_thresh,%d1 //put copy of threshold in d1
0457     movel   %d1,%d0     //copy d1 into d0
0458     subw    LOCAL_EX(%a0),%d0   //diff = threshold - exp
0459     cmpw    #67,%d0     //if diff > 67 (mant + grs bits)
0460     bpls    chk_stky    //then branch (all bits would be
0461 //              ; shifted off in denorm routine)
0462     clrl    %d0     //else clear the sticky flag
0463     bsr dnrm_lp     //denormalize the number
0464     tstb    %d1     //check flag
0465     beqs    no_inex     //if clr, no inex
0466     bras    dnrm_inex   //if set, set inex
0467 
0468 chk_stky:
0469     tstl    LOCAL_HI(%a0)   //check for any bits set
0470     bnes    set_stky
0471     tstl    LOCAL_LO(%a0)   //check for any bits set
0472     bnes    set_stky
0473     bras    clr_mant
0474 set_stky:
0475     orl #inx2a_mask,USER_FPSR(%a6) //set inex2/ainex
0476     movel   #0x20000000,%d0 //set sticky bit in return value
0477 clr_mant:
0478     movew   %d1,LOCAL_EX(%a0)       //load exp with threshold
0479     movel   #0,LOCAL_HI(%a0)    //set d1 = 0 (ms mantissa)
0480     movel   #0,LOCAL_LO(%a0)        //set d2 = 0 (ms mantissa)
0481     rts
0482 dnrm_inex:
0483     orl #inx2a_mask,USER_FPSR(%a6) //set inex2/ainex
0484 no_inex:
0485     rts
0486 
0487 //
0488 //  dnrm_lp --- normalize exponent/mantissa to specified threshold
0489 //
0490 // Input:
0491 //  a0      points to the operand to be denormalized
0492 //  d0{31:29}   initial guard,round,sticky
0493 //  d1{15:0}    denormalization threshold
0494 // Output:
0495 //  a0      points to the denormalized operand
0496 //  d0{31:29}   final guard,round,sticky
0497 //  d1.b        inexact flag:  all ones means inexact result
0498 //
0499 // The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
0500 // so that bfext can be used to extract the new low part of the mantissa.
0501 // Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there
0502 // is no LOCAL_GRS scratch word following it on the fsave frame.
0503 //
0504     .global dnrm_lp
0505 dnrm_lp:
0506     movel   %d2,-(%sp)      //save d2 for temp use
0507     btstb   #E3,E_BYTE(%a6)     //test for type E3 exception
0508     beqs    not_E3          //not type E3 exception
0509     bfextu  WBTEMP_GRS(%a6){#6:#3},%d2  //extract guard,round, sticky  bit
0510     movel   #29,%d0
0511     lsll    %d0,%d2         //shift g,r,s to their positions
0512     movel   %d2,%d0
0513 not_E3:
0514     movel   (%sp)+,%d2      //restore d2
0515     movel   LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6)
0516     movel   %d0,FP_SCR2+LOCAL_GRS(%a6)
0517     movel   %d1,%d0         //copy the denorm threshold
0518     subw    LOCAL_EX(%a0),%d1       //d1 = threshold - uns exponent
0519     bles    no_lp           //d1 <= 0
0520     cmpw    #32,%d1
0521     blts    case_1          //0 = d1 < 32
0522     cmpw    #64,%d1
0523     blts    case_2          //32 <= d1 < 64
0524     bra case_3          //d1 >= 64
0525 //
0526 // No normalization necessary
0527 //
0528 no_lp:
0529     clrb    %d1         //set no inex2 reported
0530     movel   FP_SCR2+LOCAL_GRS(%a6),%d0  //restore original g,r,s
0531     rts
0532 //
0533 // case (0<d1<32)
0534 //
0535 case_1:
0536     movel   %d2,-(%sp)
0537     movew   %d0,LOCAL_EX(%a0)       //exponent = denorm threshold
0538     movel   #32,%d0
0539     subw    %d1,%d0         //d0 = 32 - d1
0540     bfextu  LOCAL_EX(%a0){%d0:#32},%d2
0541     bfextu  %d2{%d1:%d0},%d2        //d2 = new LOCAL_HI
0542     bfextu  LOCAL_HI(%a0){%d0:#32},%d1  //d1 = new LOCAL_LO
0543     bfextu  FP_SCR2+LOCAL_LO(%a6){%d0:#32},%d0  //d0 = new G,R,S
0544     movel   %d2,LOCAL_HI(%a0)       //store new LOCAL_HI
0545     movel   %d1,LOCAL_LO(%a0)       //store new LOCAL_LO
0546     clrb    %d1
0547     bftst   %d0{#2:#30}
0548     beqs    c1nstky
0549     bsetl   #rnd_stky_bit,%d0
0550     st  %d1
0551 c1nstky:
0552     movel   FP_SCR2+LOCAL_GRS(%a6),%d2  //restore original g,r,s
0553     andil   #0xe0000000,%d2     //clear all but G,R,S
0554     tstl    %d2         //test if original G,R,S are clear
0555     beqs    grs_clear
0556     orl #0x20000000,%d0     //set sticky bit in d0
0557 grs_clear:
0558     andil   #0xe0000000,%d0     //clear all but G,R,S
0559     movel   (%sp)+,%d2
0560     rts
0561 //
0562 // case (32<=d1<64)
0563 //
0564 case_2:
0565     movel   %d2,-(%sp)
0566     movew   %d0,LOCAL_EX(%a0)       //unsigned exponent = threshold
0567     subw    #32,%d1         //d1 now between 0 and 32
0568     movel   #32,%d0
0569     subw    %d1,%d0         //d0 = 32 - d1
0570     bfextu  LOCAL_EX(%a0){%d0:#32},%d2
0571     bfextu  %d2{%d1:%d0},%d2        //d2 = new LOCAL_LO
0572     bfextu  LOCAL_HI(%a0){%d0:#32},%d1  //d1 = new G,R,S
0573     bftst   %d1{#2:#30}
0574     bnes    c2_sstky        //bra if sticky bit to be set
0575     bftst   FP_SCR2+LOCAL_LO(%a6){%d0:#32}
0576     bnes    c2_sstky        //bra if sticky bit to be set
0577     movel   %d1,%d0
0578     clrb    %d1
0579     bras    end_c2
0580 c2_sstky:
0581     movel   %d1,%d0
0582     bsetl   #rnd_stky_bit,%d0
0583     st  %d1
0584 end_c2:
0585     clrl    LOCAL_HI(%a0)       //store LOCAL_HI = 0
0586     movel   %d2,LOCAL_LO(%a0)       //store LOCAL_LO
0587     movel   FP_SCR2+LOCAL_GRS(%a6),%d2  //restore original g,r,s
0588     andil   #0xe0000000,%d2     //clear all but G,R,S
0589     tstl    %d2         //test if original G,R,S are clear
0590     beqs    clear_grs
0591     orl #0x20000000,%d0     //set sticky bit in d0
0592 clear_grs:
0593     andil   #0xe0000000,%d0     //get rid of all but G,R,S
0594     movel   (%sp)+,%d2
0595     rts
0596 //
0597 // d1 >= 64 Force the exponent to be the denorm threshold with the
0598 // correct sign.
0599 //
0600 case_3:
0601     movew   %d0,LOCAL_EX(%a0)
0602     tstw    LOCAL_SGN(%a0)
0603     bges    c3con
0604 c3neg:
0605     orl #0x80000000,LOCAL_EX(%a0)
0606 c3con:
0607     cmpw    #64,%d1
0608     beqs    sixty_four
0609     cmpw    #65,%d1
0610     beqs    sixty_five
0611 //
0612 // Shift value is out of range.  Set d1 for inex2 flag and
0613 // return a zero with the given threshold.
0614 //
0615     clrl    LOCAL_HI(%a0)
0616     clrl    LOCAL_LO(%a0)
0617     movel   #0x20000000,%d0
0618     st  %d1
0619     rts
0620 
0621 sixty_four:
0622     movel   LOCAL_HI(%a0),%d0
0623     bfextu  %d0{#2:#30},%d1
0624     andil   #0xc0000000,%d0
0625     bras    c3com
0626 
0627 sixty_five:
0628     movel   LOCAL_HI(%a0),%d0
0629     bfextu  %d0{#1:#31},%d1
0630     andil   #0x80000000,%d0
0631     lsrl    #1,%d0          //shift high bit into R bit
0632 
0633 c3com:
0634     tstl    %d1
0635     bnes    c3ssticky
0636     tstl    LOCAL_LO(%a0)
0637     bnes    c3ssticky
0638     tstb    FP_SCR2+LOCAL_GRS(%a6)
0639     bnes    c3ssticky
0640     clrb    %d1
0641     bras    c3end
0642 
0643 c3ssticky:
0644     bsetl   #rnd_stky_bit,%d0
0645     st  %d1
0646 c3end:
0647     clrl    LOCAL_HI(%a0)
0648     clrl    LOCAL_LO(%a0)
0649     rts
0650 
0651     |end