res_func.sa revision 1.1
11.1Smycroft* MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP 21.1Smycroft* M68000 Hi-Performance Microprocessor Division 31.1Smycroft* M68040 Software Package 41.1Smycroft* 51.1Smycroft* M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc. 61.1Smycroft* All rights reserved. 71.1Smycroft* 81.1Smycroft* THE SOFTWARE is provided on an "AS IS" basis and without warranty. 91.1Smycroft* To the maximum extent permitted by applicable law, 101.1Smycroft* MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 111.1Smycroft* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A 121.1Smycroft* PARTICULAR PURPOSE and any warranty against infringement with 131.1Smycroft* regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) 141.1Smycroft* and any accompanying written materials. 151.1Smycroft* 161.1Smycroft* To the maximum extent permitted by applicable law, 171.1Smycroft* IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER 181.1Smycroft* (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS 191.1Smycroft* PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR 201.1Smycroft* OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE 211.1Smycroft* SOFTWARE. Motorola assumes no responsibility for the maintenance 221.1Smycroft* and support of the SOFTWARE. 231.1Smycroft* 241.1Smycroft* You are hereby granted a copyright license to use, modify, and 251.1Smycroft* distribute the SOFTWARE so long as this entire notice is retained 261.1Smycroft* without alteration in any modified and/or redistributed versions, 271.1Smycroft* and that such modified versions are clearly identified as such. 281.1Smycroft* No licenses are granted by implication, estoppel or otherwise 291.1Smycroft* under any patents or trademarks of Motorola, Inc. 301.1Smycroft 311.1Smycroft* 321.1Smycroft* res_func.sa 3.9 7/29/91 331.1Smycroft* 341.1Smycroft* Normalizes denormalized numbers if necessary and updates the 351.1Smycroft* stack frame. The function is then restored back into the 361.1Smycroft* machine and the 040 completes the operation. This routine 371.1Smycroft* is only used by the unsupported data type/format handler. 381.1Smycroft* (Exception vector 55). 391.1Smycroft* 401.1Smycroft* For packed move out (fmove.p fpm,<ea>) the operation is 411.1Smycroft* completed here; data is packed and moved to user memory. 421.1Smycroft* The stack is restored to the 040 only in the case of a 431.1Smycroft* reportable exception in the conversion. 441.1Smycroft* 451.1Smycroft 461.1SmycroftRES_FUNC IDNT 2,1 Motorola 040 Floating Point Software Package 471.1Smycroft 481.1Smycroft section 8 491.1Smycroft 501.1Smycroft include fpsp.h 511.1Smycroft 521.1Smycroftsp_bnds: dc.w $3f81,$407e 531.1Smycroft dc.w $3f6a,$0000 541.1Smycroftdp_bnds: dc.w $3c01,$43fe 551.1Smycroft dc.w $3bcd,$0000 561.1Smycroft 571.1Smycroft xref mem_write 581.1Smycroft xref bindec 591.1Smycroft xref get_fline 601.1Smycroft xref round 611.1Smycroft xref denorm 621.1Smycroft xref dest_ext 631.1Smycroft xref dest_dbl 641.1Smycroft xref dest_sgl 651.1Smycroft xref unf_sub 661.1Smycroft xref nrm_set 671.1Smycroft xref dnrm_lp 681.1Smycroft xref ovf_res 691.1Smycroft xref reg_dest 701.1Smycroft xref t_ovfl 711.1Smycroft xref t_unfl 721.1Smycroft 731.1Smycroft xdef res_func 741.1Smycroft xdef p_move 751.1Smycroft 761.1Smycroftres_func: 771.1Smycroft clr.b DNRM_FLG(a6) 781.1Smycroft clr.b RES_FLG(a6) 791.1Smycroft clr.b CU_ONLY(a6) 801.1Smycroft tst.b DY_MO_FLG(a6) 811.1Smycroft beq.b monadic 821.1Smycroftdyadic: 831.1Smycroft btst.b #7,DTAG(a6) ;if dop = norm=000, zero=001, 841.1Smycroft* ;inf=010 or nan=011 851.1Smycroft beq.b monadic ;then branch 861.1Smycroft* ;else denorm 871.1Smycroft* HANDLE DESTINATION DENORM HERE 881.1Smycroft* ;set dtag to norm 891.1Smycroft* ;write the tag & fpte15 to the fstack 901.1Smycroft lea.l FPTEMP(a6),a0 911.1Smycroft 921.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 931.1Smycroft sne LOCAL_SGN(a0) 941.1Smycroft 951.1Smycroft bsr nrm_set ;normalize number (exp will go negative) 961.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign 971.1Smycroft bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format 981.1Smycroft beq.b dpos 991.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 1001.1Smycroftdpos: 1011.1Smycroft bfclr DTAG(a6){0:4} ;set tag to normalized, FPTE15 = 0 1021.1Smycroft bset.b #4,DTAG(a6) ;set FPTE15 1031.1Smycroft or.b #$0f,DNRM_FLG(a6) 1041.1Smycroftmonadic: 1051.1Smycroft lea.l ETEMP(a6),a0 1061.1Smycroft btst.b #direction_bit,CMDREG1B(a6) ;check direction 1071.1Smycroft bne.w opclass3 ;it is a mv out 1081.1Smycroft* 1091.1Smycroft* At this point, only oplcass 0 and 2 possible 1101.1Smycroft* 1111.1Smycroft btst.b #7,STAG(a6) ;if sop = norm=000, zero=001, 1121.1Smycroft* ;inf=010 or nan=011 1131.1Smycroft bne.w mon_dnrm ;else denorm 1141.1Smycroft tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would 1151.1Smycroft bne.w normal ;require normalization of denorm 1161.1Smycroft 1171.1Smycroft* At this point: 1181.1Smycroft* monadic instructions: fabs = $18 fneg = $1a ftst = $3a 1191.1Smycroft* fmove = $00 fsmove = $40 fdmove = $44 1201.1Smycroft* fsqrt = $05* fssqrt = $41 fdsqrt = $45 1211.1Smycroft* (*fsqrt reencoded to $05) 1221.1Smycroft* 1231.1Smycroft move.w CMDREG1B(a6),d0 ;get command register 1241.1Smycroft andi.l #$7f,d0 ;strip to only command word 1251.1Smycroft* 1261.1Smycroft* At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 1271.1Smycroft* fdsqrt are possible. 1281.1Smycroft* For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 1291.1Smycroft* For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 1301.1Smycroft* 1311.1Smycroft btst.l #0,d0 1321.1Smycroft bne.w normal ;weed out fsqrt instructions 1331.1Smycroft* 1341.1Smycroft* cu_norm handles fmove in instructions with normalized inputs. 1351.1Smycroft* The routine round is used to correctly round the input for the 1361.1Smycroft* destination precision and mode. 1371.1Smycroft* 1381.1Smycroftcu_norm: 1391.1Smycroft st CU_ONLY(a6) ;set cu-only inst flag 1401.1Smycroft move.w CMDREG1B(a6),d0 1411.1Smycroft andi.b #$3b,d0 ;isolate bits to select inst 1421.1Smycroft tst.b d0 1431.1Smycroft beq.l cu_nmove ;if zero, it is an fmove 1441.1Smycroft cmpi.b #$18,d0 1451.1Smycroft beq.l cu_nabs ;if $18, it is fabs 1461.1Smycroft cmpi.b #$1a,d0 1471.1Smycroft beq.l cu_nneg ;if $1a, it is fneg 1481.1Smycroft* 1491.1Smycroft* Inst is ftst. Check the source operand and set the cc's accordingly. 1501.1Smycroft* No write is done, so simply rts. 1511.1Smycroft* 1521.1Smycroftcu_ntst: 1531.1Smycroft move.w LOCAL_EX(a0),d0 1541.1Smycroft bclr.l #15,d0 1551.1Smycroft sne LOCAL_SGN(a0) 1561.1Smycroft beq.b cu_ntpo 1571.1Smycroft or.l #neg_mask,USER_FPSR(a6) ;set N 1581.1Smycroftcu_ntpo: 1591.1Smycroft cmpi.w #$7fff,d0 ;test for inf/nan 1601.1Smycroft bne.b cu_ntcz 1611.1Smycroft tst.l LOCAL_HI(a0) 1621.1Smycroft bne.b cu_ntn 1631.1Smycroft tst.l LOCAL_LO(a0) 1641.1Smycroft bne.b cu_ntn 1651.1Smycroft or.l #inf_mask,USER_FPSR(a6) 1661.1Smycroft rts 1671.1Smycroftcu_ntn: 1681.1Smycroft or.l #nan_mask,USER_FPSR(a6) 1691.1Smycroft move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for 1701.1Smycroft* ;snan handler 1711.1Smycroft 1721.1Smycroft rts 1731.1Smycroftcu_ntcz: 1741.1Smycroft tst.l LOCAL_HI(a0) 1751.1Smycroft bne.l cu_ntsx 1761.1Smycroft tst.l LOCAL_LO(a0) 1771.1Smycroft bne.l cu_ntsx 1781.1Smycroft or.l #z_mask,USER_FPSR(a6) 1791.1Smycroftcu_ntsx: 1801.1Smycroft rts 1811.1Smycroft* 1821.1Smycroft* Inst is fabs. Execute the absolute value function on the input. 1831.1Smycroft* Branch to the fmove code. If the operand is NaN, do nothing. 1841.1Smycroft* 1851.1Smycroftcu_nabs: 1861.1Smycroft move.b STAG(a6),d0 1871.1Smycroft btst.l #5,d0 ;test for NaN or zero 1881.1Smycroft bne wr_etemp ;if either, simply write it 1891.1Smycroft bclr.b #7,LOCAL_EX(a0) ;do abs 1901.1Smycroft bra.b cu_nmove ;fmove code will finish 1911.1Smycroft* 1921.1Smycroft* Inst is fneg. Execute the negate value function on the input. 1931.1Smycroft* Fall though to the fmove code. If the operand is NaN, do nothing. 1941.1Smycroft* 1951.1Smycroftcu_nneg: 1961.1Smycroft move.b STAG(a6),d0 1971.1Smycroft btst.l #5,d0 ;test for NaN or zero 1981.1Smycroft bne wr_etemp ;if either, simply write it 1991.1Smycroft bchg.b #7,LOCAL_EX(a0) ;do neg 2001.1Smycroft* 2011.1Smycroft* Inst is fmove. This code also handles all result writes. 2021.1Smycroft* If bit 2 is set, round is forced to double. If it is clear, 2031.1Smycroft* and bit 6 is set, round is forced to single. If both are clear, 2041.1Smycroft* the round precision is found in the fpcr. If the rounding precision 2051.1Smycroft* is double or single, round the result before the write. 2061.1Smycroft* 2071.1Smycroftcu_nmove: 2081.1Smycroft move.b STAG(a6),d0 2091.1Smycroft andi.b #$e0,d0 ;isolate stag bits 2101.1Smycroft bne wr_etemp ;if not norm, simply write it 2111.1Smycroft btst.b #2,CMDREG1B+1(a6) ;check for rd 2121.1Smycroft bne cu_nmrd 2131.1Smycroft btst.b #6,CMDREG1B+1(a6) ;check for rs 2141.1Smycroft bne cu_nmrs 2151.1Smycroft* 2161.1Smycroft* The move or operation is not with forced precision. Test for 2171.1Smycroft* nan or inf as the input; if so, simply write it to FPn. Use the 2181.1Smycroft* FPCR_MODE byte to get rounding on norms and zeros. 2191.1Smycroft* 2201.1Smycroftcu_nmnr: 2211.1Smycroft bfextu FPCR_MODE(a6){0:2},d0 2221.1Smycroft tst.b d0 ;check for extended 2231.1Smycroft beq cu_wrexn ;if so, just write result 2241.1Smycroft cmpi.b #1,d0 ;check for single 2251.1Smycroft beq cu_nmrs ;fall through to double 2261.1Smycroft* 2271.1Smycroft* The move is fdmove or round precision is double. 2281.1Smycroft* 2291.1Smycroftcu_nmrd: 2301.1Smycroft move.l #2,d0 ;set up the size for denorm 2311.1Smycroft move.w LOCAL_EX(a0),d1 ;compare exponent to double threshold 2321.1Smycroft and.w #$7fff,d1 2331.1Smycroft cmp.w #$3c01,d1 2341.1Smycroft bls cu_nunfl 2351.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ;get rmode 2361.1Smycroft or.l #$00020000,d1 ;or in rprec (double) 2371.1Smycroft clr.l d0 ;clear g,r,s for round 2381.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) ;convert to internal format 2391.1Smycroft sne LOCAL_SGN(a0) 2401.1Smycroft bsr.l round 2411.1Smycroft bfclr LOCAL_SGN(a0){0:8} 2421.1Smycroft beq.b cu_nmrdc 2431.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 2441.1Smycroftcu_nmrdc: 2451.1Smycroft move.w LOCAL_EX(a0),d1 ;check for overflow 2461.1Smycroft and.w #$7fff,d1 2471.1Smycroft cmp.w #$43ff,d1 2481.1Smycroft bge cu_novfl ;take care of overflow case 2491.1Smycroft bra.w cu_wrexn 2501.1Smycroft* 2511.1Smycroft* The move is fsmove or round precision is single. 2521.1Smycroft* 2531.1Smycroftcu_nmrs: 2541.1Smycroft move.l #1,d0 2551.1Smycroft move.w LOCAL_EX(a0),d1 2561.1Smycroft and.w #$7fff,d1 2571.1Smycroft cmp.w #$3f81,d1 2581.1Smycroft bls cu_nunfl 2591.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 2601.1Smycroft or.l #$00010000,d1 2611.1Smycroft clr.l d0 2621.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 2631.1Smycroft sne LOCAL_SGN(a0) 2641.1Smycroft bsr.l round 2651.1Smycroft bfclr LOCAL_SGN(a0){0:8} 2661.1Smycroft beq.b cu_nmrsc 2671.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 2681.1Smycroftcu_nmrsc: 2691.1Smycroft move.w LOCAL_EX(a0),d1 2701.1Smycroft and.w #$7FFF,d1 2711.1Smycroft cmp.w #$407f,d1 2721.1Smycroft blt cu_wrexn 2731.1Smycroft* 2741.1Smycroft* The operand is above precision boundaries. Use t_ovfl to 2751.1Smycroft* generate the correct value. 2761.1Smycroft* 2771.1Smycroftcu_novfl: 2781.1Smycroft bsr t_ovfl 2791.1Smycroft bra cu_wrexn 2801.1Smycroft* 2811.1Smycroft* The operand is below precision boundaries. Use denorm to 2821.1Smycroft* generate the correct value. 2831.1Smycroft* 2841.1Smycroftcu_nunfl: 2851.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 2861.1Smycroft sne LOCAL_SGN(a0) 2871.1Smycroft bsr denorm 2881.1Smycroft bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format 2891.1Smycroft beq.b cu_nucont 2901.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 2911.1Smycroftcu_nucont: 2921.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 2931.1Smycroft btst.b #2,CMDREG1B+1(a6) ;check for rd 2941.1Smycroft bne inst_d 2951.1Smycroft btst.b #6,CMDREG1B+1(a6) ;check for rs 2961.1Smycroft bne inst_s 2971.1Smycroft swap d1 2981.1Smycroft move.b FPCR_MODE(a6),d1 2991.1Smycroft lsr.b #6,d1 3001.1Smycroft swap d1 3011.1Smycroft bra inst_sd 3021.1Smycroftinst_d: 3031.1Smycroft or.l #$00020000,d1 3041.1Smycroft bra inst_sd 3051.1Smycroftinst_s: 3061.1Smycroft or.l #$00010000,d1 3071.1Smycroftinst_sd: 3081.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 3091.1Smycroft sne LOCAL_SGN(a0) 3101.1Smycroft bsr.l round 3111.1Smycroft bfclr LOCAL_SGN(a0){0:8} 3121.1Smycroft beq.b cu_nuflp 3131.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 3141.1Smycroftcu_nuflp: 3151.1Smycroft btst.b #inex2_bit,FPSR_EXCEPT(a6) 3161.1Smycroft beq.b cu_nuninx 3171.1Smycroft or.l #aunfl_mask,USER_FPSR(a6) ;if the round was inex, set AUNFL 3181.1Smycroftcu_nuninx: 3191.1Smycroft tst.l LOCAL_HI(a0) ;test for zero 3201.1Smycroft bne.b cu_nunzro 3211.1Smycroft tst.l LOCAL_LO(a0) 3221.1Smycroft bne.b cu_nunzro 3231.1Smycroft* 3241.1Smycroft* The mantissa is zero from the denorm loop. Check sign and rmode 3251.1Smycroft* to see if rounding should have occured which would leave the lsb. 3261.1Smycroft* 3271.1Smycroft move.l USER_FPCR(a6),d0 3281.1Smycroft andi.l #$30,d0 ;isolate rmode 3291.1Smycroft cmpi.l #$20,d0 3301.1Smycroft blt.b cu_nzro 3311.1Smycroft bne.b cu_nrp 3321.1Smycroftcu_nrm: 3331.1Smycroft tst.w LOCAL_EX(a0) ;if positive, set lsb 3341.1Smycroft bge.b cu_nzro 3351.1Smycroft btst.b #7,FPCR_MODE(a6) ;check for double 3361.1Smycroft beq.b cu_nincs 3371.1Smycroft bra.b cu_nincd 3381.1Smycroftcu_nrp: 3391.1Smycroft tst.w LOCAL_EX(a0) ;if positive, set lsb 3401.1Smycroft blt.b cu_nzro 3411.1Smycroft btst.b #7,FPCR_MODE(a6) ;check for double 3421.1Smycroft beq.b cu_nincs 3431.1Smycroftcu_nincd: 3441.1Smycroft or.l #$800,LOCAL_LO(a0) ;inc for double 3451.1Smycroft bra cu_nunzro 3461.1Smycroftcu_nincs: 3471.1Smycroft or.l #$100,LOCAL_HI(a0) ;inc for single 3481.1Smycroft bra cu_nunzro 3491.1Smycroftcu_nzro: 3501.1Smycroft or.l #z_mask,USER_FPSR(a6) 3511.1Smycroft move.b STAG(a6),d0 3521.1Smycroft andi.b #$e0,d0 3531.1Smycroft cmpi.b #$40,d0 ;check if input was tagged zero 3541.1Smycroft beq.b cu_numv 3551.1Smycroftcu_nunzro: 3561.1Smycroft or.l #unfl_mask,USER_FPSR(a6) ;set unfl 3571.1Smycroftcu_numv: 3581.1Smycroft move.l (a0),ETEMP(a6) 3591.1Smycroft move.l 4(a0),ETEMP_HI(a6) 3601.1Smycroft move.l 8(a0),ETEMP_LO(a6) 3611.1Smycroft* 3621.1Smycroft* Write the result to memory, setting the fpsr cc bits. NaN and Inf 3631.1Smycroft* bypass cu_wrexn. 3641.1Smycroft* 3651.1Smycroftcu_wrexn: 3661.1Smycroft tst.w LOCAL_EX(a0) ;test for zero 3671.1Smycroft beq.b cu_wrzero 3681.1Smycroft cmp.w #$8000,LOCAL_EX(a0) ;test for zero 3691.1Smycroft bne.b cu_wreon 3701.1Smycroftcu_wrzero: 3711.1Smycroft or.l #z_mask,USER_FPSR(a6) ;set Z bit 3721.1Smycroftcu_wreon: 3731.1Smycroft tst.w LOCAL_EX(a0) 3741.1Smycroft bpl wr_etemp 3751.1Smycroft or.l #neg_mask,USER_FPSR(a6) 3761.1Smycroft bra wr_etemp 3771.1Smycroft 3781.1Smycroft* 3791.1Smycroft* HANDLE SOURCE DENORM HERE 3801.1Smycroft* 3811.1Smycroft* ;clear denorm stag to norm 3821.1Smycroft* ;write the new tag & ete15 to the fstack 3831.1Smycroftmon_dnrm: 3841.1Smycroft* 3851.1Smycroft* At this point, check for the cases in which normalizing the 3861.1Smycroft* denorm produces incorrect results. 3871.1Smycroft* 3881.1Smycroft tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would 3891.1Smycroft bne.b nrm_src ;require normalization of denorm 3901.1Smycroft 3911.1Smycroft* At this point: 3921.1Smycroft* monadic instructions: fabs = $18 fneg = $1a ftst = $3a 3931.1Smycroft* fmove = $00 fsmove = $40 fdmove = $44 3941.1Smycroft* fsqrt = $05* fssqrt = $41 fdsqrt = $45 3951.1Smycroft* (*fsqrt reencoded to $05) 3961.1Smycroft* 3971.1Smycroft move.w CMDREG1B(a6),d0 ;get command register 3981.1Smycroft andi.l #$7f,d0 ;strip to only command word 3991.1Smycroft* 4001.1Smycroft* At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 4011.1Smycroft* fdsqrt are possible. 4021.1Smycroft* For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 4031.1Smycroft* For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 4041.1Smycroft* 4051.1Smycroft btst.l #0,d0 4061.1Smycroft bne.b nrm_src ;weed out fsqrt instructions 4071.1Smycroft st CU_ONLY(a6) ;set cu-only inst flag 4081.1Smycroft bra cu_dnrm ;fmove, fabs, fneg, ftst 4091.1Smycroft* ;cases go to cu_dnrm 4101.1Smycroftnrm_src: 4111.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 4121.1Smycroft sne LOCAL_SGN(a0) 4131.1Smycroft bsr nrm_set ;normalize number (exponent will go 4141.1Smycroft* ; negative) 4151.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign 4161.1Smycroft 4171.1Smycroft bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format 4181.1Smycroft beq.b spos 4191.1Smycroft bset.b #sign_bit,LOCAL_EX(a0) 4201.1Smycroftspos: 4211.1Smycroft bfclr STAG(a6){0:4} ;set tag to normalized, FPTE15 = 0 4221.1Smycroft bset.b #4,STAG(a6) ;set ETE15 4231.1Smycroft or.b #$f0,DNRM_FLG(a6) 4241.1Smycroftnormal: 4251.1Smycroft tst.b DNRM_FLG(a6) ;check if any of the ops were denorms 4261.1Smycroft bne ck_wrap ;if so, check if it is a potential 4271.1Smycroft* ;wrap-around case 4281.1Smycroftfix_stk: 4291.1Smycroft move.b #$fe,CU_SAVEPC(a6) 4301.1Smycroft bclr.b #E1,E_BYTE(a6) 4311.1Smycroft 4321.1Smycroft clr.w NMNEXC(a6) 4331.1Smycroft 4341.1Smycroft st.b RES_FLG(a6) ;indicate that a restore is needed 4351.1Smycroft rts 4361.1Smycroft 4371.1Smycroft* 4381.1Smycroft* cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and 4391.1Smycroft* ftst) completly in software without an frestore to the 040. 4401.1Smycroft* 4411.1Smycroftcu_dnrm: 4421.1Smycroft st.b CU_ONLY(a6) 4431.1Smycroft move.w CMDREG1B(a6),d0 4441.1Smycroft andi.b #$3b,d0 ;isolate bits to select inst 4451.1Smycroft tst.b d0 4461.1Smycroft beq.l cu_dmove ;if zero, it is an fmove 4471.1Smycroft cmpi.b #$18,d0 4481.1Smycroft beq.l cu_dabs ;if $18, it is fabs 4491.1Smycroft cmpi.b #$1a,d0 4501.1Smycroft beq.l cu_dneg ;if $1a, it is fneg 4511.1Smycroft* 4521.1Smycroft* Inst is ftst. Check the source operand and set the cc's accordingly. 4531.1Smycroft* No write is done, so simply rts. 4541.1Smycroft* 4551.1Smycroftcu_dtst: 4561.1Smycroft move.w LOCAL_EX(a0),d0 4571.1Smycroft bclr.l #15,d0 4581.1Smycroft sne LOCAL_SGN(a0) 4591.1Smycroft beq.b cu_dtpo 4601.1Smycroft or.l #neg_mask,USER_FPSR(a6) ;set N 4611.1Smycroftcu_dtpo: 4621.1Smycroft cmpi.w #$7fff,d0 ;test for inf/nan 4631.1Smycroft bne.b cu_dtcz 4641.1Smycroft tst.l LOCAL_HI(a0) 4651.1Smycroft bne.b cu_dtn 4661.1Smycroft tst.l LOCAL_LO(a0) 4671.1Smycroft bne.b cu_dtn 4681.1Smycroft or.l #inf_mask,USER_FPSR(a6) 4691.1Smycroft rts 4701.1Smycroftcu_dtn: 4711.1Smycroft or.l #nan_mask,USER_FPSR(a6) 4721.1Smycroft move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for 4731.1Smycroft* ;snan handler 4741.1Smycroft rts 4751.1Smycroftcu_dtcz: 4761.1Smycroft tst.l LOCAL_HI(a0) 4771.1Smycroft bne.l cu_dtsx 4781.1Smycroft tst.l LOCAL_LO(a0) 4791.1Smycroft bne.l cu_dtsx 4801.1Smycroft or.l #z_mask,USER_FPSR(a6) 4811.1Smycroftcu_dtsx: 4821.1Smycroft rts 4831.1Smycroft* 4841.1Smycroft* Inst is fabs. Execute the absolute value function on the input. 4851.1Smycroft* Branch to the fmove code. 4861.1Smycroft* 4871.1Smycroftcu_dabs: 4881.1Smycroft bclr.b #7,LOCAL_EX(a0) ;do abs 4891.1Smycroft bra.b cu_dmove ;fmove code will finish 4901.1Smycroft* 4911.1Smycroft* Inst is fneg. Execute the negate value function on the input. 4921.1Smycroft* Fall though to the fmove code. 4931.1Smycroft* 4941.1Smycroftcu_dneg: 4951.1Smycroft bchg.b #7,LOCAL_EX(a0) ;do neg 4961.1Smycroft* 4971.1Smycroft* Inst is fmove. This code also handles all result writes. 4981.1Smycroft* If bit 2 is set, round is forced to double. If it is clear, 4991.1Smycroft* and bit 6 is set, round is forced to single. If both are clear, 5001.1Smycroft* the round precision is found in the fpcr. If the rounding precision 5011.1Smycroft* is double or single, the result is zero, and the mode is checked 5021.1Smycroft* to determine if the lsb of the result should be set. 5031.1Smycroft* 5041.1Smycroftcu_dmove: 5051.1Smycroft btst.b #2,CMDREG1B+1(a6) ;check for rd 5061.1Smycroft bne cu_dmrd 5071.1Smycroft btst.b #6,CMDREG1B+1(a6) ;check for rs 5081.1Smycroft bne cu_dmrs 5091.1Smycroft* 5101.1Smycroft* The move or operation is not with forced precision. Use the 5111.1Smycroft* FPCR_MODE byte to get rounding. 5121.1Smycroft* 5131.1Smycroftcu_dmnr: 5141.1Smycroft bfextu FPCR_MODE(a6){0:2},d0 5151.1Smycroft tst.b d0 ;check for extended 5161.1Smycroft beq cu_wrexd ;if so, just write result 5171.1Smycroft cmpi.b #1,d0 ;check for single 5181.1Smycroft beq cu_dmrs ;fall through to double 5191.1Smycroft* 5201.1Smycroft* The move is fdmove or round precision is double. Result is zero. 5211.1Smycroft* Check rmode for rp or rm and set lsb accordingly. 5221.1Smycroft* 5231.1Smycroftcu_dmrd: 5241.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ;get rmode 5251.1Smycroft tst.w LOCAL_EX(a0) ;check sign 5261.1Smycroft blt.b cu_dmdn 5271.1Smycroft cmpi.b #3,d1 ;check for rp 5281.1Smycroft bne cu_dpd ;load double pos zero 5291.1Smycroft bra cu_dpdr ;load double pos zero w/lsb 5301.1Smycroftcu_dmdn: 5311.1Smycroft cmpi.b #2,d1 ;check for rm 5321.1Smycroft bne cu_dnd ;load double neg zero 5331.1Smycroft bra cu_dndr ;load double neg zero w/lsb 5341.1Smycroft* 5351.1Smycroft* The move is fsmove or round precision is single. Result is zero. 5361.1Smycroft* Check for rp or rm and set lsb accordingly. 5371.1Smycroft* 5381.1Smycroftcu_dmrs: 5391.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ;get rmode 5401.1Smycroft tst.w LOCAL_EX(a0) ;check sign 5411.1Smycroft blt.b cu_dmsn 5421.1Smycroft cmpi.b #3,d1 ;check for rp 5431.1Smycroft bne cu_spd ;load single pos zero 5441.1Smycroft bra cu_spdr ;load single pos zero w/lsb 5451.1Smycroftcu_dmsn: 5461.1Smycroft cmpi.b #2,d1 ;check for rm 5471.1Smycroft bne cu_snd ;load single neg zero 5481.1Smycroft bra cu_sndr ;load single neg zero w/lsb 5491.1Smycroft* 5501.1Smycroft* The precision is extended, so the result in etemp is correct. 5511.1Smycroft* Simply set unfl (not inex2 or aunfl) and write the result to 5521.1Smycroft* the correct fp register. 5531.1Smycroftcu_wrexd: 5541.1Smycroft or.l #unfl_mask,USER_FPSR(a6) 5551.1Smycroft tst.w LOCAL_EX(a0) 5561.1Smycroft beq wr_etemp 5571.1Smycroft or.l #neg_mask,USER_FPSR(a6) 5581.1Smycroft bra wr_etemp 5591.1Smycroft* 5601.1Smycroft* These routines write +/- zero in double format. The routines 5611.1Smycroft* cu_dpdr and cu_dndr set the double lsb. 5621.1Smycroft* 5631.1Smycroftcu_dpd: 5641.1Smycroft move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero 5651.1Smycroft clr.l LOCAL_HI(a0) 5661.1Smycroft clr.l LOCAL_LO(a0) 5671.1Smycroft or.l #z_mask,USER_FPSR(a6) 5681.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 5691.1Smycroft bra wr_etemp 5701.1Smycroftcu_dpdr: 5711.1Smycroft move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero 5721.1Smycroft clr.l LOCAL_HI(a0) 5731.1Smycroft move.l #$800,LOCAL_LO(a0) ;with lsb set 5741.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 5751.1Smycroft bra wr_etemp 5761.1Smycroftcu_dnd: 5771.1Smycroft move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero 5781.1Smycroft clr.l LOCAL_HI(a0) 5791.1Smycroft clr.l LOCAL_LO(a0) 5801.1Smycroft or.l #z_mask,USER_FPSR(a6) 5811.1Smycroft or.l #neg_mask,USER_FPSR(a6) 5821.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 5831.1Smycroft bra wr_etemp 5841.1Smycroftcu_dndr: 5851.1Smycroft move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero 5861.1Smycroft clr.l LOCAL_HI(a0) 5871.1Smycroft move.l #$800,LOCAL_LO(a0) ;with lsb set 5881.1Smycroft or.l #neg_mask,USER_FPSR(a6) 5891.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 5901.1Smycroft bra wr_etemp 5911.1Smycroft* 5921.1Smycroft* These routines write +/- zero in single format. The routines 5931.1Smycroft* cu_dpdr and cu_dndr set the single lsb. 5941.1Smycroft* 5951.1Smycroftcu_spd: 5961.1Smycroft move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero 5971.1Smycroft clr.l LOCAL_HI(a0) 5981.1Smycroft clr.l LOCAL_LO(a0) 5991.1Smycroft or.l #z_mask,USER_FPSR(a6) 6001.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 6011.1Smycroft bra wr_etemp 6021.1Smycroftcu_spdr: 6031.1Smycroft move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero 6041.1Smycroft move.l #$100,LOCAL_HI(a0) ;with lsb set 6051.1Smycroft clr.l LOCAL_LO(a0) 6061.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 6071.1Smycroft bra wr_etemp 6081.1Smycroftcu_snd: 6091.1Smycroft move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero 6101.1Smycroft clr.l LOCAL_HI(a0) 6111.1Smycroft clr.l LOCAL_LO(a0) 6121.1Smycroft or.l #z_mask,USER_FPSR(a6) 6131.1Smycroft or.l #neg_mask,USER_FPSR(a6) 6141.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 6151.1Smycroft bra wr_etemp 6161.1Smycroftcu_sndr: 6171.1Smycroft move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero 6181.1Smycroft move.l #$100,LOCAL_HI(a0) ;with lsb set 6191.1Smycroft clr.l LOCAL_LO(a0) 6201.1Smycroft or.l #neg_mask,USER_FPSR(a6) 6211.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 6221.1Smycroft bra wr_etemp 6231.1Smycroft 6241.1Smycroft* 6251.1Smycroft* This code checks for 16-bit overflow conditions on dyadic 6261.1Smycroft* operations which are not restorable into the floating-point 6271.1Smycroft* unit and must be completed in software. Basically, this 6281.1Smycroft* condition exists with a very large norm and a denorm. One 6291.1Smycroft* of the operands must be denormalized to enter this code. 6301.1Smycroft* 6311.1Smycroft* Flags used: 6321.1Smycroft* DY_MO_FLG contains 0 for monadic op, $ff for dyadic 6331.1Smycroft* DNRM_FLG contains $00 for neither op denormalized 6341.1Smycroft* $0f for the destination op denormalized 6351.1Smycroft* $f0 for the source op denormalized 6361.1Smycroft* $ff for both ops denormalzed 6371.1Smycroft* 6381.1Smycroft* The wrap-around condition occurs for add, sub, div, and cmp 6391.1Smycroft* when 6401.1Smycroft* 6411.1Smycroft* abs(dest_exp - src_exp) >= $8000 6421.1Smycroft* 6431.1Smycroft* and for mul when 6441.1Smycroft* 6451.1Smycroft* (dest_exp + src_exp) < $0 6461.1Smycroft* 6471.1Smycroft* we must process the operation here if this case is true. 6481.1Smycroft* 6491.1Smycroft* The rts following the frcfpn routine is the exit from res_func 6501.1Smycroft* for this condition. The restore flag (RES_FLG) is left clear. 6511.1Smycroft* No frestore is done unless an exception is to be reported. 6521.1Smycroft* 6531.1Smycroft* For fadd: 6541.1Smycroft* if(sign_of(dest) != sign_of(src)) 6551.1Smycroft* replace exponent of src with $3fff (keep sign) 6561.1Smycroft* use fpu to perform dest+new_src (user's rmode and X) 6571.1Smycroft* clr sticky 6581.1Smycroft* else 6591.1Smycroft* set sticky 6601.1Smycroft* call round with user's precision and mode 6611.1Smycroft* move result to fpn and wbtemp 6621.1Smycroft* 6631.1Smycroft* For fsub: 6641.1Smycroft* if(sign_of(dest) == sign_of(src)) 6651.1Smycroft* replace exponent of src with $3fff (keep sign) 6661.1Smycroft* use fpu to perform dest+new_src (user's rmode and X) 6671.1Smycroft* clr sticky 6681.1Smycroft* else 6691.1Smycroft* set sticky 6701.1Smycroft* call round with user's precision and mode 6711.1Smycroft* move result to fpn and wbtemp 6721.1Smycroft* 6731.1Smycroft* For fdiv/fsgldiv: 6741.1Smycroft* if(both operands are denorm) 6751.1Smycroft* restore_to_fpu; 6761.1Smycroft* if(dest is norm) 6771.1Smycroft* force_ovf; 6781.1Smycroft* else(dest is denorm) 6791.1Smycroft* force_unf: 6801.1Smycroft* 6811.1Smycroft* For fcmp: 6821.1Smycroft* if(dest is norm) 6831.1Smycroft* N = sign_of(dest); 6841.1Smycroft* else(dest is denorm) 6851.1Smycroft* N = sign_of(src); 6861.1Smycroft* 6871.1Smycroft* For fmul: 6881.1Smycroft* if(both operands are denorm) 6891.1Smycroft* force_unf; 6901.1Smycroft* if((dest_exp + src_exp) < 0) 6911.1Smycroft* force_unf: 6921.1Smycroft* else 6931.1Smycroft* restore_to_fpu; 6941.1Smycroft* 6951.1Smycroft* local equates: 6961.1Smycroftaddcode equ $22 6971.1Smycroftsubcode equ $28 6981.1Smycroftmulcode equ $23 6991.1Smycroftdivcode equ $20 7001.1Smycroftcmpcode equ $38 7011.1Smycroftck_wrap: 7021.1Smycroft tst.b DY_MO_FLG(a6) ;check for fsqrt 7031.1Smycroft beq fix_stk ;if zero, it is fsqrt 7041.1Smycroft move.w CMDREG1B(a6),d0 7051.1Smycroft andi.w #$3b,d0 ;strip to command bits 7061.1Smycroft cmpi.w #addcode,d0 7071.1Smycroft beq wrap_add 7081.1Smycroft cmpi.w #subcode,d0 7091.1Smycroft beq wrap_sub 7101.1Smycroft cmpi.w #mulcode,d0 7111.1Smycroft beq wrap_mul 7121.1Smycroft cmpi.w #cmpcode,d0 7131.1Smycroft beq wrap_cmp 7141.1Smycroft* 7151.1Smycroft* Inst is fdiv. 7161.1Smycroft* 7171.1Smycroftwrap_div: 7181.1Smycroft cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm, 7191.1Smycroft beq fix_stk ;restore to fpu 7201.1Smycroft* 7211.1Smycroft* One of the ops is denormalized. Test for wrap condition 7221.1Smycroft* and force the result. 7231.1Smycroft* 7241.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm 7251.1Smycroft bne.b div_srcd 7261.1Smycroftdiv_destd: 7271.1Smycroft bsr.l ckinf_ns 7281.1Smycroft bne fix_stk 7291.1Smycroft bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos) 7301.1Smycroft bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg) 7311.1Smycroft sub.l d1,d0 ;subtract dest from src 7321.1Smycroft cmp.l #$7fff,d0 7331.1Smycroft blt fix_stk ;if less, not wrap case 7341.1Smycroft clr.b WBTEMP_SGN(a6) 7351.1Smycroft move.w ETEMP_EX(a6),d0 ;find the sign of the result 7361.1Smycroft move.w FPTEMP_EX(a6),d1 7371.1Smycroft eor.w d1,d0 7381.1Smycroft andi.w #$8000,d0 7391.1Smycroft beq force_unf 7401.1Smycroft st.b WBTEMP_SGN(a6) 7411.1Smycroft bra force_unf 7421.1Smycroft 7431.1Smycroftckinf_ns: 7441.1Smycroft move.b STAG(a6),d0 ;check source tag for inf or nan 7451.1Smycroft bra ck_in_com 7461.1Smycroftckinf_nd: 7471.1Smycroft move.b DTAG(a6),d0 ;check destination tag for inf or nan 7481.1Smycroftck_in_com: 7491.1Smycroft andi.b #$60,d0 ;isolate tag bits 7501.1Smycroft cmp.b #$40,d0 ;is it inf? 7511.1Smycroft beq nan_or_inf ;not wrap case 7521.1Smycroft cmp.b #$60,d0 ;is it nan? 7531.1Smycroft beq nan_or_inf ;yes, not wrap case? 7541.1Smycroft cmp.b #$20,d0 ;is it a zero? 7551.1Smycroft beq nan_or_inf ;yes 7561.1Smycroft clr.l d0 7571.1Smycroft rts ;then it is either a zero of norm, 7581.1Smycroft* ;check wrap case 7591.1Smycroftnan_or_inf: 7601.1Smycroft moveq.l #-1,d0 7611.1Smycroft rts 7621.1Smycroft 7631.1Smycroft 7641.1Smycroft 7651.1Smycroftdiv_srcd: 7661.1Smycroft bsr.l ckinf_nd 7671.1Smycroft bne fix_stk 7681.1Smycroft bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos) 7691.1Smycroft bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg) 7701.1Smycroft sub.l d1,d0 ;subtract src from dest 7711.1Smycroft cmp.l #$8000,d0 7721.1Smycroft blt fix_stk ;if less, not wrap case 7731.1Smycroft clr.b WBTEMP_SGN(a6) 7741.1Smycroft move.w ETEMP_EX(a6),d0 ;find the sign of the result 7751.1Smycroft move.w FPTEMP_EX(a6),d1 7761.1Smycroft eor.w d1,d0 7771.1Smycroft andi.w #$8000,d0 7781.1Smycroft beq.b force_ovf 7791.1Smycroft st.b WBTEMP_SGN(a6) 7801.1Smycroft* 7811.1Smycroft* This code handles the case of the instruction resulting in 7821.1Smycroft* an overflow condition. 7831.1Smycroft* 7841.1Smycroftforce_ovf: 7851.1Smycroft bclr.b #E1,E_BYTE(a6) 7861.1Smycroft or.l #ovfl_inx_mask,USER_FPSR(a6) 7871.1Smycroft clr.w NMNEXC(a6) 7881.1Smycroft lea.l WBTEMP(a6),a0 ;point a0 to memory location 7891.1Smycroft move.w CMDREG1B(a6),d0 7901.1Smycroft btst.l #6,d0 ;test for forced precision 7911.1Smycroft beq.b frcovf_fpcr 7921.1Smycroft btst.l #2,d0 ;check for double 7931.1Smycroft bne.b frcovf_dbl 7941.1Smycroft move.l #$1,d0 ;inst is forced single 7951.1Smycroft bra.b frcovf_rnd 7961.1Smycroftfrcovf_dbl: 7971.1Smycroft move.l #$2,d0 ;inst is forced double 7981.1Smycroft bra.b frcovf_rnd 7991.1Smycroftfrcovf_fpcr: 8001.1Smycroft bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec 8011.1Smycroftfrcovf_rnd: 8021.1Smycroft 8031.1Smycroft* The 881/882 does not set inex2 for the following case, so the 8041.1Smycroft* line is commented out to be compatible with 881/882 8051.1Smycroft* tst.b d0 8061.1Smycroft* beq.b frcovf_x 8071.1Smycroft* or.l #inex2_mask,USER_FPSR(a6) ;if prec is s or d, set inex2 8081.1Smycroft 8091.1Smycroft*frcovf_x: 8101.1Smycroft bsr.l ovf_res ;get correct result based on 8111.1Smycroft* ;round precision/mode. This 8121.1Smycroft* ;sets FPSR_CC correctly 8131.1Smycroft* ;returns in external format 8141.1Smycroft bfclr WBTEMP_SGN(a6){0:8} 8151.1Smycroft beq frcfpn 8161.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 8171.1Smycroft bra frcfpn 8181.1Smycroft* 8191.1Smycroft* Inst is fadd. 8201.1Smycroft* 8211.1Smycroftwrap_add: 8221.1Smycroft cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm, 8231.1Smycroft beq fix_stk ;restore to fpu 8241.1Smycroft* 8251.1Smycroft* One of the ops is denormalized. Test for wrap condition 8261.1Smycroft* and complete the instruction. 8271.1Smycroft* 8281.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm 8291.1Smycroft bne.b add_srcd 8301.1Smycroftadd_destd: 8311.1Smycroft bsr.l ckinf_ns 8321.1Smycroft bne fix_stk 8331.1Smycroft bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos) 8341.1Smycroft bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg) 8351.1Smycroft sub.l d1,d0 ;subtract dest from src 8361.1Smycroft cmp.l #$8000,d0 8371.1Smycroft blt fix_stk ;if less, not wrap case 8381.1Smycroft bra add_wrap 8391.1Smycroftadd_srcd: 8401.1Smycroft bsr.l ckinf_nd 8411.1Smycroft bne fix_stk 8421.1Smycroft bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos) 8431.1Smycroft bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg) 8441.1Smycroft sub.l d1,d0 ;subtract src from dest 8451.1Smycroft cmp.l #$8000,d0 8461.1Smycroft blt fix_stk ;if less, not wrap case 8471.1Smycroft* 8481.1Smycroft* Check the signs of the operands. If they are unlike, the fpu 8491.1Smycroft* can be used to add the norm and 1.0 with the sign of the 8501.1Smycroft* denorm and it will correctly generate the result in extended 8511.1Smycroft* precision. We can then call round with no sticky and the result 8521.1Smycroft* will be correct for the user's rounding mode and precision. If 8531.1Smycroft* the signs are the same, we call round with the sticky bit set 8541.1Smycroft* and the result will be correctfor the user's rounding mode and 8551.1Smycroft* precision. 8561.1Smycroft* 8571.1Smycroftadd_wrap: 8581.1Smycroft move.w ETEMP_EX(a6),d0 8591.1Smycroft move.w FPTEMP_EX(a6),d1 8601.1Smycroft eor.w d1,d0 8611.1Smycroft andi.w #$8000,d0 8621.1Smycroft beq add_same 8631.1Smycroft* 8641.1Smycroft* The signs are unlike. 8651.1Smycroft* 8661.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm? 8671.1Smycroft bne.b add_u_srcd 8681.1Smycroft move.w FPTEMP_EX(a6),d0 8691.1Smycroft andi.w #$8000,d0 8701.1Smycroft or.w #$3fff,d0 ;force the exponent to +/- 1 8711.1Smycroft move.w d0,FPTEMP_EX(a6) ;in the denorm 8721.1Smycroft move.l USER_FPCR(a6),d0 8731.1Smycroft andi.l #$30,d0 8741.1Smycroft fmove.l d0,fpcr ;set up users rmode and X 8751.1Smycroft fmove.x ETEMP(a6),fp0 8761.1Smycroft fadd.x FPTEMP(a6),fp0 8771.1Smycroft lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame 8781.1Smycroft fmove.l fpsr,d1 8791.1Smycroft or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd 8801.1Smycroft fmove.x fp0,WBTEMP(a6) ;write result to memory 8811.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 8821.1Smycroft move.l USER_FPCR(a6),d1 8831.1Smycroft andi.l #$c0,d1 8841.1Smycroft lsr.l #6,d1 ;put precision in upper word 8851.1Smycroft swap d1 8861.1Smycroft or.l d0,d1 ;set up for round call 8871.1Smycroft clr.l d0 ;force sticky to zero 8881.1Smycroft bclr.b #sign_bit,WBTEMP_EX(a6) 8891.1Smycroft sne WBTEMP_SGN(a6) 8901.1Smycroft bsr.l round ;round result to users rmode & prec 8911.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 8921.1Smycroft beq frcfpnr 8931.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 8941.1Smycroft bra frcfpnr 8951.1Smycroftadd_u_srcd: 8961.1Smycroft move.w ETEMP_EX(a6),d0 8971.1Smycroft andi.w #$8000,d0 8981.1Smycroft or.w #$3fff,d0 ;force the exponent to +/- 1 8991.1Smycroft move.w d0,ETEMP_EX(a6) ;in the denorm 9001.1Smycroft move.l USER_FPCR(a6),d0 9011.1Smycroft andi.l #$30,d0 9021.1Smycroft fmove.l d0,fpcr ;set up users rmode and X 9031.1Smycroft fmove.x ETEMP(a6),fp0 9041.1Smycroft fadd.x FPTEMP(a6),fp0 9051.1Smycroft fmove.l fpsr,d1 9061.1Smycroft or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd 9071.1Smycroft lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame 9081.1Smycroft fmove.x fp0,WBTEMP(a6) ;write result to memory 9091.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 9101.1Smycroft move.l USER_FPCR(a6),d1 9111.1Smycroft andi.l #$c0,d1 9121.1Smycroft lsr.l #6,d1 ;put precision in upper word 9131.1Smycroft swap d1 9141.1Smycroft or.l d0,d1 ;set up for round call 9151.1Smycroft clr.l d0 ;force sticky to zero 9161.1Smycroft bclr.b #sign_bit,WBTEMP_EX(a6) 9171.1Smycroft sne WBTEMP_SGN(a6) ;use internal format for round 9181.1Smycroft bsr.l round ;round result to users rmode & prec 9191.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 9201.1Smycroft beq frcfpnr 9211.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 9221.1Smycroft bra frcfpnr 9231.1Smycroft* 9241.1Smycroft* Signs are alike: 9251.1Smycroft* 9261.1Smycroftadd_same: 9271.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm? 9281.1Smycroft bne.b add_s_srcd 9291.1Smycroftadd_s_destd: 9301.1Smycroft lea.l ETEMP(a6),a0 9311.1Smycroft move.l USER_FPCR(a6),d0 9321.1Smycroft andi.l #$30,d0 9331.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 9341.1Smycroft move.l USER_FPCR(a6),d1 9351.1Smycroft andi.l #$c0,d1 9361.1Smycroft lsr.l #6,d1 ;put precision in upper word 9371.1Smycroft swap d1 9381.1Smycroft or.l d0,d1 ;set up for round call 9391.1Smycroft move.l #$20000000,d0 ;set sticky for round 9401.1Smycroft bclr.b #sign_bit,ETEMP_EX(a6) 9411.1Smycroft sne ETEMP_SGN(a6) 9421.1Smycroft bsr.l round ;round result to users rmode & prec 9431.1Smycroft bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format 9441.1Smycroft beq.b add_s_dclr 9451.1Smycroft bset.b #sign_bit,ETEMP_EX(a6) 9461.1Smycroftadd_s_dclr: 9471.1Smycroft lea.l WBTEMP(a6),a0 9481.1Smycroft move.l ETEMP(a6),(a0) ;write result to wbtemp 9491.1Smycroft move.l ETEMP_HI(a6),4(a0) 9501.1Smycroft move.l ETEMP_LO(a6),8(a0) 9511.1Smycroft tst.w ETEMP_EX(a6) 9521.1Smycroft bgt add_ckovf 9531.1Smycroft or.l #neg_mask,USER_FPSR(a6) 9541.1Smycroft bra add_ckovf 9551.1Smycroftadd_s_srcd: 9561.1Smycroft lea.l FPTEMP(a6),a0 9571.1Smycroft move.l USER_FPCR(a6),d0 9581.1Smycroft andi.l #$30,d0 9591.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 9601.1Smycroft move.l USER_FPCR(a6),d1 9611.1Smycroft andi.l #$c0,d1 9621.1Smycroft lsr.l #6,d1 ;put precision in upper word 9631.1Smycroft swap d1 9641.1Smycroft or.l d0,d1 ;set up for round call 9651.1Smycroft move.l #$20000000,d0 ;set sticky for round 9661.1Smycroft bclr.b #sign_bit,FPTEMP_EX(a6) 9671.1Smycroft sne FPTEMP_SGN(a6) 9681.1Smycroft bsr.l round ;round result to users rmode & prec 9691.1Smycroft bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 9701.1Smycroft beq.b add_s_sclr 9711.1Smycroft bset.b #sign_bit,FPTEMP_EX(a6) 9721.1Smycroftadd_s_sclr: 9731.1Smycroft lea.l WBTEMP(a6),a0 9741.1Smycroft move.l FPTEMP(a6),(a0) ;write result to wbtemp 9751.1Smycroft move.l FPTEMP_HI(a6),4(a0) 9761.1Smycroft move.l FPTEMP_LO(a6),8(a0) 9771.1Smycroft tst.w FPTEMP_EX(a6) 9781.1Smycroft bgt add_ckovf 9791.1Smycroft or.l #neg_mask,USER_FPSR(a6) 9801.1Smycroftadd_ckovf: 9811.1Smycroft move.w WBTEMP_EX(a6),d0 9821.1Smycroft andi.w #$7fff,d0 9831.1Smycroft cmpi.w #$7fff,d0 9841.1Smycroft bne frcfpnr 9851.1Smycroft* 9861.1Smycroft* The result has overflowed to $7fff exponent. Set I, ovfl, 9871.1Smycroft* and aovfl, and clr the mantissa (incorrectly set by the 9881.1Smycroft* round routine.) 9891.1Smycroft* 9901.1Smycroft or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6) 9911.1Smycroft clr.l 4(a0) 9921.1Smycroft bra frcfpnr 9931.1Smycroft* 9941.1Smycroft* Inst is fsub. 9951.1Smycroft* 9961.1Smycroftwrap_sub: 9971.1Smycroft cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm, 9981.1Smycroft beq fix_stk ;restore to fpu 9991.1Smycroft* 10001.1Smycroft* One of the ops is denormalized. Test for wrap condition 10011.1Smycroft* and complete the instruction. 10021.1Smycroft* 10031.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm 10041.1Smycroft bne.b sub_srcd 10051.1Smycroftsub_destd: 10061.1Smycroft bsr.l ckinf_ns 10071.1Smycroft bne fix_stk 10081.1Smycroft bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos) 10091.1Smycroft bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg) 10101.1Smycroft sub.l d1,d0 ;subtract src from dest 10111.1Smycroft cmp.l #$8000,d0 10121.1Smycroft blt fix_stk ;if less, not wrap case 10131.1Smycroft bra sub_wrap 10141.1Smycroftsub_srcd: 10151.1Smycroft bsr.l ckinf_nd 10161.1Smycroft bne fix_stk 10171.1Smycroft bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos) 10181.1Smycroft bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg) 10191.1Smycroft sub.l d1,d0 ;subtract dest from src 10201.1Smycroft cmp.l #$8000,d0 10211.1Smycroft blt fix_stk ;if less, not wrap case 10221.1Smycroft* 10231.1Smycroft* Check the signs of the operands. If they are alike, the fpu 10241.1Smycroft* can be used to subtract from the norm 1.0 with the sign of the 10251.1Smycroft* denorm and it will correctly generate the result in extended 10261.1Smycroft* precision. We can then call round with no sticky and the result 10271.1Smycroft* will be correct for the user's rounding mode and precision. If 10281.1Smycroft* the signs are unlike, we call round with the sticky bit set 10291.1Smycroft* and the result will be correctfor the user's rounding mode and 10301.1Smycroft* precision. 10311.1Smycroft* 10321.1Smycroftsub_wrap: 10331.1Smycroft move.w ETEMP_EX(a6),d0 10341.1Smycroft move.w FPTEMP_EX(a6),d1 10351.1Smycroft eor.w d1,d0 10361.1Smycroft andi.w #$8000,d0 10371.1Smycroft bne sub_diff 10381.1Smycroft* 10391.1Smycroft* The signs are alike. 10401.1Smycroft* 10411.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm? 10421.1Smycroft bne.b sub_u_srcd 10431.1Smycroft move.w FPTEMP_EX(a6),d0 10441.1Smycroft andi.w #$8000,d0 10451.1Smycroft or.w #$3fff,d0 ;force the exponent to +/- 1 10461.1Smycroft move.w d0,FPTEMP_EX(a6) ;in the denorm 10471.1Smycroft move.l USER_FPCR(a6),d0 10481.1Smycroft andi.l #$30,d0 10491.1Smycroft fmove.l d0,fpcr ;set up users rmode and X 10501.1Smycroft fmove.x FPTEMP(a6),fp0 10511.1Smycroft fsub.x ETEMP(a6),fp0 10521.1Smycroft fmove.l fpsr,d1 10531.1Smycroft or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd 10541.1Smycroft lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame 10551.1Smycroft fmove.x fp0,WBTEMP(a6) ;write result to memory 10561.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 10571.1Smycroft move.l USER_FPCR(a6),d1 10581.1Smycroft andi.l #$c0,d1 10591.1Smycroft lsr.l #6,d1 ;put precision in upper word 10601.1Smycroft swap d1 10611.1Smycroft or.l d0,d1 ;set up for round call 10621.1Smycroft clr.l d0 ;force sticky to zero 10631.1Smycroft bclr.b #sign_bit,WBTEMP_EX(a6) 10641.1Smycroft sne WBTEMP_SGN(a6) 10651.1Smycroft bsr.l round ;round result to users rmode & prec 10661.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 10671.1Smycroft beq frcfpnr 10681.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 10691.1Smycroft bra frcfpnr 10701.1Smycroftsub_u_srcd: 10711.1Smycroft move.w ETEMP_EX(a6),d0 10721.1Smycroft andi.w #$8000,d0 10731.1Smycroft or.w #$3fff,d0 ;force the exponent to +/- 1 10741.1Smycroft move.w d0,ETEMP_EX(a6) ;in the denorm 10751.1Smycroft move.l USER_FPCR(a6),d0 10761.1Smycroft andi.l #$30,d0 10771.1Smycroft fmove.l d0,fpcr ;set up users rmode and X 10781.1Smycroft fmove.x FPTEMP(a6),fp0 10791.1Smycroft fsub.x ETEMP(a6),fp0 10801.1Smycroft fmove.l fpsr,d1 10811.1Smycroft or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd 10821.1Smycroft lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame 10831.1Smycroft fmove.x fp0,WBTEMP(a6) ;write result to memory 10841.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 10851.1Smycroft move.l USER_FPCR(a6),d1 10861.1Smycroft andi.l #$c0,d1 10871.1Smycroft lsr.l #6,d1 ;put precision in upper word 10881.1Smycroft swap d1 10891.1Smycroft or.l d0,d1 ;set up for round call 10901.1Smycroft clr.l d0 ;force sticky to zero 10911.1Smycroft bclr.b #sign_bit,WBTEMP_EX(a6) 10921.1Smycroft sne WBTEMP_SGN(a6) 10931.1Smycroft bsr.l round ;round result to users rmode & prec 10941.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 10951.1Smycroft beq frcfpnr 10961.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 10971.1Smycroft bra frcfpnr 10981.1Smycroft* 10991.1Smycroft* Signs are unlike: 11001.1Smycroft* 11011.1Smycroftsub_diff: 11021.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm? 11031.1Smycroft bne.b sub_s_srcd 11041.1Smycroftsub_s_destd: 11051.1Smycroft lea.l ETEMP(a6),a0 11061.1Smycroft move.l USER_FPCR(a6),d0 11071.1Smycroft andi.l #$30,d0 11081.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 11091.1Smycroft move.l USER_FPCR(a6),d1 11101.1Smycroft andi.l #$c0,d1 11111.1Smycroft lsr.l #6,d1 ;put precision in upper word 11121.1Smycroft swap d1 11131.1Smycroft or.l d0,d1 ;set up for round call 11141.1Smycroft move.l #$20000000,d0 ;set sticky for round 11151.1Smycroft* 11161.1Smycroft* Since the dest is the denorm, the sign is the opposite of the 11171.1Smycroft* norm sign. 11181.1Smycroft* 11191.1Smycroft eori.w #$8000,ETEMP_EX(a6) ;flip sign on result 11201.1Smycroft tst.w ETEMP_EX(a6) 11211.1Smycroft bgt.b sub_s_dwr 11221.1Smycroft or.l #neg_mask,USER_FPSR(a6) 11231.1Smycroftsub_s_dwr: 11241.1Smycroft bclr.b #sign_bit,ETEMP_EX(a6) 11251.1Smycroft sne ETEMP_SGN(a6) 11261.1Smycroft bsr.l round ;round result to users rmode & prec 11271.1Smycroft bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format 11281.1Smycroft beq.b sub_s_dclr 11291.1Smycroft bset.b #sign_bit,ETEMP_EX(a6) 11301.1Smycroftsub_s_dclr: 11311.1Smycroft lea.l WBTEMP(a6),a0 11321.1Smycroft move.l ETEMP(a6),(a0) ;write result to wbtemp 11331.1Smycroft move.l ETEMP_HI(a6),4(a0) 11341.1Smycroft move.l ETEMP_LO(a6),8(a0) 11351.1Smycroft bra sub_ckovf 11361.1Smycroftsub_s_srcd: 11371.1Smycroft lea.l FPTEMP(a6),a0 11381.1Smycroft move.l USER_FPCR(a6),d0 11391.1Smycroft andi.l #$30,d0 11401.1Smycroft lsr.l #4,d0 ;put rmode in lower 2 bits 11411.1Smycroft move.l USER_FPCR(a6),d1 11421.1Smycroft andi.l #$c0,d1 11431.1Smycroft lsr.l #6,d1 ;put precision in upper word 11441.1Smycroft swap d1 11451.1Smycroft or.l d0,d1 ;set up for round call 11461.1Smycroft move.l #$20000000,d0 ;set sticky for round 11471.1Smycroft bclr.b #sign_bit,FPTEMP_EX(a6) 11481.1Smycroft sne FPTEMP_SGN(a6) 11491.1Smycroft bsr.l round ;round result to users rmode & prec 11501.1Smycroft bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 11511.1Smycroft beq.b sub_s_sclr 11521.1Smycroft bset.b #sign_bit,FPTEMP_EX(a6) 11531.1Smycroftsub_s_sclr: 11541.1Smycroft lea.l WBTEMP(a6),a0 11551.1Smycroft move.l FPTEMP(a6),(a0) ;write result to wbtemp 11561.1Smycroft move.l FPTEMP_HI(a6),4(a0) 11571.1Smycroft move.l FPTEMP_LO(a6),8(a0) 11581.1Smycroft tst.w FPTEMP_EX(a6) 11591.1Smycroft bgt sub_ckovf 11601.1Smycroft or.l #neg_mask,USER_FPSR(a6) 11611.1Smycroftsub_ckovf: 11621.1Smycroft move.w WBTEMP_EX(a6),d0 11631.1Smycroft andi.w #$7fff,d0 11641.1Smycroft cmpi.w #$7fff,d0 11651.1Smycroft bne frcfpnr 11661.1Smycroft* 11671.1Smycroft* The result has overflowed to $7fff exponent. Set I, ovfl, 11681.1Smycroft* and aovfl, and clr the mantissa (incorrectly set by the 11691.1Smycroft* round routine.) 11701.1Smycroft* 11711.1Smycroft or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6) 11721.1Smycroft clr.l 4(a0) 11731.1Smycroft bra frcfpnr 11741.1Smycroft* 11751.1Smycroft* Inst is fcmp. 11761.1Smycroft* 11771.1Smycroftwrap_cmp: 11781.1Smycroft cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm, 11791.1Smycroft beq fix_stk ;restore to fpu 11801.1Smycroft* 11811.1Smycroft* One of the ops is denormalized. Test for wrap condition 11821.1Smycroft* and complete the instruction. 11831.1Smycroft* 11841.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm 11851.1Smycroft bne.b cmp_srcd 11861.1Smycroftcmp_destd: 11871.1Smycroft bsr.l ckinf_ns 11881.1Smycroft bne fix_stk 11891.1Smycroft bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos) 11901.1Smycroft bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg) 11911.1Smycroft sub.l d1,d0 ;subtract dest from src 11921.1Smycroft cmp.l #$8000,d0 11931.1Smycroft blt fix_stk ;if less, not wrap case 11941.1Smycroft tst.w ETEMP_EX(a6) ;set N to ~sign_of(src) 11951.1Smycroft bge cmp_setn 11961.1Smycroft rts 11971.1Smycroftcmp_srcd: 11981.1Smycroft bsr.l ckinf_nd 11991.1Smycroft bne fix_stk 12001.1Smycroft bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos) 12011.1Smycroft bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg) 12021.1Smycroft sub.l d1,d0 ;subtract src from dest 12031.1Smycroft cmp.l #$8000,d0 12041.1Smycroft blt fix_stk ;if less, not wrap case 12051.1Smycroft tst.w FPTEMP_EX(a6) ;set N to sign_of(dest) 12061.1Smycroft blt cmp_setn 12071.1Smycroft rts 12081.1Smycroftcmp_setn: 12091.1Smycroft or.l #neg_mask,USER_FPSR(a6) 12101.1Smycroft rts 12111.1Smycroft 12121.1Smycroft* 12131.1Smycroft* Inst is fmul. 12141.1Smycroft* 12151.1Smycroftwrap_mul: 12161.1Smycroft cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm, 12171.1Smycroft beq force_unf ;force an underflow (really!) 12181.1Smycroft* 12191.1Smycroft* One of the ops is denormalized. Test for wrap condition 12201.1Smycroft* and complete the instruction. 12211.1Smycroft* 12221.1Smycroft cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm 12231.1Smycroft bne.b mul_srcd 12241.1Smycroftmul_destd: 12251.1Smycroft bsr.l ckinf_ns 12261.1Smycroft bne fix_stk 12271.1Smycroft bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos) 12281.1Smycroft bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg) 12291.1Smycroft add.l d1,d0 ;subtract dest from src 12301.1Smycroft bgt fix_stk 12311.1Smycroft bra force_unf 12321.1Smycroftmul_srcd: 12331.1Smycroft bsr.l ckinf_nd 12341.1Smycroft bne fix_stk 12351.1Smycroft bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos) 12361.1Smycroft bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg) 12371.1Smycroft add.l d1,d0 ;subtract src from dest 12381.1Smycroft bgt fix_stk 12391.1Smycroft 12401.1Smycroft* 12411.1Smycroft* This code handles the case of the instruction resulting in 12421.1Smycroft* an underflow condition. 12431.1Smycroft* 12441.1Smycroftforce_unf: 12451.1Smycroft bclr.b #E1,E_BYTE(a6) 12461.1Smycroft or.l #unfinx_mask,USER_FPSR(a6) 12471.1Smycroft clr.w NMNEXC(a6) 12481.1Smycroft clr.b WBTEMP_SGN(a6) 12491.1Smycroft move.w ETEMP_EX(a6),d0 ;find the sign of the result 12501.1Smycroft move.w FPTEMP_EX(a6),d1 12511.1Smycroft eor.w d1,d0 12521.1Smycroft andi.w #$8000,d0 12531.1Smycroft beq.b frcunfcont 12541.1Smycroft st.b WBTEMP_SGN(a6) 12551.1Smycroftfrcunfcont: 12561.1Smycroft lea WBTEMP(a6),a0 ;point a0 to memory location 12571.1Smycroft move.w CMDREG1B(a6),d0 12581.1Smycroft btst.l #6,d0 ;test for forced precision 12591.1Smycroft beq.b frcunf_fpcr 12601.1Smycroft btst.l #2,d0 ;check for double 12611.1Smycroft bne.b frcunf_dbl 12621.1Smycroft move.l #$1,d0 ;inst is forced single 12631.1Smycroft bra.b frcunf_rnd 12641.1Smycroftfrcunf_dbl: 12651.1Smycroft move.l #$2,d0 ;inst is forced double 12661.1Smycroft bra.b frcunf_rnd 12671.1Smycroftfrcunf_fpcr: 12681.1Smycroft bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec 12691.1Smycroftfrcunf_rnd: 12701.1Smycroft bsr.l unf_sub ;get correct result based on 12711.1Smycroft* ;round precision/mode. This 12721.1Smycroft* ;sets FPSR_CC correctly 12731.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 12741.1Smycroft beq.b frcfpn 12751.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 12761.1Smycroft bra frcfpn 12771.1Smycroft 12781.1Smycroft* 12791.1Smycroft* Write the result to the user's fpn. All results must be HUGE to be 12801.1Smycroft* written; otherwise the results would have overflowed or underflowed. 12811.1Smycroft* If the rounding precision is single or double, the ovf_res routine 12821.1Smycroft* is needed to correctly supply the max value. 12831.1Smycroft* 12841.1Smycroftfrcfpnr: 12851.1Smycroft move.w CMDREG1B(a6),d0 12861.1Smycroft btst.l #6,d0 ;test for forced precision 12871.1Smycroft beq.b frcfpn_fpcr 12881.1Smycroft btst.l #2,d0 ;check for double 12891.1Smycroft bne.b frcfpn_dbl 12901.1Smycroft move.l #$1,d0 ;inst is forced single 12911.1Smycroft bra.b frcfpn_rnd 12921.1Smycroftfrcfpn_dbl: 12931.1Smycroft move.l #$2,d0 ;inst is forced double 12941.1Smycroft bra.b frcfpn_rnd 12951.1Smycroftfrcfpn_fpcr: 12961.1Smycroft bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec 12971.1Smycroft tst.b d0 12981.1Smycroft beq.b frcfpn ;if extended, write what you got 12991.1Smycroftfrcfpn_rnd: 13001.1Smycroft bclr.b #sign_bit,WBTEMP_EX(a6) 13011.1Smycroft sne WBTEMP_SGN(a6) 13021.1Smycroft bsr.l ovf_res ;get correct result based on 13031.1Smycroft* ;round precision/mode. This 13041.1Smycroft* ;sets FPSR_CC correctly 13051.1Smycroft bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format 13061.1Smycroft beq.b frcfpn_clr 13071.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 13081.1Smycroftfrcfpn_clr: 13091.1Smycroft or.l #ovfinx_mask,USER_FPSR(a6) 13101.1Smycroft* 13111.1Smycroft* Perform the write. 13121.1Smycroft* 13131.1Smycroftfrcfpn: 13141.1Smycroft bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register 13151.1Smycroft cmpi.b #3,d0 13161.1Smycroft ble.b frc0123 ;check if dest is fp0-fp3 13171.1Smycroft move.l #7,d1 13181.1Smycroft sub.l d0,d1 13191.1Smycroft clr.l d0 13201.1Smycroft bset.l d1,d0 13211.1Smycroft fmovem.x WBTEMP(a6),d0 13221.1Smycroft rts 13231.1Smycroftfrc0123: 13241.1Smycroft cmpi.b #0,d0 13251.1Smycroft beq.b frc0_dst 13261.1Smycroft cmpi.b #1,d0 13271.1Smycroft beq.b frc1_dst 13281.1Smycroft cmpi.b #2,d0 13291.1Smycroft beq.b frc2_dst 13301.1Smycroftfrc3_dst: 13311.1Smycroft move.l WBTEMP_EX(a6),USER_FP3(a6) 13321.1Smycroft move.l WBTEMP_HI(a6),USER_FP3+4(a6) 13331.1Smycroft move.l WBTEMP_LO(a6),USER_FP3+8(a6) 13341.1Smycroft rts 13351.1Smycroftfrc2_dst: 13361.1Smycroft move.l WBTEMP_EX(a6),USER_FP2(a6) 13371.1Smycroft move.l WBTEMP_HI(a6),USER_FP2+4(a6) 13381.1Smycroft move.l WBTEMP_LO(a6),USER_FP2+8(a6) 13391.1Smycroft rts 13401.1Smycroftfrc1_dst: 13411.1Smycroft move.l WBTEMP_EX(a6),USER_FP1(a6) 13421.1Smycroft move.l WBTEMP_HI(a6),USER_FP1+4(a6) 13431.1Smycroft move.l WBTEMP_LO(a6),USER_FP1+8(a6) 13441.1Smycroft rts 13451.1Smycroftfrc0_dst: 13461.1Smycroft move.l WBTEMP_EX(a6),USER_FP0(a6) 13471.1Smycroft move.l WBTEMP_HI(a6),USER_FP0+4(a6) 13481.1Smycroft move.l WBTEMP_LO(a6),USER_FP0+8(a6) 13491.1Smycroft rts 13501.1Smycroft 13511.1Smycroft* 13521.1Smycroft* Write etemp to fpn. 13531.1Smycroft* A check is made on enabled and signalled snan exceptions, 13541.1Smycroft* and the destination is not overwritten if this condition exists. 13551.1Smycroft* This code is designed to make fmoveins of unsupported data types 13561.1Smycroft* faster. 13571.1Smycroft* 13581.1Smycroftwr_etemp: 13591.1Smycroft btst.b #snan_bit,FPSR_EXCEPT(a6) ;if snan is set, and 13601.1Smycroft beq.b fmoveinc ;enabled, force restore 13611.1Smycroft btst.b #snan_bit,FPCR_ENABLE(a6) ;and don't overwrite 13621.1Smycroft beq.b fmoveinc ;the dest 13631.1Smycroft move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for 13641.1Smycroft* ;snan handler 13651.1Smycroft tst.b ETEMP(a6) ;check for negative 13661.1Smycroft blt.b snan_neg 13671.1Smycroft rts 13681.1Smycroftsnan_neg: 13691.1Smycroft or.l #neg_bit,USER_FPSR(a6) ;snan is negative; set N 13701.1Smycroft rts 13711.1Smycroftfmoveinc: 13721.1Smycroft clr.w NMNEXC(a6) 13731.1Smycroft bclr.b #E1,E_BYTE(a6) 13741.1Smycroft move.b STAG(a6),d0 ;check if stag is inf 13751.1Smycroft andi.b #$e0,d0 13761.1Smycroft cmpi.b #$40,d0 13771.1Smycroft bne.b fminc_cnan 13781.1Smycroft or.l #inf_mask,USER_FPSR(a6) ;if inf, nothing yet has set I 13791.1Smycroft tst.w LOCAL_EX(a0) ;check sign 13801.1Smycroft bge.b fminc_con 13811.1Smycroft or.l #neg_mask,USER_FPSR(a6) 13821.1Smycroft bra fminc_con 13831.1Smycroftfminc_cnan: 13841.1Smycroft cmpi.b #$60,d0 ;check if stag is NaN 13851.1Smycroft bne.b fminc_czero 13861.1Smycroft or.l #nan_mask,USER_FPSR(a6) ;if nan, nothing yet has set NaN 13871.1Smycroft move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for 13881.1Smycroft* ;snan handler 13891.1Smycroft tst.w LOCAL_EX(a0) ;check sign 13901.1Smycroft bge.b fminc_con 13911.1Smycroft or.l #neg_mask,USER_FPSR(a6) 13921.1Smycroft bra fminc_con 13931.1Smycroftfminc_czero: 13941.1Smycroft cmpi.b #$20,d0 ;check if zero 13951.1Smycroft bne.b fminc_con 13961.1Smycroft or.l #z_mask,USER_FPSR(a6) ;if zero, set Z 13971.1Smycroft tst.w LOCAL_EX(a0) ;check sign 13981.1Smycroft bge.b fminc_con 13991.1Smycroft or.l #neg_mask,USER_FPSR(a6) 14001.1Smycroftfminc_con: 14011.1Smycroft bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register 14021.1Smycroft cmpi.b #3,d0 14031.1Smycroft ble.b fp0123 ;check if dest is fp0-fp3 14041.1Smycroft move.l #7,d1 14051.1Smycroft sub.l d0,d1 14061.1Smycroft clr.l d0 14071.1Smycroft bset.l d1,d0 14081.1Smycroft fmovem.x ETEMP(a6),d0 14091.1Smycroft rts 14101.1Smycroft 14111.1Smycroftfp0123: 14121.1Smycroft cmpi.b #0,d0 14131.1Smycroft beq.b fp0_dst 14141.1Smycroft cmpi.b #1,d0 14151.1Smycroft beq.b fp1_dst 14161.1Smycroft cmpi.b #2,d0 14171.1Smycroft beq.b fp2_dst 14181.1Smycroftfp3_dst: 14191.1Smycroft move.l ETEMP_EX(a6),USER_FP3(a6) 14201.1Smycroft move.l ETEMP_HI(a6),USER_FP3+4(a6) 14211.1Smycroft move.l ETEMP_LO(a6),USER_FP3+8(a6) 14221.1Smycroft rts 14231.1Smycroftfp2_dst: 14241.1Smycroft move.l ETEMP_EX(a6),USER_FP2(a6) 14251.1Smycroft move.l ETEMP_HI(a6),USER_FP2+4(a6) 14261.1Smycroft move.l ETEMP_LO(a6),USER_FP2+8(a6) 14271.1Smycroft rts 14281.1Smycroftfp1_dst: 14291.1Smycroft move.l ETEMP_EX(a6),USER_FP1(a6) 14301.1Smycroft move.l ETEMP_HI(a6),USER_FP1+4(a6) 14311.1Smycroft move.l ETEMP_LO(a6),USER_FP1+8(a6) 14321.1Smycroft rts 14331.1Smycroftfp0_dst: 14341.1Smycroft move.l ETEMP_EX(a6),USER_FP0(a6) 14351.1Smycroft move.l ETEMP_HI(a6),USER_FP0+4(a6) 14361.1Smycroft move.l ETEMP_LO(a6),USER_FP0+8(a6) 14371.1Smycroft rts 14381.1Smycroft 14391.1Smycroftopclass3: 14401.1Smycroft st.b CU_ONLY(a6) 14411.1Smycroft move.w CMDREG1B(a6),d0 ;check if packed moveout 14421.1Smycroft andi.w #$0c00,d0 ;isolate last 2 bits of size field 14431.1Smycroft cmpi.w #$0c00,d0 ;if size is 011 or 111, it is packed 14441.1Smycroft beq.w pack_out ;else it is norm or denorm 14451.1Smycroft bra.w mv_out 14461.1Smycroft 14471.1Smycroft 14481.1Smycroft* 14491.1Smycroft* MOVE OUT 14501.1Smycroft* 14511.1Smycroft 14521.1Smycroftmv_tbl: 14531.1Smycroft dc.l li 14541.1Smycroft dc.l sgp 14551.1Smycroft dc.l xp 14561.1Smycroft dc.l mvout_end ;should never be taken 14571.1Smycroft dc.l wi 14581.1Smycroft dc.l dp 14591.1Smycroft dc.l bi 14601.1Smycroft dc.l mvout_end ;should never be taken 14611.1Smycroftmv_out: 14621.1Smycroft bfextu CMDREG1B(a6){3:3},d1 ;put source specifier in d1 14631.1Smycroft lea.l mv_tbl,a0 14641.1Smycroft move.l (a0,d1*4),a0 14651.1Smycroft jmp (a0) 14661.1Smycroft 14671.1Smycroft* 14681.1Smycroft* This exit is for move-out to memory. The aunfl bit is 14691.1Smycroft* set if the result is inex and unfl is signalled. 14701.1Smycroft* 14711.1Smycroftmvout_end: 14721.1Smycroft btst.b #inex2_bit,FPSR_EXCEPT(a6) 14731.1Smycroft beq.b no_aufl 14741.1Smycroft btst.b #unfl_bit,FPSR_EXCEPT(a6) 14751.1Smycroft beq.b no_aufl 14761.1Smycroft bset.b #aunfl_bit,FPSR_AEXCEPT(a6) 14771.1Smycroftno_aufl: 14781.1Smycroft clr.w NMNEXC(a6) 14791.1Smycroft bclr.b #E1,E_BYTE(a6) 14801.1Smycroft fmove.l #0,FPSR ;clear any cc bits from res_func 14811.1Smycroft* 14821.1Smycroft* Return ETEMP to extended format from internal extended format so 14831.1Smycroft* that gen_except will have a correctly signed value for ovfl/unfl 14841.1Smycroft* handlers. 14851.1Smycroft* 14861.1Smycroft bfclr ETEMP_SGN(a6){0:8} 14871.1Smycroft beq.b mvout_con 14881.1Smycroft bset.b #sign_bit,ETEMP_EX(a6) 14891.1Smycroftmvout_con: 14901.1Smycroft rts 14911.1Smycroft* 14921.1Smycroft* This exit is for move-out to int register. The aunfl bit is 14931.1Smycroft* not set in any case for this move. 14941.1Smycroft* 14951.1Smycroftmvouti_end: 14961.1Smycroft clr.w NMNEXC(a6) 14971.1Smycroft bclr.b #E1,E_BYTE(a6) 14981.1Smycroft fmove.l #0,FPSR ;clear any cc bits from res_func 14991.1Smycroft* 15001.1Smycroft* Return ETEMP to extended format from internal extended format so 15011.1Smycroft* that gen_except will have a correctly signed value for ovfl/unfl 15021.1Smycroft* handlers. 15031.1Smycroft* 15041.1Smycroft bfclr ETEMP_SGN(a6){0:8} 15051.1Smycroft beq.b mvouti_con 15061.1Smycroft bset.b #sign_bit,ETEMP_EX(a6) 15071.1Smycroftmvouti_con: 15081.1Smycroft rts 15091.1Smycroft* 15101.1Smycroft* li is used to handle a long integer source specifier 15111.1Smycroft* 15121.1Smycroft 15131.1Smycroftli: 15141.1Smycroft moveq.l #4,d0 ;set byte count 15151.1Smycroft 15161.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 15171.1Smycroft bne.w int_dnrm ;if so, branch 15181.1Smycroft 15191.1Smycroft fmovem.x ETEMP(a6),fp0 15201.1Smycroft fcmp.d #:41dfffffffc00000,fp0 15211.1Smycroft* 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec 15221.1Smycroft fbge.w lo_plrg 15231.1Smycroft fcmp.d #:c1e0000000000000,fp0 15241.1Smycroft* c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec 15251.1Smycroft fble.w lo_nlrg 15261.1Smycroft* 15271.1Smycroft* at this point, the answer is between the largest pos and neg values 15281.1Smycroft* 15291.1Smycroft move.l USER_FPCR(a6),d1 ;use user's rounding mode 15301.1Smycroft andi.l #$30,d1 15311.1Smycroft fmove.l d1,fpcr 15321.1Smycroft fmove.l fp0,L_SCR1(a6) ;let the 040 perform conversion 15331.1Smycroft fmove.l fpsr,d1 15341.1Smycroft or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set 15351.1Smycroft bra.w int_wrt 15361.1Smycroft 15371.1Smycroft 15381.1Smycroftlo_plrg: 15391.1Smycroft move.l #$7fffffff,L_SCR1(a6) ;answer is largest positive int 15401.1Smycroft fbeq.w int_wrt ;exact answer 15411.1Smycroft fcmp.d #:41dfffffffe00000,fp0 15421.1Smycroft* 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec 15431.1Smycroft fbge.w int_operr ;set operr 15441.1Smycroft bra.w int_inx ;set inexact 15451.1Smycroft 15461.1Smycroftlo_nlrg: 15471.1Smycroft move.l #$80000000,L_SCR1(a6) 15481.1Smycroft fbeq.w int_wrt ;exact answer 15491.1Smycroft fcmp.d #:c1e0000000100000,fp0 15501.1Smycroft* c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec 15511.1Smycroft fblt.w int_operr ;set operr 15521.1Smycroft bra.w int_inx ;set inexact 15531.1Smycroft 15541.1Smycroft* 15551.1Smycroft* wi is used to handle a word integer source specifier 15561.1Smycroft* 15571.1Smycroft 15581.1Smycroftwi: 15591.1Smycroft moveq.l #2,d0 ;set byte count 15601.1Smycroft 15611.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 15621.1Smycroft bne.w int_dnrm ;branch if so 15631.1Smycroft 15641.1Smycroft fmovem.x ETEMP(a6),fp0 15651.1Smycroft fcmp.s #:46fffe00,fp0 15661.1Smycroft* 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec 15671.1Smycroft fbge.w wo_plrg 15681.1Smycroft fcmp.s #:c7000000,fp0 15691.1Smycroft* c7000000 in sgl prec = c00e00008000000000000000 in ext prec 15701.1Smycroft fble.w wo_nlrg 15711.1Smycroft 15721.1Smycroft* 15731.1Smycroft* at this point, the answer is between the largest pos and neg values 15741.1Smycroft* 15751.1Smycroft move.l USER_FPCR(a6),d1 ;use user's rounding mode 15761.1Smycroft andi.l #$30,d1 15771.1Smycroft fmove.l d1,fpcr 15781.1Smycroft fmove.w fp0,L_SCR1(a6) ;let the 040 perform conversion 15791.1Smycroft fmove.l fpsr,d1 15801.1Smycroft or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set 15811.1Smycroft bra.w int_wrt 15821.1Smycroft 15831.1Smycroftwo_plrg: 15841.1Smycroft move.w #$7fff,L_SCR1(a6) ;answer is largest positive int 15851.1Smycroft fbeq.w int_wrt ;exact answer 15861.1Smycroft fcmp.s #:46ffff00,fp0 15871.1Smycroft* 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec 15881.1Smycroft fbge.w int_operr ;set operr 15891.1Smycroft bra.w int_inx ;set inexact 15901.1Smycroft 15911.1Smycroftwo_nlrg: 15921.1Smycroft move.w #$8000,L_SCR1(a6) 15931.1Smycroft fbeq.w int_wrt ;exact answer 15941.1Smycroft fcmp.s #:c7000080,fp0 15951.1Smycroft* c7000080 in sgl prec = c00e00008000800000000000 in ext prec 15961.1Smycroft fblt.w int_operr ;set operr 15971.1Smycroft bra.w int_inx ;set inexact 15981.1Smycroft 15991.1Smycroft* 16001.1Smycroft* bi is used to handle a byte integer source specifier 16011.1Smycroft* 16021.1Smycroft 16031.1Smycroftbi: 16041.1Smycroft moveq.l #1,d0 ;set byte count 16051.1Smycroft 16061.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 16071.1Smycroft bne.w int_dnrm ;branch if so 16081.1Smycroft 16091.1Smycroft fmovem.x ETEMP(a6),fp0 16101.1Smycroft fcmp.s #:42fe0000,fp0 16111.1Smycroft* 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec 16121.1Smycroft fbge.w by_plrg 16131.1Smycroft fcmp.s #:c3000000,fp0 16141.1Smycroft* c3000000 in sgl prec = c00600008000000000000000 in ext prec 16151.1Smycroft fble.w by_nlrg 16161.1Smycroft 16171.1Smycroft* 16181.1Smycroft* at this point, the answer is between the largest pos and neg values 16191.1Smycroft* 16201.1Smycroft move.l USER_FPCR(a6),d1 ;use user's rounding mode 16211.1Smycroft andi.l #$30,d1 16221.1Smycroft fmove.l d1,fpcr 16231.1Smycroft fmove.b fp0,L_SCR1(a6) ;let the 040 perform conversion 16241.1Smycroft fmove.l fpsr,d1 16251.1Smycroft or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set 16261.1Smycroft bra.w int_wrt 16271.1Smycroft 16281.1Smycroftby_plrg: 16291.1Smycroft move.b #$7f,L_SCR1(a6) ;answer is largest positive int 16301.1Smycroft fbeq.w int_wrt ;exact answer 16311.1Smycroft fcmp.s #:42ff0000,fp0 16321.1Smycroft* 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec 16331.1Smycroft fbge.w int_operr ;set operr 16341.1Smycroft bra.w int_inx ;set inexact 16351.1Smycroft 16361.1Smycroftby_nlrg: 16371.1Smycroft move.b #$80,L_SCR1(a6) 16381.1Smycroft fbeq.w int_wrt ;exact answer 16391.1Smycroft fcmp.s #:c3008000,fp0 16401.1Smycroft* c3008000 in sgl prec = c00600008080000000000000 in ext prec 16411.1Smycroft fblt.w int_operr ;set operr 16421.1Smycroft bra.w int_inx ;set inexact 16431.1Smycroft 16441.1Smycroft* 16451.1Smycroft* Common integer routines 16461.1Smycroft* 16471.1Smycroft* int_drnrm---account for possible nonzero result for round up with positive 16481.1Smycroft* operand and round down for negative answer. In the first case (result = 1) 16491.1Smycroft* byte-width (store in d0) of result must be honored. In the second case, 16501.1Smycroft* -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out). 16511.1Smycroft 16521.1Smycroftint_dnrm: 16531.1Smycroft move.l #0,L_SCR1(a6) ; initialize result to 0 16541.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ; d1 is the rounding mode 16551.1Smycroft cmp.b #2,d1 16561.1Smycroft bmi.b int_inx ; if RN or RZ, done 16571.1Smycroft bne.b int_rp ; if RP, continue below 16581.1Smycroft tst.w ETEMP(a6) ; RM: store -1 in L_SCR1 if src is negative 16591.1Smycroft bpl.b int_inx ; otherwise result is 0 16601.1Smycroft move.l #-1,L_SCR1(a6) 16611.1Smycroft bra.b int_inx 16621.1Smycroftint_rp: 16631.1Smycroft tst.w ETEMP(a6) ; RP: store +1 of proper width in L_SCR1 if 16641.1Smycroft* ; source is greater than 0 16651.1Smycroft bmi.b int_inx ; otherwise, result is 0 16661.1Smycroft lea L_SCR1(a6),a1 ; a1 is address of L_SCR1 16671.1Smycroft adda.l d0,a1 ; offset by destination width -1 16681.1Smycroft suba.l #1,a1 16691.1Smycroft bset.b #0,(a1) ; set low bit at a1 address 16701.1Smycroftint_inx: 16711.1Smycroft ori.l #inx2a_mask,USER_FPSR(a6) 16721.1Smycroft bra.b int_wrt 16731.1Smycroftint_operr: 16741.1Smycroft fmovem.x fp0,FPTEMP(a6) ;FPTEMP must contain the extended 16751.1Smycroft* ;precision source that needs to be 16761.1Smycroft* ;converted to integer this is required 16771.1Smycroft* ;if the operr exception is enabled. 16781.1Smycroft* ;set operr/aiop (no inex2 on int ovfl) 16791.1Smycroft 16801.1Smycroft ori.l #opaop_mask,USER_FPSR(a6) 16811.1Smycroft* ;fall through to perform int_wrt 16821.1Smycroftint_wrt: 16831.1Smycroft move.l EXC_EA(a6),a1 ;load destination address 16841.1Smycroft tst.l a1 ;check to see if it is a dest register 16851.1Smycroft beq.b wrt_dn ;write data register 16861.1Smycroft lea L_SCR1(a6),a0 ;point to supervisor source address 16871.1Smycroft bsr.l mem_write 16881.1Smycroft bra.w mvouti_end 16891.1Smycroft 16901.1Smycroftwrt_dn: 16911.1Smycroft move.l d0,-(sp) ;d0 currently contains the size to write 16921.1Smycroft bsr.l get_fline ;get_fline returns Dn in d0 16931.1Smycroft andi.w #$7,d0 ;isolate register 16941.1Smycroft move.l (sp)+,d1 ;get size 16951.1Smycroft cmpi.l #4,d1 ;most frequent case 16961.1Smycroft beq.b sz_long 16971.1Smycroft cmpi.l #2,d1 16981.1Smycroft bne.b sz_con 16991.1Smycroft or.l #8,d0 ;add 'word' size to register# 17001.1Smycroft bra.b sz_con 17011.1Smycroftsz_long: 17021.1Smycroft or.l #$10,d0 ;add 'long' size to register# 17031.1Smycroftsz_con: 17041.1Smycroft move.l d0,d1 ;reg_dest expects size:reg in d1 17051.1Smycroft bsr.l reg_dest ;load proper data register 17061.1Smycroft bra.w mvouti_end 17071.1Smycroftxp: 17081.1Smycroft lea ETEMP(a6),a0 17091.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 17101.1Smycroft sne LOCAL_SGN(a0) 17111.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 17121.1Smycroft bne.w xdnrm 17131.1Smycroft clr.l d0 17141.1Smycroft bra.b do_fp ;do normal case 17151.1Smycroftsgp: 17161.1Smycroft lea ETEMP(a6),a0 17171.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 17181.1Smycroft sne LOCAL_SGN(a0) 17191.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 17201.1Smycroft bne.w sp_catas ;branch if so 17211.1Smycroft move.w LOCAL_EX(a0),d0 17221.1Smycroft lea sp_bnds,a1 17231.1Smycroft cmp.w (a1),d0 17241.1Smycroft blt.w sp_under 17251.1Smycroft cmp.w 2(a1),d0 17261.1Smycroft bgt.w sp_over 17271.1Smycroft move.l #1,d0 ;set destination format to single 17281.1Smycroft bra.b do_fp ;do normal case 17291.1Smycroftdp: 17301.1Smycroft lea ETEMP(a6),a0 17311.1Smycroft bclr.b #sign_bit,LOCAL_EX(a0) 17321.1Smycroft sne LOCAL_SGN(a0) 17331.1Smycroft 17341.1Smycroft btst.b #7,STAG(a6) ;check for extended denorm 17351.1Smycroft bne.w dp_catas ;branch if so 17361.1Smycroft 17371.1Smycroft move.w LOCAL_EX(a0),d0 17381.1Smycroft lea dp_bnds,a1 17391.1Smycroft 17401.1Smycroft cmp.w (a1),d0 17411.1Smycroft blt.w dp_under 17421.1Smycroft cmp.w 2(a1),d0 17431.1Smycroft bgt.w dp_over 17441.1Smycroft 17451.1Smycroft move.l #2,d0 ;set destination format to double 17461.1Smycroft* ;fall through to do_fp 17471.1Smycroft* 17481.1Smycroftdo_fp: 17491.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ;rnd mode in d1 17501.1Smycroft swap d0 ;rnd prec in upper word 17511.1Smycroft add.l d0,d1 ;d1 has PREC/MODE info 17521.1Smycroft 17531.1Smycroft clr.l d0 ;clear g,r,s 17541.1Smycroft 17551.1Smycroft bsr.l round ;round 17561.1Smycroft 17571.1Smycroft move.l a0,a1 17581.1Smycroft move.l EXC_EA(a6),a0 17591.1Smycroft 17601.1Smycroft bfextu CMDREG1B(a6){3:3},d1 ;extract destination format 17611.1Smycroft* ;at this point only the dest 17621.1Smycroft* ;formats sgl, dbl, ext are 17631.1Smycroft* ;possible 17641.1Smycroft cmp.b #2,d1 17651.1Smycroft bgt.b ddbl ;double=5, extended=2, single=1 17661.1Smycroft bne.b dsgl 17671.1Smycroft* ;fall through to dext 17681.1Smycroftdext: 17691.1Smycroft bsr.l dest_ext 17701.1Smycroft bra.w mvout_end 17711.1Smycroftdsgl: 17721.1Smycroft bsr.l dest_sgl 17731.1Smycroft bra.w mvout_end 17741.1Smycroftddbl: 17751.1Smycroft bsr.l dest_dbl 17761.1Smycroft bra.w mvout_end 17771.1Smycroft 17781.1Smycroft* 17791.1Smycroft* Handle possible denorm or catastrophic underflow cases here 17801.1Smycroft* 17811.1Smycroftxdnrm: 17821.1Smycroft bsr.w set_xop ;initialize WBTEMP 17831.1Smycroft bset.b #wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15 17841.1Smycroft 17851.1Smycroft move.l a0,a1 17861.1Smycroft move.l EXC_EA(a6),a0 ;a0 has the destination pointer 17871.1Smycroft bsr.l dest_ext ;store to memory 17881.1Smycroft bset.b #unfl_bit,FPSR_EXCEPT(a6) 17891.1Smycroft bra.w mvout_end 17901.1Smycroft 17911.1Smycroftsp_under: 17921.1Smycroft bset.b #etemp15_bit,STAG(a6) 17931.1Smycroft 17941.1Smycroft cmp.w 4(a1),d0 17951.1Smycroft blt.b sp_catas ;catastrophic underflow case 17961.1Smycroft 17971.1Smycroft move.l #1,d0 ;load in round precision 17981.1Smycroft move.l #sgl_thresh,d1 ;load in single denorm threshold 17991.1Smycroft bsr.l dpspdnrm ;expects d1 to have the proper 18001.1Smycroft* ;denorm threshold 18011.1Smycroft bsr.l dest_sgl ;stores value to destination 18021.1Smycroft bset.b #unfl_bit,FPSR_EXCEPT(a6) 18031.1Smycroft bra.w mvout_end ;exit 18041.1Smycroft 18051.1Smycroftdp_under: 18061.1Smycroft bset.b #etemp15_bit,STAG(a6) 18071.1Smycroft 18081.1Smycroft cmp.w 4(a1),d0 18091.1Smycroft blt.b dp_catas ;catastrophic underflow case 18101.1Smycroft 18111.1Smycroft move.l #dbl_thresh,d1 ;load in double precision threshold 18121.1Smycroft move.l #2,d0 18131.1Smycroft bsr.l dpspdnrm ;expects d1 to have proper 18141.1Smycroft* ;denorm threshold 18151.1Smycroft* ;expects d0 to have round precision 18161.1Smycroft bsr.l dest_dbl ;store value to destination 18171.1Smycroft bset.b #unfl_bit,FPSR_EXCEPT(a6) 18181.1Smycroft bra.w mvout_end ;exit 18191.1Smycroft 18201.1Smycroft* 18211.1Smycroft* Handle catastrophic underflow cases here 18221.1Smycroft* 18231.1Smycroftsp_catas: 18241.1Smycroft* Temp fix for z bit set in unf_sub 18251.1Smycroft move.l USER_FPSR(a6),-(a7) 18261.1Smycroft 18271.1Smycroft move.l #1,d0 ;set round precision to sgl 18281.1Smycroft 18291.1Smycroft bsr.l unf_sub ;a0 points to result 18301.1Smycroft 18311.1Smycroft move.l (a7)+,USER_FPSR(a6) 18321.1Smycroft 18331.1Smycroft move.l #1,d0 18341.1Smycroft sub.w d0,LOCAL_EX(a0) ;account for difference between 18351.1Smycroft* ;denorm/norm bias 18361.1Smycroft 18371.1Smycroft move.l a0,a1 ;a1 has the operand input 18381.1Smycroft move.l EXC_EA(a6),a0 ;a0 has the destination pointer 18391.1Smycroft 18401.1Smycroft bsr.l dest_sgl ;store the result 18411.1Smycroft ori.l #unfinx_mask,USER_FPSR(a6) 18421.1Smycroft bra.w mvout_end 18431.1Smycroft 18441.1Smycroftdp_catas: 18451.1Smycroft* Temp fix for z bit set in unf_sub 18461.1Smycroft move.l USER_FPSR(a6),-(a7) 18471.1Smycroft 18481.1Smycroft move.l #2,d0 ;set round precision to dbl 18491.1Smycroft bsr.l unf_sub ;a0 points to result 18501.1Smycroft 18511.1Smycroft move.l (a7)+,USER_FPSR(a6) 18521.1Smycroft 18531.1Smycroft move.l #1,d0 18541.1Smycroft sub.w d0,LOCAL_EX(a0) ;account for difference between 18551.1Smycroft* ;denorm/norm bias 18561.1Smycroft 18571.1Smycroft move.l a0,a1 ;a1 has the operand input 18581.1Smycroft move.l EXC_EA(a6),a0 ;a0 has the destination pointer 18591.1Smycroft 18601.1Smycroft bsr.l dest_dbl ;store the result 18611.1Smycroft ori.l #unfinx_mask,USER_FPSR(a6) 18621.1Smycroft bra.w mvout_end 18631.1Smycroft 18641.1Smycroft* 18651.1Smycroft* Handle catastrophic overflow cases here 18661.1Smycroft* 18671.1Smycroftsp_over: 18681.1Smycroft* Temp fix for z bit set in unf_sub 18691.1Smycroft move.l USER_FPSR(a6),-(a7) 18701.1Smycroft 18711.1Smycroft move.l #1,d0 18721.1Smycroft lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result 18731.1Smycroft move.l ETEMP_EX(a6),(a0) 18741.1Smycroft move.l ETEMP_HI(a6),4(a0) 18751.1Smycroft move.l ETEMP_LO(a6),8(a0) 18761.1Smycroft bsr.l ovf_res 18771.1Smycroft 18781.1Smycroft move.l (a7)+,USER_FPSR(a6) 18791.1Smycroft 18801.1Smycroft move.l a0,a1 18811.1Smycroft move.l EXC_EA(a6),a0 18821.1Smycroft bsr.l dest_sgl 18831.1Smycroft or.l #ovfinx_mask,USER_FPSR(a6) 18841.1Smycroft bra.w mvout_end 18851.1Smycroft 18861.1Smycroftdp_over: 18871.1Smycroft* Temp fix for z bit set in ovf_res 18881.1Smycroft move.l USER_FPSR(a6),-(a7) 18891.1Smycroft 18901.1Smycroft move.l #2,d0 18911.1Smycroft lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result 18921.1Smycroft move.l ETEMP_EX(a6),(a0) 18931.1Smycroft move.l ETEMP_HI(a6),4(a0) 18941.1Smycroft move.l ETEMP_LO(a6),8(a0) 18951.1Smycroft bsr.l ovf_res 18961.1Smycroft 18971.1Smycroft move.l (a7)+,USER_FPSR(a6) 18981.1Smycroft 18991.1Smycroft move.l a0,a1 19001.1Smycroft move.l EXC_EA(a6),a0 19011.1Smycroft bsr.l dest_dbl 19021.1Smycroft or.l #ovfinx_mask,USER_FPSR(a6) 19031.1Smycroft bra.w mvout_end 19041.1Smycroft 19051.1Smycroft* 19061.1Smycroft* DPSPDNRM 19071.1Smycroft* 19081.1Smycroft* This subroutine takes an extended normalized number and denormalizes 19091.1Smycroft* it to the given round precision. This subroutine also decrements 19101.1Smycroft* the input operand's exponent by 1 to account for the fact that 19111.1Smycroft* dest_sgl or dest_dbl expects a normalized number's bias. 19121.1Smycroft* 19131.1Smycroft* Input: a0 points to a normalized number in internal extended format 19141.1Smycroft* d0 is the round precision (=1 for sgl; =2 for dbl) 19151.1Smycroft* d1 is the the single precision or double precision 19161.1Smycroft* denorm threshold 19171.1Smycroft* 19181.1Smycroft* Output: (In the format for dest_sgl or dest_dbl) 19191.1Smycroft* a0 points to the destination 19201.1Smycroft* a1 points to the operand 19211.1Smycroft* 19221.1Smycroft* Exceptions: Reports inexact 2 exception by setting USER_FPSR bits 19231.1Smycroft* 19241.1Smycroftdpspdnrm: 19251.1Smycroft move.l d0,-(a7) ;save round precision 19261.1Smycroft clr.l d0 ;clear initial g,r,s 19271.1Smycroft bsr.l dnrm_lp ;careful with d0, it's needed by round 19281.1Smycroft 19291.1Smycroft bfextu FPCR_MODE(a6){2:2},d1 ;get rounding mode 19301.1Smycroft swap d1 19311.1Smycroft move.w 2(a7),d1 ;set rounding precision 19321.1Smycroft swap d1 ;at this point d1 has PREC/MODE info 19331.1Smycroft bsr.l round ;round result, sets the inex bit in 19341.1Smycroft* ;USER_FPSR if needed 19351.1Smycroft 19361.1Smycroft move.w #1,d0 19371.1Smycroft sub.w d0,LOCAL_EX(a0) ;account for difference in denorm 19381.1Smycroft* ;vs norm bias 19391.1Smycroft 19401.1Smycroft move.l a0,a1 ;a1 has the operand input 19411.1Smycroft move.l EXC_EA(a6),a0 ;a0 has the destination pointer 19421.1Smycroft add.w #4,a7 ;pop stack 19431.1Smycroft rts 19441.1Smycroft* 19451.1Smycroft* SET_XOP initialized WBTEMP with the value pointed to by a0 19461.1Smycroft* input: a0 points to input operand in the internal extended format 19471.1Smycroft* 19481.1Smycroftset_xop: 19491.1Smycroft move.l LOCAL_EX(a0),WBTEMP_EX(a6) 19501.1Smycroft move.l LOCAL_HI(a0),WBTEMP_HI(a6) 19511.1Smycroft move.l LOCAL_LO(a0),WBTEMP_LO(a6) 19521.1Smycroft bfclr WBTEMP_SGN(a6){0:8} 19531.1Smycroft beq.b sxop 19541.1Smycroft bset.b #sign_bit,WBTEMP_EX(a6) 19551.1Smycroftsxop: 19561.1Smycroft bfclr STAG(a6){5:4} ;clear wbtm66,wbtm1,wbtm0,sbit 19571.1Smycroft rts 19581.1Smycroft* 19591.1Smycroft* P_MOVE 19601.1Smycroft* 19611.1Smycroftp_movet: 19621.1Smycroft dc.l p_move 19631.1Smycroft dc.l p_movez 19641.1Smycroft dc.l p_movei 19651.1Smycroft dc.l p_moven 19661.1Smycroft dc.l p_move 19671.1Smycroftp_regd: 19681.1Smycroft dc.l p_dyd0 19691.1Smycroft dc.l p_dyd1 19701.1Smycroft dc.l p_dyd2 19711.1Smycroft dc.l p_dyd3 19721.1Smycroft dc.l p_dyd4 19731.1Smycroft dc.l p_dyd5 19741.1Smycroft dc.l p_dyd6 19751.1Smycroft dc.l p_dyd7 19761.1Smycroft 19771.1Smycroftpack_out: 19781.1Smycroft lea.l p_movet,a0 ;load jmp table address 19791.1Smycroft move.w STAG(a6),d0 ;get source tag 19801.1Smycroft bfextu d0{16:3},d0 ;isolate source bits 19811.1Smycroft move.l (a0,d0.w*4),a0 ;load a0 with routine label for tag 19821.1Smycroft jmp (a0) ;go to the routine 19831.1Smycroft 19841.1Smycroftp_write: 19851.1Smycroft move.l #$0c,d0 ;get byte count 19861.1Smycroft move.l EXC_EA(a6),a1 ;get the destination address 19871.1Smycroft bsr mem_write ;write the user's destination 19881.1Smycroft move.b #0,CU_SAVEPC(a6) ;set the cu save pc to all 0's 19891.1Smycroft 19901.1Smycroft* 19911.1Smycroft* Also note that the dtag must be set to norm here - this is because 19921.1Smycroft* the 040 uses the dtag to execute the correct microcode. 19931.1Smycroft* 19941.1Smycroft bfclr DTAG(a6){0:3} ;set dtag to norm 19951.1Smycroft 19961.1Smycroft rts 19971.1Smycroft 19981.1Smycroft* Notes on handling of special case (zero, inf, and nan) inputs: 19991.1Smycroft* 1. Operr is not signalled if the k-factor is greater than 18. 20001.1Smycroft* 2. Per the manual, status bits are not set. 20011.1Smycroft* 20021.1Smycroft 20031.1Smycroftp_move: 20041.1Smycroft move.w CMDREG1B(a6),d0 20051.1Smycroft btst.l #kfact_bit,d0 ;test for dynamic k-factor 20061.1Smycroft beq.b statick ;if clear, k-factor is static 20071.1Smycroftdynamick: 20081.1Smycroft bfextu d0{25:3},d0 ;isolate register for dynamic k-factor 20091.1Smycroft lea p_regd,a0 20101.1Smycroft move.l (a0,d0*4),a0 20111.1Smycroft jmp (a0) 20121.1Smycroftstatick: 20131.1Smycroft andi.w #$007f,d0 ;get k-factor 20141.1Smycroft bfexts d0{25:7},d0 ;sign extend d0 for bindec 20151.1Smycroft lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal 20161.1Smycroft bsr.l bindec ;perform the convert; data at a6 20171.1Smycroft lea.l FP_SCR1(a6),a0 ;load a0 with result address 20181.1Smycroft bra.l p_write 20191.1Smycroftp_movez: 20201.1Smycroft lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal 20211.1Smycroft clr.w 2(a0) ;clear lower word of exp 20221.1Smycroft clr.l 4(a0) ;load second lword of ZERO 20231.1Smycroft clr.l 8(a0) ;load third lword of ZERO 20241.1Smycroft bra.w p_write ;go write results 20251.1Smycroftp_movei: 20261.1Smycroft fmove.l #0,FPSR ;clear aiop 20271.1Smycroft lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal 20281.1Smycroft clr.w 2(a0) ;clear lower word of exp 20291.1Smycroft bra.w p_write ;go write the result 20301.1Smycroftp_moven: 20311.1Smycroft lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal 20321.1Smycroft clr.w 2(a0) ;clear lower word of exp 20331.1Smycroft bra.w p_write ;go write the result 20341.1Smycroft 20351.1Smycroft* 20361.1Smycroft* Routines to read the dynamic k-factor from Dn. 20371.1Smycroft* 20381.1Smycroftp_dyd0: 20391.1Smycroft move.l USER_D0(a6),d0 20401.1Smycroft bra.b statick 20411.1Smycroftp_dyd1: 20421.1Smycroft move.l USER_D1(a6),d0 20431.1Smycroft bra.b statick 20441.1Smycroftp_dyd2: 20451.1Smycroft move.l d2,d0 20461.1Smycroft bra.b statick 20471.1Smycroftp_dyd3: 20481.1Smycroft move.l d3,d0 20491.1Smycroft bra.b statick 20501.1Smycroftp_dyd4: 20511.1Smycroft move.l d4,d0 20521.1Smycroft bra.b statick 20531.1Smycroftp_dyd5: 20541.1Smycroft move.l d5,d0 20551.1Smycroft bra.b statick 20561.1Smycroftp_dyd6: 20571.1Smycroft move.l d6,d0 20581.1Smycroft bra.w statick 20591.1Smycroftp_dyd7: 20601.1Smycroft move.l d7,d0 20611.1Smycroft bra.w statick 20621.1Smycroft 20631.1Smycroft end 2064