Back to home page

LXR

 
 

    


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

0001 #include "fpsp-namespace.h"
0002 //
0003 //
0004 //  res_func.sa 3.9 7/29/91
0005 //
0006 // Normalizes denormalized numbers if necessary and updates the
0007 // stack frame.  The function is then restored back into the
0008 // machine and the 040 completes the operation.  This routine
0009 // is only used by the unsupported data type/format handler.
0010 // (Exception vector 55).
0011 //
0012 // For packed move out (fmove.p fpm,<ea>) the operation is
0013 // completed here; data is packed and moved to user memory.
0014 // The stack is restored to the 040 only in the case of a
0015 // reportable exception in the conversion.
0016 //
0017 //
0018 //      Copyright (C) Motorola, Inc. 1990
0019 //          All Rights Reserved
0020 //
0021 //  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
0022 //  The copyright notice above does not evidence any
0023 //  actual or intended publication of such source code.
0024 
0025 RES_FUNC:    //idnt    2,1 | Motorola 040 Floating Point Software Package
0026 
0027     |section    8
0028 
0029 #include "fpsp.defs"
0030 
0031 sp_bnds:    .short  0x3f81,0x407e
0032         .short  0x3f6a,0x0000
0033 dp_bnds:    .short  0x3c01,0x43fe
0034         .short  0x3bcd,0x0000
0035 
0036     |xref   mem_write
0037     |xref   bindec
0038     |xref   get_fline
0039     |xref   round
0040     |xref   denorm
0041     |xref   dest_ext
0042     |xref   dest_dbl
0043     |xref   dest_sgl
0044     |xref   unf_sub
0045     |xref   nrm_set
0046     |xref   dnrm_lp
0047     |xref   ovf_res
0048     |xref   reg_dest
0049     |xref   t_ovfl
0050     |xref   t_unfl
0051 
0052     .global res_func
0053     .global     p_move
0054 
0055 res_func:
0056     clrb    DNRM_FLG(%a6)
0057     clrb    RES_FLG(%a6)
0058     clrb    CU_ONLY(%a6)
0059     tstb    DY_MO_FLG(%a6)
0060     beqs    monadic
0061 dyadic:
0062     btstb   #7,DTAG(%a6)    //if dop = norm=000, zero=001,
0063 //              ;inf=010 or nan=011
0064     beqs    monadic     //then branch
0065 //              ;else denorm
0066 // HANDLE DESTINATION DENORM HERE
0067 //              ;set dtag to norm
0068 //              ;write the tag & fpte15 to the fstack
0069     leal    FPTEMP(%a6),%a0
0070 
0071     bclrb   #sign_bit,LOCAL_EX(%a0)
0072     sne LOCAL_SGN(%a0)
0073 
0074     bsr nrm_set     //normalize number (exp will go negative)
0075     bclrb   #sign_bit,LOCAL_EX(%a0) //get rid of false sign
0076     bfclr   LOCAL_SGN(%a0){#0:#8}   //change back to IEEE ext format
0077     beqs    dpos
0078     bsetb   #sign_bit,LOCAL_EX(%a0)
0079 dpos:
0080     bfclr   DTAG(%a6){#0:#4}    //set tag to normalized, FPTE15 = 0
0081     bsetb   #4,DTAG(%a6)    //set FPTE15
0082     orb #0x0f,DNRM_FLG(%a6)
0083 monadic:
0084     leal    ETEMP(%a6),%a0
0085     btstb   #direction_bit,CMDREG1B(%a6)    //check direction
0086     bne opclass3            //it is a mv out
0087 //
0088 // At this point, only opclass 0 and 2 possible
0089 //
0090     btstb   #7,STAG(%a6)    //if sop = norm=000, zero=001,
0091 //              ;inf=010 or nan=011
0092     bne mon_dnrm    //else denorm
0093     tstb    DY_MO_FLG(%a6)  //all cases of dyadic instructions would
0094     bne normal      //require normalization of denorm
0095 
0096 // At this point:
0097 //  monadic instructions:   fabs  = $18  fneg   = $1a  ftst   = $3a
0098 //              fmove = $00  fsmove = $40  fdmove = $44
0099 //              fsqrt = $05* fssqrt = $41  fdsqrt = $45
0100 //              (*fsqrt reencoded to $05)
0101 //
0102     movew   CMDREG1B(%a6),%d0   //get command register
0103     andil   #0x7f,%d0           //strip to only command word
0104 //
0105 // At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
0106 // fdsqrt are possible.
0107 // For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
0108 // For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
0109 //
0110     btstl   #0,%d0
0111     bne normal          //weed out fsqrt instructions
0112 //
0113 // cu_norm handles fmove in instructions with normalized inputs.
0114 // The routine round is used to correctly round the input for the
0115 // destination precision and mode.
0116 //
0117 cu_norm:
0118     st  CU_ONLY(%a6)        //set cu-only inst flag
0119     movew   CMDREG1B(%a6),%d0
0120     andib   #0x3b,%d0       //isolate bits to select inst
0121     tstb    %d0
0122     beql    cu_nmove    //if zero, it is an fmove
0123     cmpib   #0x18,%d0
0124     beql    cu_nabs     //if $18, it is fabs
0125     cmpib   #0x1a,%d0
0126     beql    cu_nneg     //if $1a, it is fneg
0127 //
0128 // Inst is ftst.  Check the source operand and set the cc's accordingly.
0129 // No write is done, so simply rts.
0130 //
0131 cu_ntst:
0132     movew   LOCAL_EX(%a0),%d0
0133     bclrl   #15,%d0
0134     sne LOCAL_SGN(%a0)
0135     beqs    cu_ntpo
0136     orl #neg_mask,USER_FPSR(%a6) //set N
0137 cu_ntpo:
0138     cmpiw   #0x7fff,%d0 //test for inf/nan
0139     bnes    cu_ntcz
0140     tstl    LOCAL_HI(%a0)
0141     bnes    cu_ntn
0142     tstl    LOCAL_LO(%a0)
0143     bnes    cu_ntn
0144     orl #inf_mask,USER_FPSR(%a6)
0145     rts
0146 cu_ntn:
0147     orl #nan_mask,USER_FPSR(%a6)
0148     movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    //set up fptemp sign for
0149 //                      ;snan handler
0150 
0151     rts
0152 cu_ntcz:
0153     tstl    LOCAL_HI(%a0)
0154     bnel    cu_ntsx
0155     tstl    LOCAL_LO(%a0)
0156     bnel    cu_ntsx
0157     orl #z_mask,USER_FPSR(%a6)
0158 cu_ntsx:
0159     rts
0160 //
0161 // Inst is fabs.  Execute the absolute value function on the input.
0162 // Branch to the fmove code.  If the operand is NaN, do nothing.
0163 //
0164 cu_nabs:
0165     moveb   STAG(%a6),%d0
0166     btstl   #5,%d0          //test for NaN or zero
0167     bne wr_etemp        //if either, simply write it
0168     bclrb   #7,LOCAL_EX(%a0)        //do abs
0169     bras    cu_nmove        //fmove code will finish
0170 //
0171 // Inst is fneg.  Execute the negate value function on the input.
0172 // Fall though to the fmove code.  If the operand is NaN, do nothing.
0173 //
0174 cu_nneg:
0175     moveb   STAG(%a6),%d0
0176     btstl   #5,%d0          //test for NaN or zero
0177     bne wr_etemp        //if either, simply write it
0178     bchgb   #7,LOCAL_EX(%a0)        //do neg
0179 //
0180 // Inst is fmove.  This code also handles all result writes.
0181 // If bit 2 is set, round is forced to double.  If it is clear,
0182 // and bit 6 is set, round is forced to single.  If both are clear,
0183 // the round precision is found in the fpcr.  If the rounding precision
0184 // is double or single, round the result before the write.
0185 //
0186 cu_nmove:
0187     moveb   STAG(%a6),%d0
0188     andib   #0xe0,%d0           //isolate stag bits
0189     bne wr_etemp        //if not norm, simply write it
0190     btstb   #2,CMDREG1B+1(%a6)  //check for rd
0191     bne cu_nmrd
0192     btstb   #6,CMDREG1B+1(%a6)  //check for rs
0193     bne cu_nmrs
0194 //
0195 // The move or operation is not with forced precision.  Test for
0196 // nan or inf as the input; if so, simply write it to FPn.  Use the
0197 // FPCR_MODE byte to get rounding on norms and zeros.
0198 //
0199 cu_nmnr:
0200     bfextu  FPCR_MODE(%a6){#0:#2},%d0
0201     tstb    %d0         //check for extended
0202     beq cu_wrexn        //if so, just write result
0203     cmpib   #1,%d0          //check for single
0204     beq cu_nmrs         //fall through to double
0205 //
0206 // The move is fdmove or round precision is double.
0207 //
0208 cu_nmrd:
0209     movel   #2,%d0          //set up the size for denorm
0210     movew   LOCAL_EX(%a0),%d1       //compare exponent to double threshold
0211     andw    #0x7fff,%d1
0212     cmpw    #0x3c01,%d1
0213     bls cu_nunfl
0214     bfextu  FPCR_MODE(%a6){#2:#2},%d1   //get rmode
0215     orl #0x00020000,%d1     //or in rprec (double)
0216     clrl    %d0         //clear g,r,s for round
0217     bclrb   #sign_bit,LOCAL_EX(%a0) //convert to internal format
0218     sne LOCAL_SGN(%a0)
0219     bsrl    round
0220     bfclr   LOCAL_SGN(%a0){#0:#8}
0221     beqs    cu_nmrdc
0222     bsetb   #sign_bit,LOCAL_EX(%a0)
0223 cu_nmrdc:
0224     movew   LOCAL_EX(%a0),%d1       //check for overflow
0225     andw    #0x7fff,%d1
0226     cmpw    #0x43ff,%d1
0227     bge cu_novfl        //take care of overflow case
0228     bra cu_wrexn
0229 //
0230 // The move is fsmove or round precision is single.
0231 //
0232 cu_nmrs:
0233     movel   #1,%d0
0234     movew   LOCAL_EX(%a0),%d1
0235     andw    #0x7fff,%d1
0236     cmpw    #0x3f81,%d1
0237     bls cu_nunfl
0238     bfextu  FPCR_MODE(%a6){#2:#2},%d1
0239     orl #0x00010000,%d1
0240     clrl    %d0
0241     bclrb   #sign_bit,LOCAL_EX(%a0)
0242     sne LOCAL_SGN(%a0)
0243     bsrl    round
0244     bfclr   LOCAL_SGN(%a0){#0:#8}
0245     beqs    cu_nmrsc
0246     bsetb   #sign_bit,LOCAL_EX(%a0)
0247 cu_nmrsc:
0248     movew   LOCAL_EX(%a0),%d1
0249     andw    #0x7FFF,%d1
0250     cmpw    #0x407f,%d1
0251     blt cu_wrexn
0252 //
0253 // The operand is above precision boundaries.  Use t_ovfl to
0254 // generate the correct value.
0255 //
0256 cu_novfl:
0257     bsr t_ovfl
0258     bra cu_wrexn
0259 //
0260 // The operand is below precision boundaries.  Use denorm to
0261 // generate the correct value.
0262 //
0263 cu_nunfl:
0264     bclrb   #sign_bit,LOCAL_EX(%a0)
0265     sne LOCAL_SGN(%a0)
0266     bsr denorm
0267     bfclr   LOCAL_SGN(%a0){#0:#8}   //change back to IEEE ext format
0268     beqs    cu_nucont
0269     bsetb   #sign_bit,LOCAL_EX(%a0)
0270 cu_nucont:
0271     bfextu  FPCR_MODE(%a6){#2:#2},%d1
0272     btstb   #2,CMDREG1B+1(%a6)  //check for rd
0273     bne inst_d
0274     btstb   #6,CMDREG1B+1(%a6)  //check for rs
0275     bne inst_s
0276     swap    %d1
0277     moveb   FPCR_MODE(%a6),%d1
0278     lsrb    #6,%d1
0279     swap    %d1
0280     bra inst_sd
0281 inst_d:
0282     orl #0x00020000,%d1
0283     bra inst_sd
0284 inst_s:
0285     orl #0x00010000,%d1
0286 inst_sd:
0287     bclrb   #sign_bit,LOCAL_EX(%a0)
0288     sne LOCAL_SGN(%a0)
0289     bsrl    round
0290     bfclr   LOCAL_SGN(%a0){#0:#8}
0291     beqs    cu_nuflp
0292     bsetb   #sign_bit,LOCAL_EX(%a0)
0293 cu_nuflp:
0294     btstb   #inex2_bit,FPSR_EXCEPT(%a6)
0295     beqs    cu_nuninx
0296     orl #aunfl_mask,USER_FPSR(%a6) //if the round was inex, set AUNFL
0297 cu_nuninx:
0298     tstl    LOCAL_HI(%a0)       //test for zero
0299     bnes    cu_nunzro
0300     tstl    LOCAL_LO(%a0)
0301     bnes    cu_nunzro
0302 //
0303 // The mantissa is zero from the denorm loop.  Check sign and rmode
0304 // to see if rounding should have occurred which would leave the lsb.
0305 //
0306     movel   USER_FPCR(%a6),%d0
0307     andil   #0x30,%d0       //isolate rmode
0308     cmpil   #0x20,%d0
0309     blts    cu_nzro
0310     bnes    cu_nrp
0311 cu_nrm:
0312     tstw    LOCAL_EX(%a0)   //if positive, set lsb
0313     bges    cu_nzro
0314     btstb   #7,FPCR_MODE(%a6) //check for double
0315     beqs    cu_nincs
0316     bras    cu_nincd
0317 cu_nrp:
0318     tstw    LOCAL_EX(%a0)   //if positive, set lsb
0319     blts    cu_nzro
0320     btstb   #7,FPCR_MODE(%a6) //check for double
0321     beqs    cu_nincs
0322 cu_nincd:
0323     orl #0x800,LOCAL_LO(%a0) //inc for double
0324     bra cu_nunzro
0325 cu_nincs:
0326     orl #0x100,LOCAL_HI(%a0) //inc for single
0327     bra cu_nunzro
0328 cu_nzro:
0329     orl #z_mask,USER_FPSR(%a6)
0330     moveb   STAG(%a6),%d0
0331     andib   #0xe0,%d0
0332     cmpib   #0x40,%d0       //check if input was tagged zero
0333     beqs    cu_numv
0334 cu_nunzro:
0335     orl #unfl_mask,USER_FPSR(%a6) //set unfl
0336 cu_numv:
0337     movel   (%a0),ETEMP(%a6)
0338     movel   4(%a0),ETEMP_HI(%a6)
0339     movel   8(%a0),ETEMP_LO(%a6)
0340 //
0341 // Write the result to memory, setting the fpsr cc bits.  NaN and Inf
0342 // bypass cu_wrexn.
0343 //
0344 cu_wrexn:
0345     tstw    LOCAL_EX(%a0)       //test for zero
0346     beqs    cu_wrzero
0347     cmpw    #0x8000,LOCAL_EX(%a0)   //test for zero
0348     bnes    cu_wreon
0349 cu_wrzero:
0350     orl #z_mask,USER_FPSR(%a6)  //set Z bit
0351 cu_wreon:
0352     tstw    LOCAL_EX(%a0)
0353     bpl wr_etemp
0354     orl #neg_mask,USER_FPSR(%a6)
0355     bra wr_etemp
0356 
0357 //
0358 // HANDLE SOURCE DENORM HERE
0359 //
0360 //              ;clear denorm stag to norm
0361 //              ;write the new tag & ete15 to the fstack
0362 mon_dnrm:
0363 //
0364 // At this point, check for the cases in which normalizing the
0365 // denorm produces incorrect results.
0366 //
0367     tstb    DY_MO_FLG(%a6)  //all cases of dyadic instructions would
0368     bnes    nrm_src     //require normalization of denorm
0369 
0370 // At this point:
0371 //  monadic instructions:   fabs  = $18  fneg   = $1a  ftst   = $3a
0372 //              fmove = $00  fsmove = $40  fdmove = $44
0373 //              fsqrt = $05* fssqrt = $41  fdsqrt = $45
0374 //              (*fsqrt reencoded to $05)
0375 //
0376     movew   CMDREG1B(%a6),%d0   //get command register
0377     andil   #0x7f,%d0           //strip to only command word
0378 //
0379 // At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
0380 // fdsqrt are possible.
0381 // For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
0382 // For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
0383 //
0384     btstl   #0,%d0
0385     bnes    nrm_src     //weed out fsqrt instructions
0386     st  CU_ONLY(%a6)    //set cu-only inst flag
0387     bra cu_dnrm     //fmove, fabs, fneg, ftst
0388 //              ;cases go to cu_dnrm
0389 nrm_src:
0390     bclrb   #sign_bit,LOCAL_EX(%a0)
0391     sne LOCAL_SGN(%a0)
0392     bsr nrm_set     //normalize number (exponent will go
0393 //              ; negative)
0394     bclrb   #sign_bit,LOCAL_EX(%a0) //get rid of false sign
0395 
0396     bfclr   LOCAL_SGN(%a0){#0:#8}   //change back to IEEE ext format
0397     beqs    spos
0398     bsetb   #sign_bit,LOCAL_EX(%a0)
0399 spos:
0400     bfclr   STAG(%a6){#0:#4}    //set tag to normalized, FPTE15 = 0
0401     bsetb   #4,STAG(%a6)    //set ETE15
0402     orb #0xf0,DNRM_FLG(%a6)
0403 normal:
0404     tstb    DNRM_FLG(%a6)   //check if any of the ops were denorms
0405     bne ck_wrap     //if so, check if it is a potential
0406 //              ;wrap-around case
0407 fix_stk:
0408     moveb   #0xfe,CU_SAVEPC(%a6)
0409     bclrb   #E1,E_BYTE(%a6)
0410 
0411     clrw    NMNEXC(%a6)
0412 
0413     st  RES_FLG(%a6)    //indicate that a restore is needed
0414     rts
0415 
0416 //
0417 // cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
0418 // ftst) completely in software without an frestore to the 040.
0419 //
0420 cu_dnrm:
0421     st  CU_ONLY(%a6)
0422     movew   CMDREG1B(%a6),%d0
0423     andib   #0x3b,%d0       //isolate bits to select inst
0424     tstb    %d0
0425     beql    cu_dmove    //if zero, it is an fmove
0426     cmpib   #0x18,%d0
0427     beql    cu_dabs     //if $18, it is fabs
0428     cmpib   #0x1a,%d0
0429     beql    cu_dneg     //if $1a, it is fneg
0430 //
0431 // Inst is ftst.  Check the source operand and set the cc's accordingly.
0432 // No write is done, so simply rts.
0433 //
0434 cu_dtst:
0435     movew   LOCAL_EX(%a0),%d0
0436     bclrl   #15,%d0
0437     sne LOCAL_SGN(%a0)
0438     beqs    cu_dtpo
0439     orl #neg_mask,USER_FPSR(%a6) //set N
0440 cu_dtpo:
0441     cmpiw   #0x7fff,%d0 //test for inf/nan
0442     bnes    cu_dtcz
0443     tstl    LOCAL_HI(%a0)
0444     bnes    cu_dtn
0445     tstl    LOCAL_LO(%a0)
0446     bnes    cu_dtn
0447     orl #inf_mask,USER_FPSR(%a6)
0448     rts
0449 cu_dtn:
0450     orl #nan_mask,USER_FPSR(%a6)
0451     movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    //set up fptemp sign for
0452 //                      ;snan handler
0453     rts
0454 cu_dtcz:
0455     tstl    LOCAL_HI(%a0)
0456     bnel    cu_dtsx
0457     tstl    LOCAL_LO(%a0)
0458     bnel    cu_dtsx
0459     orl #z_mask,USER_FPSR(%a6)
0460 cu_dtsx:
0461     rts
0462 //
0463 // Inst is fabs.  Execute the absolute value function on the input.
0464 // Branch to the fmove code.
0465 //
0466 cu_dabs:
0467     bclrb   #7,LOCAL_EX(%a0)        //do abs
0468     bras    cu_dmove        //fmove code will finish
0469 //
0470 // Inst is fneg.  Execute the negate value function on the input.
0471 // Fall though to the fmove code.
0472 //
0473 cu_dneg:
0474     bchgb   #7,LOCAL_EX(%a0)        //do neg
0475 //
0476 // Inst is fmove.  This code also handles all result writes.
0477 // If bit 2 is set, round is forced to double.  If it is clear,
0478 // and bit 6 is set, round is forced to single.  If both are clear,
0479 // the round precision is found in the fpcr.  If the rounding precision
0480 // is double or single, the result is zero, and the mode is checked
0481 // to determine if the lsb of the result should be set.
0482 //
0483 cu_dmove:
0484     btstb   #2,CMDREG1B+1(%a6)  //check for rd
0485     bne cu_dmrd
0486     btstb   #6,CMDREG1B+1(%a6)  //check for rs
0487     bne cu_dmrs
0488 //
0489 // The move or operation is not with forced precision.  Use the
0490 // FPCR_MODE byte to get rounding.
0491 //
0492 cu_dmnr:
0493     bfextu  FPCR_MODE(%a6){#0:#2},%d0
0494     tstb    %d0         //check for extended
0495     beq cu_wrexd        //if so, just write result
0496     cmpib   #1,%d0          //check for single
0497     beq cu_dmrs         //fall through to double
0498 //
0499 // The move is fdmove or round precision is double.  Result is zero.
0500 // Check rmode for rp or rm and set lsb accordingly.
0501 //
0502 cu_dmrd:
0503     bfextu  FPCR_MODE(%a6){#2:#2},%d1   //get rmode
0504     tstw    LOCAL_EX(%a0)       //check sign
0505     blts    cu_dmdn
0506     cmpib   #3,%d1          //check for rp
0507     bne cu_dpd          //load double pos zero
0508     bra cu_dpdr         //load double pos zero w/lsb
0509 cu_dmdn:
0510     cmpib   #2,%d1          //check for rm
0511     bne cu_dnd          //load double neg zero
0512     bra cu_dndr         //load double neg zero w/lsb
0513 //
0514 // The move is fsmove or round precision is single.  Result is zero.
0515 // Check for rp or rm and set lsb accordingly.
0516 //
0517 cu_dmrs:
0518     bfextu  FPCR_MODE(%a6){#2:#2},%d1   //get rmode
0519     tstw    LOCAL_EX(%a0)       //check sign
0520     blts    cu_dmsn
0521     cmpib   #3,%d1          //check for rp
0522     bne cu_spd          //load single pos zero
0523     bra cu_spdr         //load single pos zero w/lsb
0524 cu_dmsn:
0525     cmpib   #2,%d1          //check for rm
0526     bne cu_snd          //load single neg zero
0527     bra cu_sndr         //load single neg zero w/lsb
0528 //
0529 // The precision is extended, so the result in etemp is correct.
0530 // Simply set unfl (not inex2 or aunfl) and write the result to
0531 // the correct fp register.
0532 cu_wrexd:
0533     orl #unfl_mask,USER_FPSR(%a6)
0534     tstw    LOCAL_EX(%a0)
0535     beq wr_etemp
0536     orl #neg_mask,USER_FPSR(%a6)
0537     bra wr_etemp
0538 //
0539 // These routines write +/- zero in double format.  The routines
0540 // cu_dpdr and cu_dndr set the double lsb.
0541 //
0542 cu_dpd:
0543     movel   #0x3c010000,LOCAL_EX(%a0)   //force pos double zero
0544     clrl    LOCAL_HI(%a0)
0545     clrl    LOCAL_LO(%a0)
0546     orl #z_mask,USER_FPSR(%a6)
0547     orl #unfinx_mask,USER_FPSR(%a6)
0548     bra wr_etemp
0549 cu_dpdr:
0550     movel   #0x3c010000,LOCAL_EX(%a0)   //force pos double zero
0551     clrl    LOCAL_HI(%a0)
0552     movel   #0x800,LOCAL_LO(%a0)    //with lsb set
0553     orl #unfinx_mask,USER_FPSR(%a6)
0554     bra wr_etemp
0555 cu_dnd:
0556     movel   #0xbc010000,LOCAL_EX(%a0)   //force pos double zero
0557     clrl    LOCAL_HI(%a0)
0558     clrl    LOCAL_LO(%a0)
0559     orl #z_mask,USER_FPSR(%a6)
0560     orl #neg_mask,USER_FPSR(%a6)
0561     orl #unfinx_mask,USER_FPSR(%a6)
0562     bra wr_etemp
0563 cu_dndr:
0564     movel   #0xbc010000,LOCAL_EX(%a0)   //force pos double zero
0565     clrl    LOCAL_HI(%a0)
0566     movel   #0x800,LOCAL_LO(%a0)    //with lsb set
0567     orl #neg_mask,USER_FPSR(%a6)
0568     orl #unfinx_mask,USER_FPSR(%a6)
0569     bra wr_etemp
0570 //
0571 // These routines write +/- zero in single format.  The routines
0572 // cu_dpdr and cu_dndr set the single lsb.
0573 //
0574 cu_spd:
0575     movel   #0x3f810000,LOCAL_EX(%a0)   //force pos single zero
0576     clrl    LOCAL_HI(%a0)
0577     clrl    LOCAL_LO(%a0)
0578     orl #z_mask,USER_FPSR(%a6)
0579     orl #unfinx_mask,USER_FPSR(%a6)
0580     bra wr_etemp
0581 cu_spdr:
0582     movel   #0x3f810000,LOCAL_EX(%a0)   //force pos single zero
0583     movel   #0x100,LOCAL_HI(%a0)    //with lsb set
0584     clrl    LOCAL_LO(%a0)
0585     orl #unfinx_mask,USER_FPSR(%a6)
0586     bra wr_etemp
0587 cu_snd:
0588     movel   #0xbf810000,LOCAL_EX(%a0)   //force pos single zero
0589     clrl    LOCAL_HI(%a0)
0590     clrl    LOCAL_LO(%a0)
0591     orl #z_mask,USER_FPSR(%a6)
0592     orl #neg_mask,USER_FPSR(%a6)
0593     orl #unfinx_mask,USER_FPSR(%a6)
0594     bra wr_etemp
0595 cu_sndr:
0596     movel   #0xbf810000,LOCAL_EX(%a0)   //force pos single zero
0597     movel   #0x100,LOCAL_HI(%a0)    //with lsb set
0598     clrl    LOCAL_LO(%a0)
0599     orl #neg_mask,USER_FPSR(%a6)
0600     orl #unfinx_mask,USER_FPSR(%a6)
0601     bra wr_etemp
0602 
0603 //
0604 // This code checks for 16-bit overflow conditions on dyadic
0605 // operations which are not restorable into the floating-point
0606 // unit and must be completed in software.  Basically, this
0607 // condition exists with a very large norm and a denorm.  One
0608 // of the operands must be denormalized to enter this code.
0609 //
0610 // Flags used:
0611 //  DY_MO_FLG contains 0 for monadic op, $ff for dyadic
0612 //  DNRM_FLG contains $00 for neither op denormalized
0613 //                    $0f for the destination op denormalized
0614 //                    $f0 for the source op denormalized
0615 //                    $ff for both ops denormalized
0616 //
0617 // The wrap-around condition occurs for add, sub, div, and cmp
0618 // when
0619 //
0620 //  abs(dest_exp - src_exp) >= $8000
0621 //
0622 // and for mul when
0623 //
0624 //  (dest_exp + src_exp) < $0
0625 //
0626 // we must process the operation here if this case is true.
0627 //
0628 // The rts following the frcfpn routine is the exit from res_func
0629 // for this condition.  The restore flag (RES_FLG) is left clear.
0630 // No frestore is done unless an exception is to be reported.
0631 //
0632 // For fadd:
0633 //  if(sign_of(dest) != sign_of(src))
0634 //      replace exponent of src with $3fff (keep sign)
0635 //      use fpu to perform dest+new_src (user's rmode and X)
0636 //      clr sticky
0637 //  else
0638 //      set sticky
0639 //  call round with user's precision and mode
0640 //  move result to fpn and wbtemp
0641 //
0642 // For fsub:
0643 //  if(sign_of(dest) == sign_of(src))
0644 //      replace exponent of src with $3fff (keep sign)
0645 //      use fpu to perform dest+new_src (user's rmode and X)
0646 //      clr sticky
0647 //  else
0648 //      set sticky
0649 //  call round with user's precision and mode
0650 //  move result to fpn and wbtemp
0651 //
0652 // For fdiv/fsgldiv:
0653 //  if(both operands are denorm)
0654 //      restore_to_fpu;
0655 //  if(dest is norm)
0656 //      force_ovf;
0657 //  else(dest is denorm)
0658 //      force_unf:
0659 //
0660 // For fcmp:
0661 //  if(dest is norm)
0662 //      N = sign_of(dest);
0663 //  else(dest is denorm)
0664 //      N = sign_of(src);
0665 //
0666 // For fmul:
0667 //  if(both operands are denorm)
0668 //      force_unf;
0669 //  if((dest_exp + src_exp) < 0)
0670 //      force_unf:
0671 //  else
0672 //      restore_to_fpu;
0673 //
0674 // local equates:
0675     .set    addcode,0x22
0676     .set    subcode,0x28
0677     .set    mulcode,0x23
0678     .set    divcode,0x20
0679     .set    cmpcode,0x38
0680 ck_wrap:
0681     | tstb  DY_MO_FLG(%a6)  ;check for fsqrt
0682     beq fix_stk     //if zero, it is fsqrt
0683     movew   CMDREG1B(%a6),%d0
0684     andiw   #0x3b,%d0       //strip to command bits
0685     cmpiw   #addcode,%d0
0686     beq wrap_add
0687     cmpiw   #subcode,%d0
0688     beq wrap_sub
0689     cmpiw   #mulcode,%d0
0690     beq wrap_mul
0691     cmpiw   #cmpcode,%d0
0692     beq wrap_cmp
0693 //
0694 // Inst is fdiv.
0695 //
0696 wrap_div:
0697     cmpb    #0xff,DNRM_FLG(%a6) //if both ops denorm,
0698     beq fix_stk      //restore to fpu
0699 //
0700 // One of the ops is denormalized.  Test for wrap condition
0701 // and force the result.
0702 //
0703     cmpb    #0x0f,DNRM_FLG(%a6) //check for dest denorm
0704     bnes    div_srcd
0705 div_destd:
0706     bsrl    ckinf_ns
0707     bne fix_stk
0708     bfextu  ETEMP_EX(%a6){#1:#15},%d0   //get src exp (always pos)
0709     bfexts  FPTEMP_EX(%a6){#1:#15},%d1  //get dest exp (always neg)
0710     subl    %d1,%d0         //subtract dest from src
0711     cmpl    #0x7fff,%d0
0712     blt fix_stk         //if less, not wrap case
0713     clrb    WBTEMP_SGN(%a6)
0714     movew   ETEMP_EX(%a6),%d0       //find the sign of the result
0715     movew   FPTEMP_EX(%a6),%d1
0716     eorw    %d1,%d0
0717     andiw   #0x8000,%d0
0718     beq force_unf
0719     st  WBTEMP_SGN(%a6)
0720     bra force_unf
0721 
0722 ckinf_ns:
0723     moveb   STAG(%a6),%d0       //check source tag for inf or nan
0724     bra ck_in_com
0725 ckinf_nd:
0726     moveb   DTAG(%a6),%d0       //check destination tag for inf or nan
0727 ck_in_com:
0728     andib   #0x60,%d0           //isolate tag bits
0729     cmpb    #0x40,%d0           //is it inf?
0730     beq nan_or_inf      //not wrap case
0731     cmpb    #0x60,%d0           //is it nan?
0732     beq nan_or_inf      //yes, not wrap case?
0733     cmpb    #0x20,%d0           //is it a zero?
0734     beq nan_or_inf      //yes
0735     clrl    %d0
0736     rts             //then ; it is either a zero of norm,
0737 //                  ;check wrap case
0738 nan_or_inf:
0739     moveql  #-1,%d0
0740     rts
0741 
0742 
0743 
0744 div_srcd:
0745     bsrl    ckinf_nd
0746     bne fix_stk
0747     bfextu  FPTEMP_EX(%a6){#1:#15},%d0  //get dest exp (always pos)
0748     bfexts  ETEMP_EX(%a6){#1:#15},%d1   //get src exp (always neg)
0749     subl    %d1,%d0         //subtract src from dest
0750     cmpl    #0x8000,%d0
0751     blt fix_stk         //if less, not wrap case
0752     clrb    WBTEMP_SGN(%a6)
0753     movew   ETEMP_EX(%a6),%d0       //find the sign of the result
0754     movew   FPTEMP_EX(%a6),%d1
0755     eorw    %d1,%d0
0756     andiw   #0x8000,%d0
0757     beqs    force_ovf
0758     st  WBTEMP_SGN(%a6)
0759 //
0760 // This code handles the case of the instruction resulting in
0761 // an overflow condition.
0762 //
0763 force_ovf:
0764     bclrb   #E1,E_BYTE(%a6)
0765     orl #ovfl_inx_mask,USER_FPSR(%a6)
0766     clrw    NMNEXC(%a6)
0767     leal    WBTEMP(%a6),%a0     //point a0 to memory location
0768     movew   CMDREG1B(%a6),%d0
0769     btstl   #6,%d0          //test for forced precision
0770     beqs    frcovf_fpcr
0771     btstl   #2,%d0          //check for double
0772     bnes    frcovf_dbl
0773     movel   #0x1,%d0            //inst is forced single
0774     bras    frcovf_rnd
0775 frcovf_dbl:
0776     movel   #0x2,%d0            //inst is forced double
0777     bras    frcovf_rnd
0778 frcovf_fpcr:
0779     bfextu  FPCR_MODE(%a6){#0:#2},%d0   //inst not forced - use fpcr prec
0780 frcovf_rnd:
0781 
0782 // The 881/882 does not set inex2 for the following case, so the
0783 // line is commented out to be compatible with 881/882
0784 //  tst.b   %d0
0785 //  beq.b   frcovf_x
0786 //  or.l    #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
0787 
0788 //frcovf_x:
0789     bsrl    ovf_res         //get correct result based on
0790 //                  ;round precision/mode.  This
0791 //                  ;sets FPSR_CC correctly
0792 //                  ;returns in external format
0793     bfclr   WBTEMP_SGN(%a6){#0:#8}
0794     beq frcfpn
0795     bsetb   #sign_bit,WBTEMP_EX(%a6)
0796     bra frcfpn
0797 //
0798 // Inst is fadd.
0799 //
0800 wrap_add:
0801     cmpb    #0xff,DNRM_FLG(%a6) //if both ops denorm,
0802     beq fix_stk      //restore to fpu
0803 //
0804 // One of the ops is denormalized.  Test for wrap condition
0805 // and complete the instruction.
0806 //
0807     cmpb    #0x0f,DNRM_FLG(%a6) //check for dest denorm
0808     bnes    add_srcd
0809 add_destd:
0810     bsrl    ckinf_ns
0811     bne fix_stk
0812     bfextu  ETEMP_EX(%a6){#1:#15},%d0   //get src exp (always pos)
0813     bfexts  FPTEMP_EX(%a6){#1:#15},%d1  //get dest exp (always neg)
0814     subl    %d1,%d0         //subtract dest from src
0815     cmpl    #0x8000,%d0
0816     blt fix_stk         //if less, not wrap case
0817     bra add_wrap
0818 add_srcd:
0819     bsrl    ckinf_nd
0820     bne fix_stk
0821     bfextu  FPTEMP_EX(%a6){#1:#15},%d0  //get dest exp (always pos)
0822     bfexts  ETEMP_EX(%a6){#1:#15},%d1   //get src exp (always neg)
0823     subl    %d1,%d0         //subtract src from dest
0824     cmpl    #0x8000,%d0
0825     blt fix_stk         //if less, not wrap case
0826 //
0827 // Check the signs of the operands.  If they are unlike, the fpu
0828 // can be used to add the norm and 1.0 with the sign of the
0829 // denorm and it will correctly generate the result in extended
0830 // precision.  We can then call round with no sticky and the result
0831 // will be correct for the user's rounding mode and precision.  If
0832 // the signs are the same, we call round with the sticky bit set
0833 // and the result will be correct for the user's rounding mode and
0834 // precision.
0835 //
0836 add_wrap:
0837     movew   ETEMP_EX(%a6),%d0
0838     movew   FPTEMP_EX(%a6),%d1
0839     eorw    %d1,%d0
0840     andiw   #0x8000,%d0
0841     beq add_same
0842 //
0843 // The signs are unlike.
0844 //
0845     cmpb    #0x0f,DNRM_FLG(%a6) //is dest the denorm?
0846     bnes    add_u_srcd
0847     movew   FPTEMP_EX(%a6),%d0
0848     andiw   #0x8000,%d0
0849     orw #0x3fff,%d0 //force the exponent to +/- 1
0850     movew   %d0,FPTEMP_EX(%a6) //in the denorm
0851     movel   USER_FPCR(%a6),%d0
0852     andil   #0x30,%d0
0853     fmovel  %d0,%fpcr       //set up users rmode and X
0854     fmovex  ETEMP(%a6),%fp0
0855     faddx   FPTEMP(%a6),%fp0
0856     leal    WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
0857     fmovel  %fpsr,%d1
0858     orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
0859     fmovex  %fp0,WBTEMP(%a6)    //write result to memory
0860     lsrl    #4,%d0      //put rmode in lower 2 bits
0861     movel   USER_FPCR(%a6),%d1
0862     andil   #0xc0,%d1
0863     lsrl    #6,%d1      //put precision in upper word
0864     swap    %d1
0865     orl %d0,%d1     //set up for round call
0866     clrl    %d0     //force sticky to zero
0867     bclrb   #sign_bit,WBTEMP_EX(%a6)
0868     sne WBTEMP_SGN(%a6)
0869     bsrl    round       //round result to users rmode & prec
0870     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
0871     beq frcfpnr
0872     bsetb   #sign_bit,WBTEMP_EX(%a6)
0873     bra frcfpnr
0874 add_u_srcd:
0875     movew   ETEMP_EX(%a6),%d0
0876     andiw   #0x8000,%d0
0877     orw #0x3fff,%d0 //force the exponent to +/- 1
0878     movew   %d0,ETEMP_EX(%a6) //in the denorm
0879     movel   USER_FPCR(%a6),%d0
0880     andil   #0x30,%d0
0881     fmovel  %d0,%fpcr       //set up users rmode and X
0882     fmovex  ETEMP(%a6),%fp0
0883     faddx   FPTEMP(%a6),%fp0
0884     fmovel  %fpsr,%d1
0885     orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
0886     leal    WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
0887     fmovex  %fp0,WBTEMP(%a6)    //write result to memory
0888     lsrl    #4,%d0      //put rmode in lower 2 bits
0889     movel   USER_FPCR(%a6),%d1
0890     andil   #0xc0,%d1
0891     lsrl    #6,%d1      //put precision in upper word
0892     swap    %d1
0893     orl %d0,%d1     //set up for round call
0894     clrl    %d0     //force sticky to zero
0895     bclrb   #sign_bit,WBTEMP_EX(%a6)
0896     sne WBTEMP_SGN(%a6) //use internal format for round
0897     bsrl    round       //round result to users rmode & prec
0898     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
0899     beq frcfpnr
0900     bsetb   #sign_bit,WBTEMP_EX(%a6)
0901     bra frcfpnr
0902 //
0903 // Signs are alike:
0904 //
0905 add_same:
0906     cmpb    #0x0f,DNRM_FLG(%a6) //is dest the denorm?
0907     bnes    add_s_srcd
0908 add_s_destd:
0909     leal    ETEMP(%a6),%a0
0910     movel   USER_FPCR(%a6),%d0
0911     andil   #0x30,%d0
0912     lsrl    #4,%d0      //put rmode in lower 2 bits
0913     movel   USER_FPCR(%a6),%d1
0914     andil   #0xc0,%d1
0915     lsrl    #6,%d1      //put precision in upper word
0916     swap    %d1
0917     orl %d0,%d1     //set up for round call
0918     movel   #0x20000000,%d0 //set sticky for round
0919     bclrb   #sign_bit,ETEMP_EX(%a6)
0920     sne ETEMP_SGN(%a6)
0921     bsrl    round       //round result to users rmode & prec
0922     bfclr   ETEMP_SGN(%a6){#0:#8}   //convert back to IEEE ext format
0923     beqs    add_s_dclr
0924     bsetb   #sign_bit,ETEMP_EX(%a6)
0925 add_s_dclr:
0926     leal    WBTEMP(%a6),%a0
0927     movel   ETEMP(%a6),(%a0)    //write result to wbtemp
0928     movel   ETEMP_HI(%a6),4(%a0)
0929     movel   ETEMP_LO(%a6),8(%a0)
0930     tstw    ETEMP_EX(%a6)
0931     bgt add_ckovf
0932     orl #neg_mask,USER_FPSR(%a6)
0933     bra add_ckovf
0934 add_s_srcd:
0935     leal    FPTEMP(%a6),%a0
0936     movel   USER_FPCR(%a6),%d0
0937     andil   #0x30,%d0
0938     lsrl    #4,%d0      //put rmode in lower 2 bits
0939     movel   USER_FPCR(%a6),%d1
0940     andil   #0xc0,%d1
0941     lsrl    #6,%d1      //put precision in upper word
0942     swap    %d1
0943     orl %d0,%d1     //set up for round call
0944     movel   #0x20000000,%d0 //set sticky for round
0945     bclrb   #sign_bit,FPTEMP_EX(%a6)
0946     sne FPTEMP_SGN(%a6)
0947     bsrl    round       //round result to users rmode & prec
0948     bfclr   FPTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
0949     beqs    add_s_sclr
0950     bsetb   #sign_bit,FPTEMP_EX(%a6)
0951 add_s_sclr:
0952     leal    WBTEMP(%a6),%a0
0953     movel   FPTEMP(%a6),(%a0)   //write result to wbtemp
0954     movel   FPTEMP_HI(%a6),4(%a0)
0955     movel   FPTEMP_LO(%a6),8(%a0)
0956     tstw    FPTEMP_EX(%a6)
0957     bgt add_ckovf
0958     orl #neg_mask,USER_FPSR(%a6)
0959 add_ckovf:
0960     movew   WBTEMP_EX(%a6),%d0
0961     andiw   #0x7fff,%d0
0962     cmpiw   #0x7fff,%d0
0963     bne frcfpnr
0964 //
0965 // The result has overflowed to $7fff exponent.  Set I, ovfl,
0966 // and aovfl, and clr the mantissa (incorrectly set by the
0967 // round routine.)
0968 //
0969     orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
0970     clrl    4(%a0)
0971     bra frcfpnr
0972 //
0973 // Inst is fsub.
0974 //
0975 wrap_sub:
0976     cmpb    #0xff,DNRM_FLG(%a6) //if both ops denorm,
0977     beq fix_stk      //restore to fpu
0978 //
0979 // One of the ops is denormalized.  Test for wrap condition
0980 // and complete the instruction.
0981 //
0982     cmpb    #0x0f,DNRM_FLG(%a6) //check for dest denorm
0983     bnes    sub_srcd
0984 sub_destd:
0985     bsrl    ckinf_ns
0986     bne fix_stk
0987     bfextu  ETEMP_EX(%a6){#1:#15},%d0   //get src exp (always pos)
0988     bfexts  FPTEMP_EX(%a6){#1:#15},%d1  //get dest exp (always neg)
0989     subl    %d1,%d0         //subtract src from dest
0990     cmpl    #0x8000,%d0
0991     blt fix_stk         //if less, not wrap case
0992     bra sub_wrap
0993 sub_srcd:
0994     bsrl    ckinf_nd
0995     bne fix_stk
0996     bfextu  FPTEMP_EX(%a6){#1:#15},%d0  //get dest exp (always pos)
0997     bfexts  ETEMP_EX(%a6){#1:#15},%d1   //get src exp (always neg)
0998     subl    %d1,%d0         //subtract dest from src
0999     cmpl    #0x8000,%d0
1000     blt fix_stk         //if less, not wrap case
1001 //
1002 // Check the signs of the operands.  If they are alike, the fpu
1003 // can be used to subtract from the norm 1.0 with the sign of the
1004 // denorm and it will correctly generate the result in extended
1005 // precision.  We can then call round with no sticky and the result
1006 // will be correct for the user's rounding mode and precision.  If
1007 // the signs are unlike, we call round with the sticky bit set
1008 // and the result will be correct for the user's rounding mode and
1009 // precision.
1010 //
1011 sub_wrap:
1012     movew   ETEMP_EX(%a6),%d0
1013     movew   FPTEMP_EX(%a6),%d1
1014     eorw    %d1,%d0
1015     andiw   #0x8000,%d0
1016     bne sub_diff
1017 //
1018 // The signs are alike.
1019 //
1020     cmpb    #0x0f,DNRM_FLG(%a6) //is dest the denorm?
1021     bnes    sub_u_srcd
1022     movew   FPTEMP_EX(%a6),%d0
1023     andiw   #0x8000,%d0
1024     orw #0x3fff,%d0 //force the exponent to +/- 1
1025     movew   %d0,FPTEMP_EX(%a6) //in the denorm
1026     movel   USER_FPCR(%a6),%d0
1027     andil   #0x30,%d0
1028     fmovel  %d0,%fpcr       //set up users rmode and X
1029     fmovex  FPTEMP(%a6),%fp0
1030     fsubx   ETEMP(%a6),%fp0
1031     fmovel  %fpsr,%d1
1032     orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
1033     leal    WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
1034     fmovex  %fp0,WBTEMP(%a6)    //write result to memory
1035     lsrl    #4,%d0      //put rmode in lower 2 bits
1036     movel   USER_FPCR(%a6),%d1
1037     andil   #0xc0,%d1
1038     lsrl    #6,%d1      //put precision in upper word
1039     swap    %d1
1040     orl %d0,%d1     //set up for round call
1041     clrl    %d0     //force sticky to zero
1042     bclrb   #sign_bit,WBTEMP_EX(%a6)
1043     sne WBTEMP_SGN(%a6)
1044     bsrl    round       //round result to users rmode & prec
1045     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
1046     beq frcfpnr
1047     bsetb   #sign_bit,WBTEMP_EX(%a6)
1048     bra frcfpnr
1049 sub_u_srcd:
1050     movew   ETEMP_EX(%a6),%d0
1051     andiw   #0x8000,%d0
1052     orw #0x3fff,%d0 //force the exponent to +/- 1
1053     movew   %d0,ETEMP_EX(%a6) //in the denorm
1054     movel   USER_FPCR(%a6),%d0
1055     andil   #0x30,%d0
1056     fmovel  %d0,%fpcr       //set up users rmode and X
1057     fmovex  FPTEMP(%a6),%fp0
1058     fsubx   ETEMP(%a6),%fp0
1059     fmovel  %fpsr,%d1
1060     orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
1061     leal    WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
1062     fmovex  %fp0,WBTEMP(%a6)    //write result to memory
1063     lsrl    #4,%d0      //put rmode in lower 2 bits
1064     movel   USER_FPCR(%a6),%d1
1065     andil   #0xc0,%d1
1066     lsrl    #6,%d1      //put precision in upper word
1067     swap    %d1
1068     orl %d0,%d1     //set up for round call
1069     clrl    %d0     //force sticky to zero
1070     bclrb   #sign_bit,WBTEMP_EX(%a6)
1071     sne WBTEMP_SGN(%a6)
1072     bsrl    round       //round result to users rmode & prec
1073     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
1074     beq frcfpnr
1075     bsetb   #sign_bit,WBTEMP_EX(%a6)
1076     bra frcfpnr
1077 //
1078 // Signs are unlike:
1079 //
1080 sub_diff:
1081     cmpb    #0x0f,DNRM_FLG(%a6) //is dest the denorm?
1082     bnes    sub_s_srcd
1083 sub_s_destd:
1084     leal    ETEMP(%a6),%a0
1085     movel   USER_FPCR(%a6),%d0
1086     andil   #0x30,%d0
1087     lsrl    #4,%d0      //put rmode in lower 2 bits
1088     movel   USER_FPCR(%a6),%d1
1089     andil   #0xc0,%d1
1090     lsrl    #6,%d1      //put precision in upper word
1091     swap    %d1
1092     orl %d0,%d1     //set up for round call
1093     movel   #0x20000000,%d0 //set sticky for round
1094 //
1095 // Since the dest is the denorm, the sign is the opposite of the
1096 // norm sign.
1097 //
1098     eoriw   #0x8000,ETEMP_EX(%a6)   //flip sign on result
1099     tstw    ETEMP_EX(%a6)
1100     bgts    sub_s_dwr
1101     orl #neg_mask,USER_FPSR(%a6)
1102 sub_s_dwr:
1103     bclrb   #sign_bit,ETEMP_EX(%a6)
1104     sne ETEMP_SGN(%a6)
1105     bsrl    round       //round result to users rmode & prec
1106     bfclr   ETEMP_SGN(%a6){#0:#8}   //convert back to IEEE ext format
1107     beqs    sub_s_dclr
1108     bsetb   #sign_bit,ETEMP_EX(%a6)
1109 sub_s_dclr:
1110     leal    WBTEMP(%a6),%a0
1111     movel   ETEMP(%a6),(%a0)    //write result to wbtemp
1112     movel   ETEMP_HI(%a6),4(%a0)
1113     movel   ETEMP_LO(%a6),8(%a0)
1114     bra sub_ckovf
1115 sub_s_srcd:
1116     leal    FPTEMP(%a6),%a0
1117     movel   USER_FPCR(%a6),%d0
1118     andil   #0x30,%d0
1119     lsrl    #4,%d0      //put rmode in lower 2 bits
1120     movel   USER_FPCR(%a6),%d1
1121     andil   #0xc0,%d1
1122     lsrl    #6,%d1      //put precision in upper word
1123     swap    %d1
1124     orl %d0,%d1     //set up for round call
1125     movel   #0x20000000,%d0 //set sticky for round
1126     bclrb   #sign_bit,FPTEMP_EX(%a6)
1127     sne FPTEMP_SGN(%a6)
1128     bsrl    round       //round result to users rmode & prec
1129     bfclr   FPTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
1130     beqs    sub_s_sclr
1131     bsetb   #sign_bit,FPTEMP_EX(%a6)
1132 sub_s_sclr:
1133     leal    WBTEMP(%a6),%a0
1134     movel   FPTEMP(%a6),(%a0)   //write result to wbtemp
1135     movel   FPTEMP_HI(%a6),4(%a0)
1136     movel   FPTEMP_LO(%a6),8(%a0)
1137     tstw    FPTEMP_EX(%a6)
1138     bgt sub_ckovf
1139     orl #neg_mask,USER_FPSR(%a6)
1140 sub_ckovf:
1141     movew   WBTEMP_EX(%a6),%d0
1142     andiw   #0x7fff,%d0
1143     cmpiw   #0x7fff,%d0
1144     bne frcfpnr
1145 //
1146 // The result has overflowed to $7fff exponent.  Set I, ovfl,
1147 // and aovfl, and clr the mantissa (incorrectly set by the
1148 // round routine.)
1149 //
1150     orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1151     clrl    4(%a0)
1152     bra frcfpnr
1153 //
1154 // Inst is fcmp.
1155 //
1156 wrap_cmp:
1157     cmpb    #0xff,DNRM_FLG(%a6) //if both ops denorm,
1158     beq fix_stk      //restore to fpu
1159 //
1160 // One of the ops is denormalized.  Test for wrap condition
1161 // and complete the instruction.
1162 //
1163     cmpb    #0x0f,DNRM_FLG(%a6) //check for dest denorm
1164     bnes    cmp_srcd
1165 cmp_destd:
1166     bsrl    ckinf_ns
1167     bne fix_stk
1168     bfextu  ETEMP_EX(%a6){#1:#15},%d0   //get src exp (always pos)
1169     bfexts  FPTEMP_EX(%a6){#1:#15},%d1  //get dest exp (always neg)
1170     subl    %d1,%d0         //subtract dest from src
1171     cmpl    #0x8000,%d0
1172     blt fix_stk         //if less, not wrap case
1173     tstw    ETEMP_EX(%a6)       //set N to ~sign_of(src)
1174     bge cmp_setn
1175     rts
1176 cmp_srcd:
1177     bsrl    ckinf_nd
1178     bne fix_stk
1179     bfextu  FPTEMP_EX(%a6){#1:#15},%d0  //get dest exp (always pos)
1180     bfexts  ETEMP_EX(%a6){#1:#15},%d1   //get src exp (always neg)
1181     subl    %d1,%d0         //subtract src from dest
1182     cmpl    #0x8000,%d0
1183     blt fix_stk         //if less, not wrap case
1184     tstw    FPTEMP_EX(%a6)      //set N to sign_of(dest)
1185     blt cmp_setn
1186     rts
1187 cmp_setn:
1188     orl #neg_mask,USER_FPSR(%a6)
1189     rts
1190 
1191 //
1192 // Inst is fmul.
1193 //
1194 wrap_mul:
1195     cmpb    #0xff,DNRM_FLG(%a6) //if both ops denorm,
1196     beq force_unf   //force an underflow (really!)
1197 //
1198 // One of the ops is denormalized.  Test for wrap condition
1199 // and complete the instruction.
1200 //
1201     cmpb    #0x0f,DNRM_FLG(%a6) //check for dest denorm
1202     bnes    mul_srcd
1203 mul_destd:
1204     bsrl    ckinf_ns
1205     bne fix_stk
1206     bfextu  ETEMP_EX(%a6){#1:#15},%d0   //get src exp (always pos)
1207     bfexts  FPTEMP_EX(%a6){#1:#15},%d1  //get dest exp (always neg)
1208     addl    %d1,%d0         //subtract dest from src
1209     bgt fix_stk
1210     bra force_unf
1211 mul_srcd:
1212     bsrl    ckinf_nd
1213     bne fix_stk
1214     bfextu  FPTEMP_EX(%a6){#1:#15},%d0  //get dest exp (always pos)
1215     bfexts  ETEMP_EX(%a6){#1:#15},%d1   //get src exp (always neg)
1216     addl    %d1,%d0         //subtract src from dest
1217     bgt fix_stk
1218 
1219 //
1220 // This code handles the case of the instruction resulting in
1221 // an underflow condition.
1222 //
1223 force_unf:
1224     bclrb   #E1,E_BYTE(%a6)
1225     orl #unfinx_mask,USER_FPSR(%a6)
1226     clrw    NMNEXC(%a6)
1227     clrb    WBTEMP_SGN(%a6)
1228     movew   ETEMP_EX(%a6),%d0       //find the sign of the result
1229     movew   FPTEMP_EX(%a6),%d1
1230     eorw    %d1,%d0
1231     andiw   #0x8000,%d0
1232     beqs    frcunfcont
1233     st  WBTEMP_SGN(%a6)
1234 frcunfcont:
1235     lea WBTEMP(%a6),%a0     //point a0 to memory location
1236     movew   CMDREG1B(%a6),%d0
1237     btstl   #6,%d0          //test for forced precision
1238     beqs    frcunf_fpcr
1239     btstl   #2,%d0          //check for double
1240     bnes    frcunf_dbl
1241     movel   #0x1,%d0            //inst is forced single
1242     bras    frcunf_rnd
1243 frcunf_dbl:
1244     movel   #0x2,%d0            //inst is forced double
1245     bras    frcunf_rnd
1246 frcunf_fpcr:
1247     bfextu  FPCR_MODE(%a6){#0:#2},%d0   //inst not forced - use fpcr prec
1248 frcunf_rnd:
1249     bsrl    unf_sub         //get correct result based on
1250 //                  ;round precision/mode.  This
1251 //                  ;sets FPSR_CC correctly
1252     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
1253     beqs    frcfpn
1254     bsetb   #sign_bit,WBTEMP_EX(%a6)
1255     bra frcfpn
1256 
1257 //
1258 // Write the result to the user's fpn.  All results must be HUGE to be
1259 // written; otherwise the results would have overflowed or underflowed.
1260 // If the rounding precision is single or double, the ovf_res routine
1261 // is needed to correctly supply the max value.
1262 //
1263 frcfpnr:
1264     movew   CMDREG1B(%a6),%d0
1265     btstl   #6,%d0          //test for forced precision
1266     beqs    frcfpn_fpcr
1267     btstl   #2,%d0          //check for double
1268     bnes    frcfpn_dbl
1269     movel   #0x1,%d0            //inst is forced single
1270     bras    frcfpn_rnd
1271 frcfpn_dbl:
1272     movel   #0x2,%d0            //inst is forced double
1273     bras    frcfpn_rnd
1274 frcfpn_fpcr:
1275     bfextu  FPCR_MODE(%a6){#0:#2},%d0   //inst not forced - use fpcr prec
1276     tstb    %d0
1277     beqs    frcfpn          //if extended, write what you got
1278 frcfpn_rnd:
1279     bclrb   #sign_bit,WBTEMP_EX(%a6)
1280     sne WBTEMP_SGN(%a6)
1281     bsrl    ovf_res         //get correct result based on
1282 //                  ;round precision/mode.  This
1283 //                  ;sets FPSR_CC correctly
1284     bfclr   WBTEMP_SGN(%a6){#0:#8}  //convert back to IEEE ext format
1285     beqs    frcfpn_clr
1286     bsetb   #sign_bit,WBTEMP_EX(%a6)
1287 frcfpn_clr:
1288     orl #ovfinx_mask,USER_FPSR(%a6)
1289 //
1290 // Perform the write.
1291 //
1292 frcfpn:
1293     bfextu  CMDREG1B(%a6){#6:#3},%d0    //extract fp destination register
1294     cmpib   #3,%d0
1295     bles    frc0123         //check if dest is fp0-fp3
1296     movel   #7,%d1
1297     subl    %d0,%d1
1298     clrl    %d0
1299     bsetl   %d1,%d0
1300     fmovemx WBTEMP(%a6),%d0
1301     rts
1302 frc0123:
1303     cmpib   #0,%d0
1304     beqs    frc0_dst
1305     cmpib   #1,%d0
1306     beqs    frc1_dst
1307     cmpib   #2,%d0
1308     beqs    frc2_dst
1309 frc3_dst:
1310     movel   WBTEMP_EX(%a6),USER_FP3(%a6)
1311     movel   WBTEMP_HI(%a6),USER_FP3+4(%a6)
1312     movel   WBTEMP_LO(%a6),USER_FP3+8(%a6)
1313     rts
1314 frc2_dst:
1315     movel   WBTEMP_EX(%a6),USER_FP2(%a6)
1316     movel   WBTEMP_HI(%a6),USER_FP2+4(%a6)
1317     movel   WBTEMP_LO(%a6),USER_FP2+8(%a6)
1318     rts
1319 frc1_dst:
1320     movel   WBTEMP_EX(%a6),USER_FP1(%a6)
1321     movel   WBTEMP_HI(%a6),USER_FP1+4(%a6)
1322     movel   WBTEMP_LO(%a6),USER_FP1+8(%a6)
1323     rts
1324 frc0_dst:
1325     movel   WBTEMP_EX(%a6),USER_FP0(%a6)
1326     movel   WBTEMP_HI(%a6),USER_FP0+4(%a6)
1327     movel   WBTEMP_LO(%a6),USER_FP0+8(%a6)
1328     rts
1329 
1330 //
1331 // Write etemp to fpn.
1332 // A check is made on enabled and signalled snan exceptions,
1333 // and the destination is not overwritten if this condition exists.
1334 // This code is designed to make fmoveins of unsupported data types
1335 // faster.
1336 //
1337 wr_etemp:
1338     btstb   #snan_bit,FPSR_EXCEPT(%a6)  //if snan is set, and
1339     beqs    fmoveinc        //enabled, force restore
1340     btstb   #snan_bit,FPCR_ENABLE(%a6) //and don't overwrite
1341     beqs    fmoveinc        //the dest
1342     movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    //set up fptemp sign for
1343 //                      ;snan handler
1344     tstb    ETEMP(%a6)      //check for negative
1345     blts    snan_neg
1346     rts
1347 snan_neg:
1348     orl #neg_bit,USER_FPSR(%a6) //snan is negative; set N
1349     rts
1350 fmoveinc:
1351     clrw    NMNEXC(%a6)
1352     bclrb   #E1,E_BYTE(%a6)
1353     moveb   STAG(%a6),%d0       //check if stag is inf
1354     andib   #0xe0,%d0
1355     cmpib   #0x40,%d0
1356     bnes    fminc_cnan
1357     orl #inf_mask,USER_FPSR(%a6) //if inf, nothing yet has set I
1358     tstw    LOCAL_EX(%a0)       //check sign
1359     bges    fminc_con
1360     orl #neg_mask,USER_FPSR(%a6)
1361     bra fminc_con
1362 fminc_cnan:
1363     cmpib   #0x60,%d0           //check if stag is NaN
1364     bnes    fminc_czero
1365     orl #nan_mask,USER_FPSR(%a6) //if nan, nothing yet has set NaN
1366     movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    //set up fptemp sign for
1367 //                      ;snan handler
1368     tstw    LOCAL_EX(%a0)       //check sign
1369     bges    fminc_con
1370     orl #neg_mask,USER_FPSR(%a6)
1371     bra fminc_con
1372 fminc_czero:
1373     cmpib   #0x20,%d0           //check if zero
1374     bnes    fminc_con
1375     orl #z_mask,USER_FPSR(%a6)  //if zero, set Z
1376     tstw    LOCAL_EX(%a0)       //check sign
1377     bges    fminc_con
1378     orl #neg_mask,USER_FPSR(%a6)
1379 fminc_con:
1380     bfextu  CMDREG1B(%a6){#6:#3},%d0    //extract fp destination register
1381     cmpib   #3,%d0
1382     bles    fp0123          //check if dest is fp0-fp3
1383     movel   #7,%d1
1384     subl    %d0,%d1
1385     clrl    %d0
1386     bsetl   %d1,%d0
1387     fmovemx ETEMP(%a6),%d0
1388     rts
1389 
1390 fp0123:
1391     cmpib   #0,%d0
1392     beqs    fp0_dst
1393     cmpib   #1,%d0
1394     beqs    fp1_dst
1395     cmpib   #2,%d0
1396     beqs    fp2_dst
1397 fp3_dst:
1398     movel   ETEMP_EX(%a6),USER_FP3(%a6)
1399     movel   ETEMP_HI(%a6),USER_FP3+4(%a6)
1400     movel   ETEMP_LO(%a6),USER_FP3+8(%a6)
1401     rts
1402 fp2_dst:
1403     movel   ETEMP_EX(%a6),USER_FP2(%a6)
1404     movel   ETEMP_HI(%a6),USER_FP2+4(%a6)
1405     movel   ETEMP_LO(%a6),USER_FP2+8(%a6)
1406     rts
1407 fp1_dst:
1408     movel   ETEMP_EX(%a6),USER_FP1(%a6)
1409     movel   ETEMP_HI(%a6),USER_FP1+4(%a6)
1410     movel   ETEMP_LO(%a6),USER_FP1+8(%a6)
1411     rts
1412 fp0_dst:
1413     movel   ETEMP_EX(%a6),USER_FP0(%a6)
1414     movel   ETEMP_HI(%a6),USER_FP0+4(%a6)
1415     movel   ETEMP_LO(%a6),USER_FP0+8(%a6)
1416     rts
1417 
1418 opclass3:
1419     st  CU_ONLY(%a6)
1420     movew   CMDREG1B(%a6),%d0   //check if packed moveout
1421     andiw   #0x0c00,%d0 //isolate last 2 bits of size field
1422     cmpiw   #0x0c00,%d0 //if size is 011 or 111, it is packed
1423     beq pack_out    //else it is norm or denorm
1424     bra mv_out
1425 
1426 
1427 //
1428 //  MOVE OUT
1429 //
1430 
1431 mv_tbl:
1432     .long   li
1433     .long   sgp
1434     .long   xp
1435     .long   mvout_end   //should never be taken
1436     .long   wi
1437     .long   dp
1438     .long   bi
1439     .long   mvout_end   //should never be taken
1440 mv_out:
1441     bfextu  CMDREG1B(%a6){#3:#3},%d1    //put source specifier in d1
1442     leal    mv_tbl,%a0
1443     movel   %a0@(%d1:l:4),%a0
1444     jmp (%a0)
1445 
1446 //
1447 // This exit is for move-out to memory.  The aunfl bit is
1448 // set if the result is inex and unfl is signalled.
1449 //
1450 mvout_end:
1451     btstb   #inex2_bit,FPSR_EXCEPT(%a6)
1452     beqs    no_aufl
1453     btstb   #unfl_bit,FPSR_EXCEPT(%a6)
1454     beqs    no_aufl
1455     bsetb   #aunfl_bit,FPSR_AEXCEPT(%a6)
1456 no_aufl:
1457     clrw    NMNEXC(%a6)
1458     bclrb   #E1,E_BYTE(%a6)
1459     fmovel  #0,%FPSR            //clear any cc bits from res_func
1460 //
1461 // Return ETEMP to extended format from internal extended format so
1462 // that gen_except will have a correctly signed value for ovfl/unfl
1463 // handlers.
1464 //
1465     bfclr   ETEMP_SGN(%a6){#0:#8}
1466     beqs    mvout_con
1467     bsetb   #sign_bit,ETEMP_EX(%a6)
1468 mvout_con:
1469     rts
1470 //
1471 // This exit is for move-out to int register.  The aunfl bit is
1472 // not set in any case for this move.
1473 //
1474 mvouti_end:
1475     clrw    NMNEXC(%a6)
1476     bclrb   #E1,E_BYTE(%a6)
1477     fmovel  #0,%FPSR            //clear any cc bits from res_func
1478 //
1479 // Return ETEMP to extended format from internal extended format so
1480 // that gen_except will have a correctly signed value for ovfl/unfl
1481 // handlers.
1482 //
1483     bfclr   ETEMP_SGN(%a6){#0:#8}
1484     beqs    mvouti_con
1485     bsetb   #sign_bit,ETEMP_EX(%a6)
1486 mvouti_con:
1487     rts
1488 //
1489 // li is used to handle a long integer source specifier
1490 //
1491 
1492 li:
1493     moveql  #4,%d0      //set byte count
1494 
1495     btstb   #7,STAG(%a6)    //check for extended denorm
1496     bne int_dnrm    //if so, branch
1497 
1498     fmovemx ETEMP(%a6),%fp0-%fp0
1499     fcmpd   #0x41dfffffffc00000,%fp0
1500 // 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1501     fbge    lo_plrg
1502     fcmpd   #0xc1e0000000000000,%fp0
1503 // c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1504     fble    lo_nlrg
1505 //
1506 // at this point, the answer is between the largest pos and neg values
1507 //
1508     movel   USER_FPCR(%a6),%d1  //use user's rounding mode
1509     andil   #0x30,%d1
1510     fmovel  %d1,%fpcr
1511     fmovel  %fp0,L_SCR1(%a6)    //let the 040 perform conversion
1512     fmovel %fpsr,%d1
1513     orl %d1,USER_FPSR(%a6)  //capture inex2/ainex if set
1514     bra int_wrt
1515 
1516 
1517 lo_plrg:
1518     movel   #0x7fffffff,L_SCR1(%a6) //answer is largest positive int
1519     fbeq    int_wrt         //exact answer
1520     fcmpd   #0x41dfffffffe00000,%fp0
1521 // 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1522     fbge    int_operr       //set operr
1523     bra int_inx         //set inexact
1524 
1525 lo_nlrg:
1526     movel   #0x80000000,L_SCR1(%a6)
1527     fbeq    int_wrt         //exact answer
1528     fcmpd   #0xc1e0000000100000,%fp0
1529 // c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1530     fblt    int_operr       //set operr
1531     bra int_inx         //set inexact
1532 
1533 //
1534 // wi is used to handle a word integer source specifier
1535 //
1536 
1537 wi:
1538     moveql  #2,%d0      //set byte count
1539 
1540     btstb   #7,STAG(%a6)    //check for extended denorm
1541     bne int_dnrm    //branch if so
1542 
1543     fmovemx ETEMP(%a6),%fp0-%fp0
1544     fcmps   #0x46fffe00,%fp0
1545 // 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1546     fbge    wo_plrg
1547     fcmps   #0xc7000000,%fp0
1548 // c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1549     fble    wo_nlrg
1550 
1551 //
1552 // at this point, the answer is between the largest pos and neg values
1553 //
1554     movel   USER_FPCR(%a6),%d1  //use user's rounding mode
1555     andil   #0x30,%d1
1556     fmovel  %d1,%fpcr
1557     fmovew  %fp0,L_SCR1(%a6)    //let the 040 perform conversion
1558     fmovel %fpsr,%d1
1559     orl %d1,USER_FPSR(%a6)  //capture inex2/ainex if set
1560     bra int_wrt
1561 
1562 wo_plrg:
1563     movew   #0x7fff,L_SCR1(%a6) //answer is largest positive int
1564     fbeq    int_wrt         //exact answer
1565     fcmps   #0x46ffff00,%fp0
1566 // 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1567     fbge    int_operr       //set operr
1568     bra int_inx         //set inexact
1569 
1570 wo_nlrg:
1571     movew   #0x8000,L_SCR1(%a6)
1572     fbeq    int_wrt         //exact answer
1573     fcmps   #0xc7000080,%fp0
1574 // c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1575     fblt    int_operr       //set operr
1576     bra int_inx         //set inexact
1577 
1578 //
1579 // bi is used to handle a byte integer source specifier
1580 //
1581 
1582 bi:
1583     moveql  #1,%d0      //set byte count
1584 
1585     btstb   #7,STAG(%a6)    //check for extended denorm
1586     bne int_dnrm    //branch if so
1587 
1588     fmovemx ETEMP(%a6),%fp0-%fp0
1589     fcmps   #0x42fe0000,%fp0
1590 // 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1591     fbge    by_plrg
1592     fcmps   #0xc3000000,%fp0
1593 // c3000000 in sgl prec = c00600008000000000000000 in ext prec
1594     fble    by_nlrg
1595 
1596 //
1597 // at this point, the answer is between the largest pos and neg values
1598 //
1599     movel   USER_FPCR(%a6),%d1  //use user's rounding mode
1600     andil   #0x30,%d1
1601     fmovel  %d1,%fpcr
1602     fmoveb  %fp0,L_SCR1(%a6)    //let the 040 perform conversion
1603     fmovel %fpsr,%d1
1604     orl %d1,USER_FPSR(%a6)  //capture inex2/ainex if set
1605     bra int_wrt
1606 
1607 by_plrg:
1608     moveb   #0x7f,L_SCR1(%a6)       //answer is largest positive int
1609     fbeq    int_wrt         //exact answer
1610     fcmps   #0x42ff0000,%fp0
1611 // 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1612     fbge    int_operr       //set operr
1613     bra int_inx         //set inexact
1614 
1615 by_nlrg:
1616     moveb   #0x80,L_SCR1(%a6)
1617     fbeq    int_wrt         //exact answer
1618     fcmps   #0xc3008000,%fp0
1619 // c3008000 in sgl prec = c00600008080000000000000 in ext prec
1620     fblt    int_operr       //set operr
1621     bra int_inx         //set inexact
1622 
1623 //
1624 // Common integer routines
1625 //
1626 // int_drnrm---account for possible nonzero result for round up with positive
1627 // operand and round down for negative answer.  In the first case (result = 1)
1628 // byte-width (store in d0) of result must be honored.  In the second case,
1629 // -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1630 
1631 int_dnrm:
1632     movel   #0,L_SCR1(%a6)  // initialize result to 0
1633     bfextu  FPCR_MODE(%a6){#2:#2},%d1   // d1 is the rounding mode
1634     cmpb    #2,%d1
1635     bmis    int_inx     // if RN or RZ, done
1636     bnes    int_rp      // if RP, continue below
1637     tstw    ETEMP(%a6)  // RM: store -1 in L_SCR1 if src is negative
1638     bpls    int_inx     // otherwise result is 0
1639     movel   #-1,L_SCR1(%a6)
1640     bras    int_inx
1641 int_rp:
1642     tstw    ETEMP(%a6)  // RP: store +1 of proper width in L_SCR1 if
1643 //              ; source is greater than 0
1644     bmis    int_inx     // otherwise, result is 0
1645     lea L_SCR1(%a6),%a1 // a1 is address of L_SCR1
1646     addal   %d0,%a1     // offset by destination width -1
1647     subal   #1,%a1
1648     bsetb   #0,(%a1)        // set low bit at a1 address
1649 int_inx:
1650     oril    #inx2a_mask,USER_FPSR(%a6)
1651     bras    int_wrt
1652 int_operr:
1653     fmovemx %fp0-%fp0,FPTEMP(%a6)   //FPTEMP must contain the extended
1654 //              ;precision source that needs to be
1655 //              ;converted to integer this is required
1656 //              ;if the operr exception is enabled.
1657 //              ;set operr/aiop (no inex2 on int ovfl)
1658 
1659     oril    #opaop_mask,USER_FPSR(%a6)
1660 //              ;fall through to perform int_wrt
1661 int_wrt:
1662     movel   EXC_EA(%a6),%a1 //load destination address
1663     tstl    %a1     //check to see if it is a dest register
1664     beqs    wrt_dn      //write data register
1665     lea L_SCR1(%a6),%a0 //point to supervisor source address
1666     bsrl    mem_write
1667     bra mvouti_end
1668 
1669 wrt_dn:
1670     movel   %d0,-(%sp)  //d0 currently contains the size to write
1671     bsrl    get_fline   //get_fline returns Dn in d0
1672     andiw   #0x7,%d0        //isolate register
1673     movel   (%sp)+,%d1  //get size
1674     cmpil   #4,%d1      //most frequent case
1675     beqs    sz_long
1676     cmpil   #2,%d1
1677     bnes    sz_con
1678     orl #8,%d0      //add 'word' size to register#
1679     bras    sz_con
1680 sz_long:
1681     orl #0x10,%d0       //add 'long' size to register#
1682 sz_con:
1683     movel   %d0,%d1     //reg_dest expects size:reg in d1
1684     bsrl    reg_dest    //load proper data register
1685     bra mvouti_end
1686 xp:
1687     lea ETEMP(%a6),%a0
1688     bclrb   #sign_bit,LOCAL_EX(%a0)
1689     sne LOCAL_SGN(%a0)
1690     btstb   #7,STAG(%a6)    //check for extended denorm
1691     bne xdnrm
1692     clrl    %d0
1693     bras    do_fp       //do normal case
1694 sgp:
1695     lea ETEMP(%a6),%a0
1696     bclrb   #sign_bit,LOCAL_EX(%a0)
1697     sne LOCAL_SGN(%a0)
1698     btstb   #7,STAG(%a6)    //check for extended denorm
1699     bne sp_catas    //branch if so
1700     movew   LOCAL_EX(%a0),%d0
1701     lea sp_bnds,%a1
1702     cmpw    (%a1),%d0
1703     blt sp_under
1704     cmpw    2(%a1),%d0
1705     bgt sp_over
1706     movel   #1,%d0      //set destination format to single
1707     bras    do_fp       //do normal case
1708 dp:
1709     lea ETEMP(%a6),%a0
1710     bclrb   #sign_bit,LOCAL_EX(%a0)
1711     sne LOCAL_SGN(%a0)
1712 
1713     btstb   #7,STAG(%a6)    //check for extended denorm
1714     bne dp_catas    //branch if so
1715 
1716     movew   LOCAL_EX(%a0),%d0
1717     lea dp_bnds,%a1
1718 
1719     cmpw    (%a1),%d0
1720     blt dp_under
1721     cmpw    2(%a1),%d0
1722     bgt dp_over
1723 
1724     movel   #2,%d0      //set destination format to double
1725 //              ;fall through to do_fp
1726 //
1727 do_fp:
1728     bfextu  FPCR_MODE(%a6){#2:#2},%d1   //rnd mode in d1
1729     swap    %d0         //rnd prec in upper word
1730     addl    %d0,%d1         //d1 has PREC/MODE info
1731 
1732     clrl    %d0         //clear g,r,s
1733 
1734     bsrl    round           //round
1735 
1736     movel   %a0,%a1
1737     movel   EXC_EA(%a6),%a0
1738 
1739     bfextu  CMDREG1B(%a6){#3:#3},%d1    //extract destination format
1740 //                  ;at this point only the dest
1741 //                  ;formats sgl, dbl, ext are
1742 //                  ;possible
1743     cmpb    #2,%d1
1744     bgts    ddbl            //double=5, extended=2, single=1
1745     bnes    dsgl
1746 //                  ;fall through to dext
1747 dext:
1748     bsrl    dest_ext
1749     bra mvout_end
1750 dsgl:
1751     bsrl    dest_sgl
1752     bra mvout_end
1753 ddbl:
1754     bsrl    dest_dbl
1755     bra mvout_end
1756 
1757 //
1758 // Handle possible denorm or catastrophic underflow cases here
1759 //
1760 xdnrm:
1761     bsr set_xop     //initialize WBTEMP
1762     bsetb   #wbtemp15_bit,WB_BYTE(%a6) //set wbtemp15
1763 
1764     movel   %a0,%a1
1765     movel   EXC_EA(%a6),%a0 //a0 has the destination pointer
1766     bsrl    dest_ext    //store to memory
1767     bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1768     bra mvout_end
1769 
1770 sp_under:
1771     bsetb   #etemp15_bit,STAG(%a6)
1772 
1773     cmpw    4(%a1),%d0
1774     blts    sp_catas    //catastrophic underflow case
1775 
1776     movel   #1,%d0      //load in round precision
1777     movel   #sgl_thresh,%d1 //load in single denorm threshold
1778     bsrl    dpspdnrm    //expects d1 to have the proper
1779 //              ;denorm threshold
1780     bsrl    dest_sgl    //stores value to destination
1781     bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1782     bra mvout_end   //exit
1783 
1784 dp_under:
1785     bsetb   #etemp15_bit,STAG(%a6)
1786 
1787     cmpw    4(%a1),%d0
1788     blts    dp_catas    //catastrophic underflow case
1789 
1790     movel   #dbl_thresh,%d1 //load in double precision threshold
1791     movel   #2,%d0
1792     bsrl    dpspdnrm    //expects d1 to have proper
1793 //              ;denorm threshold
1794 //              ;expects d0 to have round precision
1795     bsrl    dest_dbl    //store value to destination
1796     bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1797     bra mvout_end   //exit
1798 
1799 //
1800 // Handle catastrophic underflow cases here
1801 //
1802 sp_catas:
1803 // Temp fix for z bit set in unf_sub
1804     movel   USER_FPSR(%a6),-(%a7)
1805 
1806     movel   #1,%d0      //set round precision to sgl
1807 
1808     bsrl    unf_sub     //a0 points to result
1809 
1810     movel   (%a7)+,USER_FPSR(%a6)
1811 
1812     movel   #1,%d0
1813     subw    %d0,LOCAL_EX(%a0) //account for difference between
1814 //              ;denorm/norm bias
1815 
1816     movel   %a0,%a1     //a1 has the operand input
1817     movel   EXC_EA(%a6),%a0 //a0 has the destination pointer
1818 
1819     bsrl    dest_sgl    //store the result
1820     oril    #unfinx_mask,USER_FPSR(%a6)
1821     bra mvout_end
1822 
1823 dp_catas:
1824 // Temp fix for z bit set in unf_sub
1825     movel   USER_FPSR(%a6),-(%a7)
1826 
1827     movel   #2,%d0      //set round precision to dbl
1828     bsrl    unf_sub     //a0 points to result
1829 
1830     movel   (%a7)+,USER_FPSR(%a6)
1831 
1832     movel   #1,%d0
1833     subw    %d0,LOCAL_EX(%a0) //account for difference between
1834 //              ;denorm/norm bias
1835 
1836     movel   %a0,%a1     //a1 has the operand input
1837     movel   EXC_EA(%a6),%a0 //a0 has the destination pointer
1838 
1839     bsrl    dest_dbl    //store the result
1840     oril    #unfinx_mask,USER_FPSR(%a6)
1841     bra mvout_end
1842 
1843 //
1844 // Handle catastrophic overflow cases here
1845 //
1846 sp_over:
1847 // Temp fix for z bit set in unf_sub
1848     movel   USER_FPSR(%a6),-(%a7)
1849 
1850     movel   #1,%d0
1851     leal    FP_SCR1(%a6),%a0    //use FP_SCR1 for creating result
1852     movel   ETEMP_EX(%a6),(%a0)
1853     movel   ETEMP_HI(%a6),4(%a0)
1854     movel   ETEMP_LO(%a6),8(%a0)
1855     bsrl    ovf_res
1856 
1857     movel   (%a7)+,USER_FPSR(%a6)
1858 
1859     movel   %a0,%a1
1860     movel   EXC_EA(%a6),%a0
1861     bsrl    dest_sgl
1862     orl #ovfinx_mask,USER_FPSR(%a6)
1863     bra mvout_end
1864 
1865 dp_over:
1866 // Temp fix for z bit set in ovf_res
1867     movel   USER_FPSR(%a6),-(%a7)
1868 
1869     movel   #2,%d0
1870     leal    FP_SCR1(%a6),%a0    //use FP_SCR1 for creating result
1871     movel   ETEMP_EX(%a6),(%a0)
1872     movel   ETEMP_HI(%a6),4(%a0)
1873     movel   ETEMP_LO(%a6),8(%a0)
1874     bsrl    ovf_res
1875 
1876     movel   (%a7)+,USER_FPSR(%a6)
1877 
1878     movel   %a0,%a1
1879     movel   EXC_EA(%a6),%a0
1880     bsrl    dest_dbl
1881     orl #ovfinx_mask,USER_FPSR(%a6)
1882     bra mvout_end
1883 
1884 //
1885 //  DPSPDNRM
1886 //
1887 // This subroutine takes an extended normalized number and denormalizes
1888 // it to the given round precision. This subroutine also decrements
1889 // the input operand's exponent by 1 to account for the fact that
1890 // dest_sgl or dest_dbl expects a normalized number's bias.
1891 //
1892 // Input: a0  points to a normalized number in internal extended format
1893 //   d0  is the round precision (=1 for sgl; =2 for dbl)
1894 //   d1  is the the single precision or double precision
1895 //       denorm threshold
1896 //
1897 // Output: (In the format for dest_sgl or dest_dbl)
1898 //   a0   points to the destination
1899 //       a1   points to the operand
1900 //
1901 // Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1902 //
1903 dpspdnrm:
1904     movel   %d0,-(%a7)  //save round precision
1905     clrl    %d0     //clear initial g,r,s
1906     bsrl    dnrm_lp     //careful with d0, it's needed by round
1907 
1908     bfextu  FPCR_MODE(%a6){#2:#2},%d1 //get rounding mode
1909     swap    %d1
1910     movew   2(%a7),%d1  //set rounding precision
1911     swap    %d1     //at this point d1 has PREC/MODE info
1912     bsrl    round       //round result, sets the inex bit in
1913 //              ;USER_FPSR if needed
1914 
1915     movew   #1,%d0
1916     subw    %d0,LOCAL_EX(%a0) //account for difference in denorm
1917 //              ;vs norm bias
1918 
1919     movel   %a0,%a1     //a1 has the operand input
1920     movel   EXC_EA(%a6),%a0 //a0 has the destination pointer
1921     addw    #4,%a7      //pop stack
1922     rts
1923 //
1924 // SET_XOP initialized WBTEMP with the value pointed to by a0
1925 // input: a0 points to input operand in the internal extended format
1926 //
1927 set_xop:
1928     movel   LOCAL_EX(%a0),WBTEMP_EX(%a6)
1929     movel   LOCAL_HI(%a0),WBTEMP_HI(%a6)
1930     movel   LOCAL_LO(%a0),WBTEMP_LO(%a6)
1931     bfclr   WBTEMP_SGN(%a6){#0:#8}
1932     beqs    sxop
1933     bsetb   #sign_bit,WBTEMP_EX(%a6)
1934 sxop:
1935     bfclr   STAG(%a6){#5:#4}    //clear wbtm66,wbtm1,wbtm0,sbit
1936     rts
1937 //
1938 //  P_MOVE
1939 //
1940 p_movet:
1941     .long   p_move
1942     .long   p_movez
1943     .long   p_movei
1944     .long   p_moven
1945     .long   p_move
1946 p_regd:
1947     .long   p_dyd0
1948     .long   p_dyd1
1949     .long   p_dyd2
1950     .long   p_dyd3
1951     .long   p_dyd4
1952     .long   p_dyd5
1953     .long   p_dyd6
1954     .long   p_dyd7
1955 
1956 pack_out:
1957     leal    p_movet,%a0 //load jmp table address
1958     movew   STAG(%a6),%d0   //get source tag
1959     bfextu  %d0{#16:#3},%d0 //isolate source bits
1960     movel   (%a0,%d0.w*4),%a0   //load a0 with routine label for tag
1961     jmp (%a0)       //go to the routine
1962 
1963 p_write:
1964     movel   #0x0c,%d0   //get byte count
1965     movel   EXC_EA(%a6),%a1 //get the destination address
1966     bsr     mem_write   //write the user's destination
1967     moveb   #0,CU_SAVEPC(%a6) //set the cu save pc to all 0's
1968 
1969 //
1970 // Also note that the dtag must be set to norm here - this is because
1971 // the 040 uses the dtag to execute the correct microcode.
1972 //
1973         bfclr    DTAG(%a6){#0:#3}  //set dtag to norm
1974 
1975     rts
1976 
1977 // Notes on handling of special case (zero, inf, and nan) inputs:
1978 //  1. Operr is not signalled if the k-factor is greater than 18.
1979 //  2. Per the manual, status bits are not set.
1980 //
1981 
1982 p_move:
1983     movew   CMDREG1B(%a6),%d0
1984     btstl   #kfact_bit,%d0  //test for dynamic k-factor
1985     beqs    statick     //if clear, k-factor is static
1986 dynamick:
1987     bfextu  %d0{#25:#3},%d0 //isolate register for dynamic k-factor
1988     lea p_regd,%a0
1989     movel   %a0@(%d0:l:4),%a0
1990     jmp (%a0)
1991 statick:
1992     andiw   #0x007f,%d0 //get k-factor
1993     bfexts  %d0{#25:#7},%d0 //sign extend d0 for bindec
1994     leal    ETEMP(%a6),%a0  //a0 will point to the packed decimal
1995     bsrl    bindec      //perform the convert; data at a6
1996     leal    FP_SCR1(%a6),%a0    //load a0 with result address
1997     bral    p_write
1998 p_movez:
1999     leal    ETEMP(%a6),%a0  //a0 will point to the packed decimal
2000     clrw    2(%a0)      //clear lower word of exp
2001     clrl    4(%a0)      //load second lword of ZERO
2002     clrl    8(%a0)      //load third lword of ZERO
2003     bra p_write     //go write results
2004 p_movei:
2005     fmovel  #0,%FPSR        //clear aiop
2006     leal    ETEMP(%a6),%a0  //a0 will point to the packed decimal
2007     clrw    2(%a0)      //clear lower word of exp
2008     bra p_write     //go write the result
2009 p_moven:
2010     leal    ETEMP(%a6),%a0  //a0 will point to the packed decimal
2011     clrw    2(%a0)      //clear lower word of exp
2012     bra p_write     //go write the result
2013 
2014 //
2015 // Routines to read the dynamic k-factor from Dn.
2016 //
2017 p_dyd0:
2018     movel   USER_D0(%a6),%d0
2019     bras    statick
2020 p_dyd1:
2021     movel   USER_D1(%a6),%d0
2022     bras    statick
2023 p_dyd2:
2024     movel   %d2,%d0
2025     bras    statick
2026 p_dyd3:
2027     movel   %d3,%d0
2028     bras    statick
2029 p_dyd4:
2030     movel   %d4,%d0
2031     bras    statick
2032 p_dyd5:
2033     movel   %d5,%d0
2034     bras    statick
2035 p_dyd6:
2036     movel   %d6,%d0
2037     bra statick
2038 p_dyd7:
2039     movel   %d7,%d0
2040     bra statick
2041 
2042     |end