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