11da177e4SLinus Torvalds| 21da177e4SLinus Torvalds| res_func.sa 3.9 7/29/91 31da177e4SLinus Torvalds| 41da177e4SLinus Torvalds| Normalizes denormalized numbers if necessary and updates the 51da177e4SLinus Torvalds| stack frame. The function is then restored back into the 61da177e4SLinus Torvalds| machine and the 040 completes the operation. This routine 71da177e4SLinus Torvalds| is only used by the unsupported data type/format handler. 81da177e4SLinus Torvalds| (Exception vector 55). 91da177e4SLinus Torvalds| 101da177e4SLinus Torvalds| For packed move out (fmove.p fpm,<ea>) the operation is 111da177e4SLinus Torvalds| completed here; data is packed and moved to user memory. 121da177e4SLinus Torvalds| The stack is restored to the 040 only in the case of a 131da177e4SLinus Torvalds| reportable exception in the conversion. 141da177e4SLinus Torvalds| 151da177e4SLinus Torvalds| 161da177e4SLinus Torvalds| Copyright (C) Motorola, Inc. 1990 171da177e4SLinus Torvalds| All Rights Reserved 181da177e4SLinus Torvalds| 19e00d82d0SMatt Waddel| For details on the license for this file, please see the 20e00d82d0SMatt Waddel| file, README, in this same directory. 211da177e4SLinus Torvalds 221da177e4SLinus TorvaldsRES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds |section 8 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds#include "fpsp.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvaldssp_bnds: .short 0x3f81,0x407e 291da177e4SLinus Torvalds .short 0x3f6a,0x0000 301da177e4SLinus Torvaldsdp_bnds: .short 0x3c01,0x43fe 311da177e4SLinus Torvalds .short 0x3bcd,0x0000 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds |xref mem_write 341da177e4SLinus Torvalds |xref bindec 351da177e4SLinus Torvalds |xref get_fline 361da177e4SLinus Torvalds |xref round 371da177e4SLinus Torvalds |xref denorm 381da177e4SLinus Torvalds |xref dest_ext 391da177e4SLinus Torvalds |xref dest_dbl 401da177e4SLinus Torvalds |xref dest_sgl 411da177e4SLinus Torvalds |xref unf_sub 421da177e4SLinus Torvalds |xref nrm_set 431da177e4SLinus Torvalds |xref dnrm_lp 441da177e4SLinus Torvalds |xref ovf_res 451da177e4SLinus Torvalds |xref reg_dest 461da177e4SLinus Torvalds |xref t_ovfl 471da177e4SLinus Torvalds |xref t_unfl 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds .global res_func 501da177e4SLinus Torvalds .global p_move 511da177e4SLinus Torvalds 521da177e4SLinus Torvaldsres_func: 531da177e4SLinus Torvalds clrb DNRM_FLG(%a6) 541da177e4SLinus Torvalds clrb RES_FLG(%a6) 551da177e4SLinus Torvalds clrb CU_ONLY(%a6) 561da177e4SLinus Torvalds tstb DY_MO_FLG(%a6) 571da177e4SLinus Torvalds beqs monadic 581da177e4SLinus Torvaldsdyadic: 591da177e4SLinus Torvalds btstb #7,DTAG(%a6) |if dop = norm=000, zero=001, 601da177e4SLinus Torvalds| ;inf=010 or nan=011 611da177e4SLinus Torvalds beqs monadic |then branch 621da177e4SLinus Torvalds| ;else denorm 631da177e4SLinus Torvalds| HANDLE DESTINATION DENORM HERE 641da177e4SLinus Torvalds| ;set dtag to norm 651da177e4SLinus Torvalds| ;write the tag & fpte15 to the fstack 661da177e4SLinus Torvalds leal FPTEMP(%a6),%a0 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 691da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds bsr nrm_set |normalize number (exp will go negative) 721da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign 731da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 741da177e4SLinus Torvalds beqs dpos 751da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 761da177e4SLinus Torvaldsdpos: 771da177e4SLinus Torvalds bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 781da177e4SLinus Torvalds bsetb #4,DTAG(%a6) |set FPTE15 791da177e4SLinus Torvalds orb #0x0f,DNRM_FLG(%a6) 801da177e4SLinus Torvaldsmonadic: 811da177e4SLinus Torvalds leal ETEMP(%a6),%a0 821da177e4SLinus Torvalds btstb #direction_bit,CMDREG1B(%a6) |check direction 831da177e4SLinus Torvalds bne opclass3 |it is a mv out 841da177e4SLinus Torvalds| 851da177e4SLinus Torvalds| At this point, only opclass 0 and 2 possible 861da177e4SLinus Torvalds| 871da177e4SLinus Torvalds btstb #7,STAG(%a6) |if sop = norm=000, zero=001, 881da177e4SLinus Torvalds| ;inf=010 or nan=011 891da177e4SLinus Torvalds bne mon_dnrm |else denorm 901da177e4SLinus Torvalds tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would 911da177e4SLinus Torvalds bne normal |require normalization of denorm 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds| At this point: 941da177e4SLinus Torvalds| monadic instructions: fabs = $18 fneg = $1a ftst = $3a 951da177e4SLinus Torvalds| fmove = $00 fsmove = $40 fdmove = $44 961da177e4SLinus Torvalds| fsqrt = $05* fssqrt = $41 fdsqrt = $45 971da177e4SLinus Torvalds| (*fsqrt reencoded to $05) 981da177e4SLinus Torvalds| 991da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 |get command register 1001da177e4SLinus Torvalds andil #0x7f,%d0 |strip to only command word 1011da177e4SLinus Torvalds| 1021da177e4SLinus Torvalds| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 1031da177e4SLinus Torvalds| fdsqrt are possible. 1041da177e4SLinus Torvalds| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 1051da177e4SLinus Torvalds| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 1061da177e4SLinus Torvalds| 1071da177e4SLinus Torvalds btstl #0,%d0 1081da177e4SLinus Torvalds bne normal |weed out fsqrt instructions 1091da177e4SLinus Torvalds| 1101da177e4SLinus Torvalds| cu_norm handles fmove in instructions with normalized inputs. 1111da177e4SLinus Torvalds| The routine round is used to correctly round the input for the 1121da177e4SLinus Torvalds| destination precision and mode. 1131da177e4SLinus Torvalds| 1141da177e4SLinus Torvaldscu_norm: 1151da177e4SLinus Torvalds st CU_ONLY(%a6) |set cu-only inst flag 1161da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 1171da177e4SLinus Torvalds andib #0x3b,%d0 |isolate bits to select inst 1181da177e4SLinus Torvalds tstb %d0 1191da177e4SLinus Torvalds beql cu_nmove |if zero, it is an fmove 1201da177e4SLinus Torvalds cmpib #0x18,%d0 1211da177e4SLinus Torvalds beql cu_nabs |if $18, it is fabs 1221da177e4SLinus Torvalds cmpib #0x1a,%d0 1231da177e4SLinus Torvalds beql cu_nneg |if $1a, it is fneg 1241da177e4SLinus Torvalds| 1251da177e4SLinus Torvalds| Inst is ftst. Check the source operand and set the cc's accordingly. 1261da177e4SLinus Torvalds| No write is done, so simply rts. 1271da177e4SLinus Torvalds| 1281da177e4SLinus Torvaldscu_ntst: 1291da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d0 1301da177e4SLinus Torvalds bclrl #15,%d0 1311da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 1321da177e4SLinus Torvalds beqs cu_ntpo 1331da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) |set N 1341da177e4SLinus Torvaldscu_ntpo: 1351da177e4SLinus Torvalds cmpiw #0x7fff,%d0 |test for inf/nan 1361da177e4SLinus Torvalds bnes cu_ntcz 1371da177e4SLinus Torvalds tstl LOCAL_HI(%a0) 1381da177e4SLinus Torvalds bnes cu_ntn 1391da177e4SLinus Torvalds tstl LOCAL_LO(%a0) 1401da177e4SLinus Torvalds bnes cu_ntn 1411da177e4SLinus Torvalds orl #inf_mask,USER_FPSR(%a6) 1421da177e4SLinus Torvalds rts 1431da177e4SLinus Torvaldscu_ntn: 1441da177e4SLinus Torvalds orl #nan_mask,USER_FPSR(%a6) 1451da177e4SLinus Torvalds movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 1461da177e4SLinus Torvalds| ;snan handler 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds rts 1491da177e4SLinus Torvaldscu_ntcz: 1501da177e4SLinus Torvalds tstl LOCAL_HI(%a0) 1511da177e4SLinus Torvalds bnel cu_ntsx 1521da177e4SLinus Torvalds tstl LOCAL_LO(%a0) 1531da177e4SLinus Torvalds bnel cu_ntsx 1541da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 1551da177e4SLinus Torvaldscu_ntsx: 1561da177e4SLinus Torvalds rts 1571da177e4SLinus Torvalds| 1581da177e4SLinus Torvalds| Inst is fabs. Execute the absolute value function on the input. 1591da177e4SLinus Torvalds| Branch to the fmove code. If the operand is NaN, do nothing. 1601da177e4SLinus Torvalds| 1611da177e4SLinus Torvaldscu_nabs: 1621da177e4SLinus Torvalds moveb STAG(%a6),%d0 1631da177e4SLinus Torvalds btstl #5,%d0 |test for NaN or zero 1641da177e4SLinus Torvalds bne wr_etemp |if either, simply write it 1651da177e4SLinus Torvalds bclrb #7,LOCAL_EX(%a0) |do abs 1661da177e4SLinus Torvalds bras cu_nmove |fmove code will finish 1671da177e4SLinus Torvalds| 1681da177e4SLinus Torvalds| Inst is fneg. Execute the negate value function on the input. 1691da177e4SLinus Torvalds| Fall though to the fmove code. If the operand is NaN, do nothing. 1701da177e4SLinus Torvalds| 1711da177e4SLinus Torvaldscu_nneg: 1721da177e4SLinus Torvalds moveb STAG(%a6),%d0 1731da177e4SLinus Torvalds btstl #5,%d0 |test for NaN or zero 1741da177e4SLinus Torvalds bne wr_etemp |if either, simply write it 1751da177e4SLinus Torvalds bchgb #7,LOCAL_EX(%a0) |do neg 1761da177e4SLinus Torvalds| 1771da177e4SLinus Torvalds| Inst is fmove. This code also handles all result writes. 1781da177e4SLinus Torvalds| If bit 2 is set, round is forced to double. If it is clear, 1791da177e4SLinus Torvalds| and bit 6 is set, round is forced to single. If both are clear, 1801da177e4SLinus Torvalds| the round precision is found in the fpcr. If the rounding precision 1811da177e4SLinus Torvalds| is double or single, round the result before the write. 1821da177e4SLinus Torvalds| 1831da177e4SLinus Torvaldscu_nmove: 1841da177e4SLinus Torvalds moveb STAG(%a6),%d0 1851da177e4SLinus Torvalds andib #0xe0,%d0 |isolate stag bits 1861da177e4SLinus Torvalds bne wr_etemp |if not norm, simply write it 1871da177e4SLinus Torvalds btstb #2,CMDREG1B+1(%a6) |check for rd 1881da177e4SLinus Torvalds bne cu_nmrd 1891da177e4SLinus Torvalds btstb #6,CMDREG1B+1(%a6) |check for rs 1901da177e4SLinus Torvalds bne cu_nmrs 1911da177e4SLinus Torvalds| 1921da177e4SLinus Torvalds| The move or operation is not with forced precision. Test for 1931da177e4SLinus Torvalds| nan or inf as the input; if so, simply write it to FPn. Use the 1941da177e4SLinus Torvalds| FPCR_MODE byte to get rounding on norms and zeros. 1951da177e4SLinus Torvalds| 1961da177e4SLinus Torvaldscu_nmnr: 1971da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#0:#2},%d0 1981da177e4SLinus Torvalds tstb %d0 |check for extended 1991da177e4SLinus Torvalds beq cu_wrexn |if so, just write result 2001da177e4SLinus Torvalds cmpib #1,%d0 |check for single 2011da177e4SLinus Torvalds beq cu_nmrs |fall through to double 2021da177e4SLinus Torvalds| 2031da177e4SLinus Torvalds| The move is fdmove or round precision is double. 2041da177e4SLinus Torvalds| 2051da177e4SLinus Torvaldscu_nmrd: 2061da177e4SLinus Torvalds movel #2,%d0 |set up the size for denorm 2071da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold 2081da177e4SLinus Torvalds andw #0x7fff,%d1 2091da177e4SLinus Torvalds cmpw #0x3c01,%d1 2101da177e4SLinus Torvalds bls cu_nunfl 2111da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 2121da177e4SLinus Torvalds orl #0x00020000,%d1 |or in rprec (double) 2131da177e4SLinus Torvalds clrl %d0 |clear g,r,s for round 2141da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format 2151da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 2161da177e4SLinus Torvalds bsrl round 2171da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} 2181da177e4SLinus Torvalds beqs cu_nmrdc 2191da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 2201da177e4SLinus Torvaldscu_nmrdc: 2211da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d1 |check for overflow 2221da177e4SLinus Torvalds andw #0x7fff,%d1 2231da177e4SLinus Torvalds cmpw #0x43ff,%d1 2241da177e4SLinus Torvalds bge cu_novfl |take care of overflow case 2251da177e4SLinus Torvalds bra cu_wrexn 2261da177e4SLinus Torvalds| 2271da177e4SLinus Torvalds| The move is fsmove or round precision is single. 2281da177e4SLinus Torvalds| 2291da177e4SLinus Torvaldscu_nmrs: 2301da177e4SLinus Torvalds movel #1,%d0 2311da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d1 2321da177e4SLinus Torvalds andw #0x7fff,%d1 2331da177e4SLinus Torvalds cmpw #0x3f81,%d1 2341da177e4SLinus Torvalds bls cu_nunfl 2351da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 2361da177e4SLinus Torvalds orl #0x00010000,%d1 2371da177e4SLinus Torvalds clrl %d0 2381da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 2391da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 2401da177e4SLinus Torvalds bsrl round 2411da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} 2421da177e4SLinus Torvalds beqs cu_nmrsc 2431da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 2441da177e4SLinus Torvaldscu_nmrsc: 2451da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d1 2461da177e4SLinus Torvalds andw #0x7FFF,%d1 2471da177e4SLinus Torvalds cmpw #0x407f,%d1 2481da177e4SLinus Torvalds blt cu_wrexn 2491da177e4SLinus Torvalds| 2501da177e4SLinus Torvalds| The operand is above precision boundaries. Use t_ovfl to 2511da177e4SLinus Torvalds| generate the correct value. 2521da177e4SLinus Torvalds| 2531da177e4SLinus Torvaldscu_novfl: 2541da177e4SLinus Torvalds bsr t_ovfl 2551da177e4SLinus Torvalds bra cu_wrexn 2561da177e4SLinus Torvalds| 2571da177e4SLinus Torvalds| The operand is below precision boundaries. Use denorm to 2581da177e4SLinus Torvalds| generate the correct value. 2591da177e4SLinus Torvalds| 2601da177e4SLinus Torvaldscu_nunfl: 2611da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 2621da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 2631da177e4SLinus Torvalds bsr denorm 2641da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 2651da177e4SLinus Torvalds beqs cu_nucont 2661da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 2671da177e4SLinus Torvaldscu_nucont: 2681da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 2691da177e4SLinus Torvalds btstb #2,CMDREG1B+1(%a6) |check for rd 2701da177e4SLinus Torvalds bne inst_d 2711da177e4SLinus Torvalds btstb #6,CMDREG1B+1(%a6) |check for rs 2721da177e4SLinus Torvalds bne inst_s 2731da177e4SLinus Torvalds swap %d1 2741da177e4SLinus Torvalds moveb FPCR_MODE(%a6),%d1 2751da177e4SLinus Torvalds lsrb #6,%d1 2761da177e4SLinus Torvalds swap %d1 2771da177e4SLinus Torvalds bra inst_sd 2781da177e4SLinus Torvaldsinst_d: 2791da177e4SLinus Torvalds orl #0x00020000,%d1 2801da177e4SLinus Torvalds bra inst_sd 2811da177e4SLinus Torvaldsinst_s: 2821da177e4SLinus Torvalds orl #0x00010000,%d1 2831da177e4SLinus Torvaldsinst_sd: 2841da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 2851da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 2861da177e4SLinus Torvalds bsrl round 2871da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} 2881da177e4SLinus Torvalds beqs cu_nuflp 2891da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 2901da177e4SLinus Torvaldscu_nuflp: 2911da177e4SLinus Torvalds btstb #inex2_bit,FPSR_EXCEPT(%a6) 2921da177e4SLinus Torvalds beqs cu_nuninx 2931da177e4SLinus Torvalds orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL 2941da177e4SLinus Torvaldscu_nuninx: 2951da177e4SLinus Torvalds tstl LOCAL_HI(%a0) |test for zero 2961da177e4SLinus Torvalds bnes cu_nunzro 2971da177e4SLinus Torvalds tstl LOCAL_LO(%a0) 2981da177e4SLinus Torvalds bnes cu_nunzro 2991da177e4SLinus Torvalds| 3001da177e4SLinus Torvalds| The mantissa is zero from the denorm loop. Check sign and rmode 3011da177e4SLinus Torvalds| to see if rounding should have occurred which would leave the lsb. 3021da177e4SLinus Torvalds| 3031da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 3041da177e4SLinus Torvalds andil #0x30,%d0 |isolate rmode 3051da177e4SLinus Torvalds cmpil #0x20,%d0 3061da177e4SLinus Torvalds blts cu_nzro 3071da177e4SLinus Torvalds bnes cu_nrp 3081da177e4SLinus Torvaldscu_nrm: 3091da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |if positive, set lsb 3101da177e4SLinus Torvalds bges cu_nzro 3111da177e4SLinus Torvalds btstb #7,FPCR_MODE(%a6) |check for double 3121da177e4SLinus Torvalds beqs cu_nincs 3131da177e4SLinus Torvalds bras cu_nincd 3141da177e4SLinus Torvaldscu_nrp: 3151da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |if positive, set lsb 3161da177e4SLinus Torvalds blts cu_nzro 3171da177e4SLinus Torvalds btstb #7,FPCR_MODE(%a6) |check for double 3181da177e4SLinus Torvalds beqs cu_nincs 3191da177e4SLinus Torvaldscu_nincd: 3201da177e4SLinus Torvalds orl #0x800,LOCAL_LO(%a0) |inc for double 3211da177e4SLinus Torvalds bra cu_nunzro 3221da177e4SLinus Torvaldscu_nincs: 3231da177e4SLinus Torvalds orl #0x100,LOCAL_HI(%a0) |inc for single 3241da177e4SLinus Torvalds bra cu_nunzro 3251da177e4SLinus Torvaldscu_nzro: 3261da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 3271da177e4SLinus Torvalds moveb STAG(%a6),%d0 3281da177e4SLinus Torvalds andib #0xe0,%d0 3291da177e4SLinus Torvalds cmpib #0x40,%d0 |check if input was tagged zero 3301da177e4SLinus Torvalds beqs cu_numv 3311da177e4SLinus Torvaldscu_nunzro: 3321da177e4SLinus Torvalds orl #unfl_mask,USER_FPSR(%a6) |set unfl 3331da177e4SLinus Torvaldscu_numv: 3341da177e4SLinus Torvalds movel (%a0),ETEMP(%a6) 3351da177e4SLinus Torvalds movel 4(%a0),ETEMP_HI(%a6) 3361da177e4SLinus Torvalds movel 8(%a0),ETEMP_LO(%a6) 3371da177e4SLinus Torvalds| 3381da177e4SLinus Torvalds| Write the result to memory, setting the fpsr cc bits. NaN and Inf 3391da177e4SLinus Torvalds| bypass cu_wrexn. 3401da177e4SLinus Torvalds| 3411da177e4SLinus Torvaldscu_wrexn: 3421da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |test for zero 3431da177e4SLinus Torvalds beqs cu_wrzero 3441da177e4SLinus Torvalds cmpw #0x8000,LOCAL_EX(%a0) |test for zero 3451da177e4SLinus Torvalds bnes cu_wreon 3461da177e4SLinus Torvaldscu_wrzero: 3471da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) |set Z bit 3481da177e4SLinus Torvaldscu_wreon: 3491da177e4SLinus Torvalds tstw LOCAL_EX(%a0) 3501da177e4SLinus Torvalds bpl wr_etemp 3511da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 3521da177e4SLinus Torvalds bra wr_etemp 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds| 3551da177e4SLinus Torvalds| HANDLE SOURCE DENORM HERE 3561da177e4SLinus Torvalds| 3571da177e4SLinus Torvalds| ;clear denorm stag to norm 3581da177e4SLinus Torvalds| ;write the new tag & ete15 to the fstack 3591da177e4SLinus Torvaldsmon_dnrm: 3601da177e4SLinus Torvalds| 3611da177e4SLinus Torvalds| At this point, check for the cases in which normalizing the 3621da177e4SLinus Torvalds| denorm produces incorrect results. 3631da177e4SLinus Torvalds| 3641da177e4SLinus Torvalds tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would 3651da177e4SLinus Torvalds bnes nrm_src |require normalization of denorm 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds| At this point: 3681da177e4SLinus Torvalds| monadic instructions: fabs = $18 fneg = $1a ftst = $3a 3691da177e4SLinus Torvalds| fmove = $00 fsmove = $40 fdmove = $44 3701da177e4SLinus Torvalds| fsqrt = $05* fssqrt = $41 fdsqrt = $45 3711da177e4SLinus Torvalds| (*fsqrt reencoded to $05) 3721da177e4SLinus Torvalds| 3731da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 |get command register 3741da177e4SLinus Torvalds andil #0x7f,%d0 |strip to only command word 3751da177e4SLinus Torvalds| 3761da177e4SLinus Torvalds| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 3771da177e4SLinus Torvalds| fdsqrt are possible. 3781da177e4SLinus Torvalds| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 3791da177e4SLinus Torvalds| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 3801da177e4SLinus Torvalds| 3811da177e4SLinus Torvalds btstl #0,%d0 3821da177e4SLinus Torvalds bnes nrm_src |weed out fsqrt instructions 3831da177e4SLinus Torvalds st CU_ONLY(%a6) |set cu-only inst flag 3841da177e4SLinus Torvalds bra cu_dnrm |fmove, fabs, fneg, ftst 3851da177e4SLinus Torvalds| ;cases go to cu_dnrm 3861da177e4SLinus Torvaldsnrm_src: 3871da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 3881da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 3891da177e4SLinus Torvalds bsr nrm_set |normalize number (exponent will go 3901da177e4SLinus Torvalds| ; negative) 3911da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 3941da177e4SLinus Torvalds beqs spos 3951da177e4SLinus Torvalds bsetb #sign_bit,LOCAL_EX(%a0) 3961da177e4SLinus Torvaldsspos: 3971da177e4SLinus Torvalds bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 3981da177e4SLinus Torvalds bsetb #4,STAG(%a6) |set ETE15 3991da177e4SLinus Torvalds orb #0xf0,DNRM_FLG(%a6) 4001da177e4SLinus Torvaldsnormal: 4011da177e4SLinus Torvalds tstb DNRM_FLG(%a6) |check if any of the ops were denorms 4021da177e4SLinus Torvalds bne ck_wrap |if so, check if it is a potential 4031da177e4SLinus Torvalds| ;wrap-around case 4041da177e4SLinus Torvaldsfix_stk: 4051da177e4SLinus Torvalds moveb #0xfe,CU_SAVEPC(%a6) 4061da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds clrw NMNEXC(%a6) 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds st RES_FLG(%a6) |indicate that a restore is needed 4111da177e4SLinus Torvalds rts 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds| 4141da177e4SLinus Torvalds| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and 4151da177e4SLinus Torvalds| ftst) completely in software without an frestore to the 040. 4161da177e4SLinus Torvalds| 4171da177e4SLinus Torvaldscu_dnrm: 4181da177e4SLinus Torvalds st CU_ONLY(%a6) 4191da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 4201da177e4SLinus Torvalds andib #0x3b,%d0 |isolate bits to select inst 4211da177e4SLinus Torvalds tstb %d0 4221da177e4SLinus Torvalds beql cu_dmove |if zero, it is an fmove 4231da177e4SLinus Torvalds cmpib #0x18,%d0 4241da177e4SLinus Torvalds beql cu_dabs |if $18, it is fabs 4251da177e4SLinus Torvalds cmpib #0x1a,%d0 4261da177e4SLinus Torvalds beql cu_dneg |if $1a, it is fneg 4271da177e4SLinus Torvalds| 4281da177e4SLinus Torvalds| Inst is ftst. Check the source operand and set the cc's accordingly. 4291da177e4SLinus Torvalds| No write is done, so simply rts. 4301da177e4SLinus Torvalds| 4311da177e4SLinus Torvaldscu_dtst: 4321da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d0 4331da177e4SLinus Torvalds bclrl #15,%d0 4341da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 4351da177e4SLinus Torvalds beqs cu_dtpo 4361da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) |set N 4371da177e4SLinus Torvaldscu_dtpo: 4381da177e4SLinus Torvalds cmpiw #0x7fff,%d0 |test for inf/nan 4391da177e4SLinus Torvalds bnes cu_dtcz 4401da177e4SLinus Torvalds tstl LOCAL_HI(%a0) 4411da177e4SLinus Torvalds bnes cu_dtn 4421da177e4SLinus Torvalds tstl LOCAL_LO(%a0) 4431da177e4SLinus Torvalds bnes cu_dtn 4441da177e4SLinus Torvalds orl #inf_mask,USER_FPSR(%a6) 4451da177e4SLinus Torvalds rts 4461da177e4SLinus Torvaldscu_dtn: 4471da177e4SLinus Torvalds orl #nan_mask,USER_FPSR(%a6) 4481da177e4SLinus Torvalds movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 4491da177e4SLinus Torvalds| ;snan handler 4501da177e4SLinus Torvalds rts 4511da177e4SLinus Torvaldscu_dtcz: 4521da177e4SLinus Torvalds tstl LOCAL_HI(%a0) 4531da177e4SLinus Torvalds bnel cu_dtsx 4541da177e4SLinus Torvalds tstl LOCAL_LO(%a0) 4551da177e4SLinus Torvalds bnel cu_dtsx 4561da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 4571da177e4SLinus Torvaldscu_dtsx: 4581da177e4SLinus Torvalds rts 4591da177e4SLinus Torvalds| 4601da177e4SLinus Torvalds| Inst is fabs. Execute the absolute value function on the input. 4611da177e4SLinus Torvalds| Branch to the fmove code. 4621da177e4SLinus Torvalds| 4631da177e4SLinus Torvaldscu_dabs: 4641da177e4SLinus Torvalds bclrb #7,LOCAL_EX(%a0) |do abs 4651da177e4SLinus Torvalds bras cu_dmove |fmove code will finish 4661da177e4SLinus Torvalds| 4671da177e4SLinus Torvalds| Inst is fneg. Execute the negate value function on the input. 4681da177e4SLinus Torvalds| Fall though to the fmove code. 4691da177e4SLinus Torvalds| 4701da177e4SLinus Torvaldscu_dneg: 4711da177e4SLinus Torvalds bchgb #7,LOCAL_EX(%a0) |do neg 4721da177e4SLinus Torvalds| 4731da177e4SLinus Torvalds| Inst is fmove. This code also handles all result writes. 4741da177e4SLinus Torvalds| If bit 2 is set, round is forced to double. If it is clear, 4751da177e4SLinus Torvalds| and bit 6 is set, round is forced to single. If both are clear, 4761da177e4SLinus Torvalds| the round precision is found in the fpcr. If the rounding precision 4771da177e4SLinus Torvalds| is double or single, the result is zero, and the mode is checked 4781da177e4SLinus Torvalds| to determine if the lsb of the result should be set. 4791da177e4SLinus Torvalds| 4801da177e4SLinus Torvaldscu_dmove: 4811da177e4SLinus Torvalds btstb #2,CMDREG1B+1(%a6) |check for rd 4821da177e4SLinus Torvalds bne cu_dmrd 4831da177e4SLinus Torvalds btstb #6,CMDREG1B+1(%a6) |check for rs 4841da177e4SLinus Torvalds bne cu_dmrs 4851da177e4SLinus Torvalds| 4861da177e4SLinus Torvalds| The move or operation is not with forced precision. Use the 4871da177e4SLinus Torvalds| FPCR_MODE byte to get rounding. 4881da177e4SLinus Torvalds| 4891da177e4SLinus Torvaldscu_dmnr: 4901da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#0:#2},%d0 4911da177e4SLinus Torvalds tstb %d0 |check for extended 4921da177e4SLinus Torvalds beq cu_wrexd |if so, just write result 4931da177e4SLinus Torvalds cmpib #1,%d0 |check for single 4941da177e4SLinus Torvalds beq cu_dmrs |fall through to double 4951da177e4SLinus Torvalds| 4961da177e4SLinus Torvalds| The move is fdmove or round precision is double. Result is zero. 4971da177e4SLinus Torvalds| Check rmode for rp or rm and set lsb accordingly. 4981da177e4SLinus Torvalds| 4991da177e4SLinus Torvaldscu_dmrd: 5001da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 5011da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |check sign 5021da177e4SLinus Torvalds blts cu_dmdn 5031da177e4SLinus Torvalds cmpib #3,%d1 |check for rp 5041da177e4SLinus Torvalds bne cu_dpd |load double pos zero 5051da177e4SLinus Torvalds bra cu_dpdr |load double pos zero w/lsb 5061da177e4SLinus Torvaldscu_dmdn: 5071da177e4SLinus Torvalds cmpib #2,%d1 |check for rm 5081da177e4SLinus Torvalds bne cu_dnd |load double neg zero 5091da177e4SLinus Torvalds bra cu_dndr |load double neg zero w/lsb 5101da177e4SLinus Torvalds| 5111da177e4SLinus Torvalds| The move is fsmove or round precision is single. Result is zero. 5121da177e4SLinus Torvalds| Check for rp or rm and set lsb accordingly. 5131da177e4SLinus Torvalds| 5141da177e4SLinus Torvaldscu_dmrs: 5151da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 5161da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |check sign 5171da177e4SLinus Torvalds blts cu_dmsn 5181da177e4SLinus Torvalds cmpib #3,%d1 |check for rp 5191da177e4SLinus Torvalds bne cu_spd |load single pos zero 5201da177e4SLinus Torvalds bra cu_spdr |load single pos zero w/lsb 5211da177e4SLinus Torvaldscu_dmsn: 5221da177e4SLinus Torvalds cmpib #2,%d1 |check for rm 5231da177e4SLinus Torvalds bne cu_snd |load single neg zero 5241da177e4SLinus Torvalds bra cu_sndr |load single neg zero w/lsb 5251da177e4SLinus Torvalds| 5261da177e4SLinus Torvalds| The precision is extended, so the result in etemp is correct. 5271da177e4SLinus Torvalds| Simply set unfl (not inex2 or aunfl) and write the result to 5281da177e4SLinus Torvalds| the correct fp register. 5291da177e4SLinus Torvaldscu_wrexd: 5301da177e4SLinus Torvalds orl #unfl_mask,USER_FPSR(%a6) 5311da177e4SLinus Torvalds tstw LOCAL_EX(%a0) 5321da177e4SLinus Torvalds beq wr_etemp 5331da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 5341da177e4SLinus Torvalds bra wr_etemp 5351da177e4SLinus Torvalds| 5361da177e4SLinus Torvalds| These routines write +/- zero in double format. The routines 5371da177e4SLinus Torvalds| cu_dpdr and cu_dndr set the double lsb. 5381da177e4SLinus Torvalds| 5391da177e4SLinus Torvaldscu_dpd: 5401da177e4SLinus Torvalds movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero 5411da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5421da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5431da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 5441da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5451da177e4SLinus Torvalds bra wr_etemp 5461da177e4SLinus Torvaldscu_dpdr: 5471da177e4SLinus Torvalds movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero 5481da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5491da177e4SLinus Torvalds movel #0x800,LOCAL_LO(%a0) |with lsb set 5501da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5511da177e4SLinus Torvalds bra wr_etemp 5521da177e4SLinus Torvaldscu_dnd: 5531da177e4SLinus Torvalds movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero 5541da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5551da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5561da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 5571da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 5581da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5591da177e4SLinus Torvalds bra wr_etemp 5601da177e4SLinus Torvaldscu_dndr: 5611da177e4SLinus Torvalds movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero 5621da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5631da177e4SLinus Torvalds movel #0x800,LOCAL_LO(%a0) |with lsb set 5641da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 5651da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5661da177e4SLinus Torvalds bra wr_etemp 5671da177e4SLinus Torvalds| 5681da177e4SLinus Torvalds| These routines write +/- zero in single format. The routines 5691da177e4SLinus Torvalds| cu_dpdr and cu_dndr set the single lsb. 5701da177e4SLinus Torvalds| 5711da177e4SLinus Torvaldscu_spd: 5721da177e4SLinus Torvalds movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero 5731da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5741da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5751da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 5761da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5771da177e4SLinus Torvalds bra wr_etemp 5781da177e4SLinus Torvaldscu_spdr: 5791da177e4SLinus Torvalds movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero 5801da177e4SLinus Torvalds movel #0x100,LOCAL_HI(%a0) |with lsb set 5811da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5821da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5831da177e4SLinus Torvalds bra wr_etemp 5841da177e4SLinus Torvaldscu_snd: 5851da177e4SLinus Torvalds movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero 5861da177e4SLinus Torvalds clrl LOCAL_HI(%a0) 5871da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5881da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) 5891da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 5901da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5911da177e4SLinus Torvalds bra wr_etemp 5921da177e4SLinus Torvaldscu_sndr: 5931da177e4SLinus Torvalds movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero 5941da177e4SLinus Torvalds movel #0x100,LOCAL_HI(%a0) |with lsb set 5951da177e4SLinus Torvalds clrl LOCAL_LO(%a0) 5961da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 5971da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 5981da177e4SLinus Torvalds bra wr_etemp 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds| 6011da177e4SLinus Torvalds| This code checks for 16-bit overflow conditions on dyadic 6021da177e4SLinus Torvalds| operations which are not restorable into the floating-point 6031da177e4SLinus Torvalds| unit and must be completed in software. Basically, this 6041da177e4SLinus Torvalds| condition exists with a very large norm and a denorm. One 6051da177e4SLinus Torvalds| of the operands must be denormalized to enter this code. 6061da177e4SLinus Torvalds| 6071da177e4SLinus Torvalds| Flags used: 6081da177e4SLinus Torvalds| DY_MO_FLG contains 0 for monadic op, $ff for dyadic 6091da177e4SLinus Torvalds| DNRM_FLG contains $00 for neither op denormalized 6101da177e4SLinus Torvalds| $0f for the destination op denormalized 6111da177e4SLinus Torvalds| $f0 for the source op denormalized 6121da177e4SLinus Torvalds| $ff for both ops denormalized 6131da177e4SLinus Torvalds| 6141da177e4SLinus Torvalds| The wrap-around condition occurs for add, sub, div, and cmp 6151da177e4SLinus Torvalds| when 6161da177e4SLinus Torvalds| 6171da177e4SLinus Torvalds| abs(dest_exp - src_exp) >= $8000 6181da177e4SLinus Torvalds| 6191da177e4SLinus Torvalds| and for mul when 6201da177e4SLinus Torvalds| 6211da177e4SLinus Torvalds| (dest_exp + src_exp) < $0 6221da177e4SLinus Torvalds| 6231da177e4SLinus Torvalds| we must process the operation here if this case is true. 6241da177e4SLinus Torvalds| 6251da177e4SLinus Torvalds| The rts following the frcfpn routine is the exit from res_func 6261da177e4SLinus Torvalds| for this condition. The restore flag (RES_FLG) is left clear. 6271da177e4SLinus Torvalds| No frestore is done unless an exception is to be reported. 6281da177e4SLinus Torvalds| 6291da177e4SLinus Torvalds| For fadd: 6301da177e4SLinus Torvalds| if(sign_of(dest) != sign_of(src)) 6311da177e4SLinus Torvalds| replace exponent of src with $3fff (keep sign) 6321da177e4SLinus Torvalds| use fpu to perform dest+new_src (user's rmode and X) 6331da177e4SLinus Torvalds| clr sticky 6341da177e4SLinus Torvalds| else 6351da177e4SLinus Torvalds| set sticky 6361da177e4SLinus Torvalds| call round with user's precision and mode 6371da177e4SLinus Torvalds| move result to fpn and wbtemp 6381da177e4SLinus Torvalds| 6391da177e4SLinus Torvalds| For fsub: 6401da177e4SLinus Torvalds| if(sign_of(dest) == sign_of(src)) 6411da177e4SLinus Torvalds| replace exponent of src with $3fff (keep sign) 6421da177e4SLinus Torvalds| use fpu to perform dest+new_src (user's rmode and X) 6431da177e4SLinus Torvalds| clr sticky 6441da177e4SLinus Torvalds| else 6451da177e4SLinus Torvalds| set sticky 6461da177e4SLinus Torvalds| call round with user's precision and mode 6471da177e4SLinus Torvalds| move result to fpn and wbtemp 6481da177e4SLinus Torvalds| 6491da177e4SLinus Torvalds| For fdiv/fsgldiv: 6501da177e4SLinus Torvalds| if(both operands are denorm) 6511da177e4SLinus Torvalds| restore_to_fpu; 6521da177e4SLinus Torvalds| if(dest is norm) 6531da177e4SLinus Torvalds| force_ovf; 6541da177e4SLinus Torvalds| else(dest is denorm) 6551da177e4SLinus Torvalds| force_unf: 6561da177e4SLinus Torvalds| 6571da177e4SLinus Torvalds| For fcmp: 6581da177e4SLinus Torvalds| if(dest is norm) 6591da177e4SLinus Torvalds| N = sign_of(dest); 6601da177e4SLinus Torvalds| else(dest is denorm) 6611da177e4SLinus Torvalds| N = sign_of(src); 6621da177e4SLinus Torvalds| 6631da177e4SLinus Torvalds| For fmul: 6641da177e4SLinus Torvalds| if(both operands are denorm) 6651da177e4SLinus Torvalds| force_unf; 6661da177e4SLinus Torvalds| if((dest_exp + src_exp) < 0) 6671da177e4SLinus Torvalds| force_unf: 6681da177e4SLinus Torvalds| else 6691da177e4SLinus Torvalds| restore_to_fpu; 6701da177e4SLinus Torvalds| 6711da177e4SLinus Torvalds| local equates: 6721da177e4SLinus Torvalds .set addcode,0x22 6731da177e4SLinus Torvalds .set subcode,0x28 6741da177e4SLinus Torvalds .set mulcode,0x23 6751da177e4SLinus Torvalds .set divcode,0x20 6761da177e4SLinus Torvalds .set cmpcode,0x38 6771da177e4SLinus Torvaldsck_wrap: 6781da177e4SLinus Torvalds | tstb DY_MO_FLG(%a6) ;check for fsqrt 6791da177e4SLinus Torvalds beq fix_stk |if zero, it is fsqrt 6801da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 6811da177e4SLinus Torvalds andiw #0x3b,%d0 |strip to command bits 6821da177e4SLinus Torvalds cmpiw #addcode,%d0 6831da177e4SLinus Torvalds beq wrap_add 6841da177e4SLinus Torvalds cmpiw #subcode,%d0 6851da177e4SLinus Torvalds beq wrap_sub 6861da177e4SLinus Torvalds cmpiw #mulcode,%d0 6871da177e4SLinus Torvalds beq wrap_mul 6881da177e4SLinus Torvalds cmpiw #cmpcode,%d0 6891da177e4SLinus Torvalds beq wrap_cmp 6901da177e4SLinus Torvalds| 6911da177e4SLinus Torvalds| Inst is fdiv. 6921da177e4SLinus Torvalds| 6931da177e4SLinus Torvaldswrap_div: 6941da177e4SLinus Torvalds cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 6951da177e4SLinus Torvalds beq fix_stk |restore to fpu 6961da177e4SLinus Torvalds| 6971da177e4SLinus Torvalds| One of the ops is denormalized. Test for wrap condition 6981da177e4SLinus Torvalds| and force the result. 6991da177e4SLinus Torvalds| 7001da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 7011da177e4SLinus Torvalds bnes div_srcd 7021da177e4SLinus Torvaldsdiv_destd: 7031da177e4SLinus Torvalds bsrl ckinf_ns 7041da177e4SLinus Torvalds bne fix_stk 7051da177e4SLinus Torvalds bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 7061da177e4SLinus Torvalds bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 7071da177e4SLinus Torvalds subl %d1,%d0 |subtract dest from src 7081da177e4SLinus Torvalds cmpl #0x7fff,%d0 7091da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 7101da177e4SLinus Torvalds clrb WBTEMP_SGN(%a6) 7111da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 |find the sign of the result 7121da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d1 7131da177e4SLinus Torvalds eorw %d1,%d0 7141da177e4SLinus Torvalds andiw #0x8000,%d0 7151da177e4SLinus Torvalds beq force_unf 7161da177e4SLinus Torvalds st WBTEMP_SGN(%a6) 7171da177e4SLinus Torvalds bra force_unf 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvaldsckinf_ns: 7201da177e4SLinus Torvalds moveb STAG(%a6),%d0 |check source tag for inf or nan 7211da177e4SLinus Torvalds bra ck_in_com 7221da177e4SLinus Torvaldsckinf_nd: 7231da177e4SLinus Torvalds moveb DTAG(%a6),%d0 |check destination tag for inf or nan 7241da177e4SLinus Torvaldsck_in_com: 7251da177e4SLinus Torvalds andib #0x60,%d0 |isolate tag bits 7261da177e4SLinus Torvalds cmpb #0x40,%d0 |is it inf? 7271da177e4SLinus Torvalds beq nan_or_inf |not wrap case 7281da177e4SLinus Torvalds cmpb #0x60,%d0 |is it nan? 7291da177e4SLinus Torvalds beq nan_or_inf |yes, not wrap case? 7301da177e4SLinus Torvalds cmpb #0x20,%d0 |is it a zero? 7311da177e4SLinus Torvalds beq nan_or_inf |yes 7321da177e4SLinus Torvalds clrl %d0 7331da177e4SLinus Torvalds rts |then ; it is either a zero of norm, 7341da177e4SLinus Torvalds| ;check wrap case 7351da177e4SLinus Torvaldsnan_or_inf: 7361da177e4SLinus Torvalds moveql #-1,%d0 7371da177e4SLinus Torvalds rts 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvaldsdiv_srcd: 7421da177e4SLinus Torvalds bsrl ckinf_nd 7431da177e4SLinus Torvalds bne fix_stk 7441da177e4SLinus Torvalds bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 7451da177e4SLinus Torvalds bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 7461da177e4SLinus Torvalds subl %d1,%d0 |subtract src from dest 7471da177e4SLinus Torvalds cmpl #0x8000,%d0 7481da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 7491da177e4SLinus Torvalds clrb WBTEMP_SGN(%a6) 7501da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 |find the sign of the result 7511da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d1 7521da177e4SLinus Torvalds eorw %d1,%d0 7531da177e4SLinus Torvalds andiw #0x8000,%d0 7541da177e4SLinus Torvalds beqs force_ovf 7551da177e4SLinus Torvalds st WBTEMP_SGN(%a6) 7561da177e4SLinus Torvalds| 7571da177e4SLinus Torvalds| This code handles the case of the instruction resulting in 7581da177e4SLinus Torvalds| an overflow condition. 7591da177e4SLinus Torvalds| 7601da177e4SLinus Torvaldsforce_ovf: 7611da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 7621da177e4SLinus Torvalds orl #ovfl_inx_mask,USER_FPSR(%a6) 7631da177e4SLinus Torvalds clrw NMNEXC(%a6) 7641da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 |point a0 to memory location 7651da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 7661da177e4SLinus Torvalds btstl #6,%d0 |test for forced precision 7671da177e4SLinus Torvalds beqs frcovf_fpcr 7681da177e4SLinus Torvalds btstl #2,%d0 |check for double 7691da177e4SLinus Torvalds bnes frcovf_dbl 7701da177e4SLinus Torvalds movel #0x1,%d0 |inst is forced single 7711da177e4SLinus Torvalds bras frcovf_rnd 7721da177e4SLinus Torvaldsfrcovf_dbl: 7731da177e4SLinus Torvalds movel #0x2,%d0 |inst is forced double 7741da177e4SLinus Torvalds bras frcovf_rnd 7751da177e4SLinus Torvaldsfrcovf_fpcr: 7761da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 7771da177e4SLinus Torvaldsfrcovf_rnd: 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds| The 881/882 does not set inex2 for the following case, so the 7801da177e4SLinus Torvalds| line is commented out to be compatible with 881/882 7811da177e4SLinus Torvalds| tst.b %d0 7821da177e4SLinus Torvalds| beq.b frcovf_x 7831da177e4SLinus Torvalds| or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds|frcovf_x: 7861da177e4SLinus Torvalds bsrl ovf_res |get correct result based on 7871da177e4SLinus Torvalds| ;round precision/mode. This 7881da177e4SLinus Torvalds| ;sets FPSR_CC correctly 7891da177e4SLinus Torvalds| ;returns in external format 7901da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} 7911da177e4SLinus Torvalds beq frcfpn 7921da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 7931da177e4SLinus Torvalds bra frcfpn 7941da177e4SLinus Torvalds| 7951da177e4SLinus Torvalds| Inst is fadd. 7961da177e4SLinus Torvalds| 7971da177e4SLinus Torvaldswrap_add: 7981da177e4SLinus Torvalds cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 7991da177e4SLinus Torvalds beq fix_stk |restore to fpu 8001da177e4SLinus Torvalds| 8011da177e4SLinus Torvalds| One of the ops is denormalized. Test for wrap condition 8021da177e4SLinus Torvalds| and complete the instruction. 8031da177e4SLinus Torvalds| 8041da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 8051da177e4SLinus Torvalds bnes add_srcd 8061da177e4SLinus Torvaldsadd_destd: 8071da177e4SLinus Torvalds bsrl ckinf_ns 8081da177e4SLinus Torvalds bne fix_stk 8091da177e4SLinus Torvalds bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 8101da177e4SLinus Torvalds bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 8111da177e4SLinus Torvalds subl %d1,%d0 |subtract dest from src 8121da177e4SLinus Torvalds cmpl #0x8000,%d0 8131da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 8141da177e4SLinus Torvalds bra add_wrap 8151da177e4SLinus Torvaldsadd_srcd: 8161da177e4SLinus Torvalds bsrl ckinf_nd 8171da177e4SLinus Torvalds bne fix_stk 8181da177e4SLinus Torvalds bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 8191da177e4SLinus Torvalds bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 8201da177e4SLinus Torvalds subl %d1,%d0 |subtract src from dest 8211da177e4SLinus Torvalds cmpl #0x8000,%d0 8221da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 8231da177e4SLinus Torvalds| 8241da177e4SLinus Torvalds| Check the signs of the operands. If they are unlike, the fpu 8251da177e4SLinus Torvalds| can be used to add the norm and 1.0 with the sign of the 8261da177e4SLinus Torvalds| denorm and it will correctly generate the result in extended 8271da177e4SLinus Torvalds| precision. We can then call round with no sticky and the result 8281da177e4SLinus Torvalds| will be correct for the user's rounding mode and precision. If 8291da177e4SLinus Torvalds| the signs are the same, we call round with the sticky bit set 8301da177e4SLinus Torvalds| and the result will be correct for the user's rounding mode and 8311da177e4SLinus Torvalds| precision. 8321da177e4SLinus Torvalds| 8331da177e4SLinus Torvaldsadd_wrap: 8341da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 8351da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d1 8361da177e4SLinus Torvalds eorw %d1,%d0 8371da177e4SLinus Torvalds andiw #0x8000,%d0 8381da177e4SLinus Torvalds beq add_same 8391da177e4SLinus Torvalds| 8401da177e4SLinus Torvalds| The signs are unlike. 8411da177e4SLinus Torvalds| 8421da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 8431da177e4SLinus Torvalds bnes add_u_srcd 8441da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d0 8451da177e4SLinus Torvalds andiw #0x8000,%d0 8461da177e4SLinus Torvalds orw #0x3fff,%d0 |force the exponent to +/- 1 8471da177e4SLinus Torvalds movew %d0,FPTEMP_EX(%a6) |in the denorm 8481da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 8491da177e4SLinus Torvalds andil #0x30,%d0 8501da177e4SLinus Torvalds fmovel %d0,%fpcr |set up users rmode and X 8511da177e4SLinus Torvalds fmovex ETEMP(%a6),%fp0 8521da177e4SLinus Torvalds faddx FPTEMP(%a6),%fp0 8531da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 8541da177e4SLinus Torvalds fmovel %fpsr,%d1 8551da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 8561da177e4SLinus Torvalds fmovex %fp0,WBTEMP(%a6) |write result to memory 8571da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 8581da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 8591da177e4SLinus Torvalds andil #0xc0,%d1 8601da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 8611da177e4SLinus Torvalds swap %d1 8621da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 8631da177e4SLinus Torvalds clrl %d0 |force sticky to zero 8641da177e4SLinus Torvalds bclrb #sign_bit,WBTEMP_EX(%a6) 8651da177e4SLinus Torvalds sne WBTEMP_SGN(%a6) 8661da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 8671da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 8681da177e4SLinus Torvalds beq frcfpnr 8691da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 8701da177e4SLinus Torvalds bra frcfpnr 8711da177e4SLinus Torvaldsadd_u_srcd: 8721da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 8731da177e4SLinus Torvalds andiw #0x8000,%d0 8741da177e4SLinus Torvalds orw #0x3fff,%d0 |force the exponent to +/- 1 8751da177e4SLinus Torvalds movew %d0,ETEMP_EX(%a6) |in the denorm 8761da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 8771da177e4SLinus Torvalds andil #0x30,%d0 8781da177e4SLinus Torvalds fmovel %d0,%fpcr |set up users rmode and X 8791da177e4SLinus Torvalds fmovex ETEMP(%a6),%fp0 8801da177e4SLinus Torvalds faddx FPTEMP(%a6),%fp0 8811da177e4SLinus Torvalds fmovel %fpsr,%d1 8821da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 8831da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 8841da177e4SLinus Torvalds fmovex %fp0,WBTEMP(%a6) |write result to memory 8851da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 8861da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 8871da177e4SLinus Torvalds andil #0xc0,%d1 8881da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 8891da177e4SLinus Torvalds swap %d1 8901da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 8911da177e4SLinus Torvalds clrl %d0 |force sticky to zero 8921da177e4SLinus Torvalds bclrb #sign_bit,WBTEMP_EX(%a6) 8931da177e4SLinus Torvalds sne WBTEMP_SGN(%a6) |use internal format for round 8941da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 8951da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 8961da177e4SLinus Torvalds beq frcfpnr 8971da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 8981da177e4SLinus Torvalds bra frcfpnr 8991da177e4SLinus Torvalds| 9001da177e4SLinus Torvalds| Signs are alike: 9011da177e4SLinus Torvalds| 9021da177e4SLinus Torvaldsadd_same: 9031da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 9041da177e4SLinus Torvalds bnes add_s_srcd 9051da177e4SLinus Torvaldsadd_s_destd: 9061da177e4SLinus Torvalds leal ETEMP(%a6),%a0 9071da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 9081da177e4SLinus Torvalds andil #0x30,%d0 9091da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 9101da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 9111da177e4SLinus Torvalds andil #0xc0,%d1 9121da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 9131da177e4SLinus Torvalds swap %d1 9141da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 9151da177e4SLinus Torvalds movel #0x20000000,%d0 |set sticky for round 9161da177e4SLinus Torvalds bclrb #sign_bit,ETEMP_EX(%a6) 9171da177e4SLinus Torvalds sne ETEMP_SGN(%a6) 9181da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 9191da177e4SLinus Torvalds bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 9201da177e4SLinus Torvalds beqs add_s_dclr 9211da177e4SLinus Torvalds bsetb #sign_bit,ETEMP_EX(%a6) 9221da177e4SLinus Torvaldsadd_s_dclr: 9231da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 9241da177e4SLinus Torvalds movel ETEMP(%a6),(%a0) |write result to wbtemp 9251da177e4SLinus Torvalds movel ETEMP_HI(%a6),4(%a0) 9261da177e4SLinus Torvalds movel ETEMP_LO(%a6),8(%a0) 9271da177e4SLinus Torvalds tstw ETEMP_EX(%a6) 9281da177e4SLinus Torvalds bgt add_ckovf 9291da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 9301da177e4SLinus Torvalds bra add_ckovf 9311da177e4SLinus Torvaldsadd_s_srcd: 9321da177e4SLinus Torvalds leal FPTEMP(%a6),%a0 9331da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 9341da177e4SLinus Torvalds andil #0x30,%d0 9351da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 9361da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 9371da177e4SLinus Torvalds andil #0xc0,%d1 9381da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 9391da177e4SLinus Torvalds swap %d1 9401da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 9411da177e4SLinus Torvalds movel #0x20000000,%d0 |set sticky for round 9421da177e4SLinus Torvalds bclrb #sign_bit,FPTEMP_EX(%a6) 9431da177e4SLinus Torvalds sne FPTEMP_SGN(%a6) 9441da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 9451da177e4SLinus Torvalds bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 9461da177e4SLinus Torvalds beqs add_s_sclr 9471da177e4SLinus Torvalds bsetb #sign_bit,FPTEMP_EX(%a6) 9481da177e4SLinus Torvaldsadd_s_sclr: 9491da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 9501da177e4SLinus Torvalds movel FPTEMP(%a6),(%a0) |write result to wbtemp 9511da177e4SLinus Torvalds movel FPTEMP_HI(%a6),4(%a0) 9521da177e4SLinus Torvalds movel FPTEMP_LO(%a6),8(%a0) 9531da177e4SLinus Torvalds tstw FPTEMP_EX(%a6) 9541da177e4SLinus Torvalds bgt add_ckovf 9551da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 9561da177e4SLinus Torvaldsadd_ckovf: 9571da177e4SLinus Torvalds movew WBTEMP_EX(%a6),%d0 9581da177e4SLinus Torvalds andiw #0x7fff,%d0 9591da177e4SLinus Torvalds cmpiw #0x7fff,%d0 9601da177e4SLinus Torvalds bne frcfpnr 9611da177e4SLinus Torvalds| 9621da177e4SLinus Torvalds| The result has overflowed to $7fff exponent. Set I, ovfl, 9631da177e4SLinus Torvalds| and aovfl, and clr the mantissa (incorrectly set by the 9641da177e4SLinus Torvalds| round routine.) 9651da177e4SLinus Torvalds| 9661da177e4SLinus Torvalds orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) 9671da177e4SLinus Torvalds clrl 4(%a0) 9681da177e4SLinus Torvalds bra frcfpnr 9691da177e4SLinus Torvalds| 9701da177e4SLinus Torvalds| Inst is fsub. 9711da177e4SLinus Torvalds| 9721da177e4SLinus Torvaldswrap_sub: 9731da177e4SLinus Torvalds cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 9741da177e4SLinus Torvalds beq fix_stk |restore to fpu 9751da177e4SLinus Torvalds| 9761da177e4SLinus Torvalds| One of the ops is denormalized. Test for wrap condition 9771da177e4SLinus Torvalds| and complete the instruction. 9781da177e4SLinus Torvalds| 9791da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 9801da177e4SLinus Torvalds bnes sub_srcd 9811da177e4SLinus Torvaldssub_destd: 9821da177e4SLinus Torvalds bsrl ckinf_ns 9831da177e4SLinus Torvalds bne fix_stk 9841da177e4SLinus Torvalds bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 9851da177e4SLinus Torvalds bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 9861da177e4SLinus Torvalds subl %d1,%d0 |subtract src from dest 9871da177e4SLinus Torvalds cmpl #0x8000,%d0 9881da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 9891da177e4SLinus Torvalds bra sub_wrap 9901da177e4SLinus Torvaldssub_srcd: 9911da177e4SLinus Torvalds bsrl ckinf_nd 9921da177e4SLinus Torvalds bne fix_stk 9931da177e4SLinus Torvalds bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 9941da177e4SLinus Torvalds bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 9951da177e4SLinus Torvalds subl %d1,%d0 |subtract dest from src 9961da177e4SLinus Torvalds cmpl #0x8000,%d0 9971da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 9981da177e4SLinus Torvalds| 9991da177e4SLinus Torvalds| Check the signs of the operands. If they are alike, the fpu 10001da177e4SLinus Torvalds| can be used to subtract from the norm 1.0 with the sign of the 10011da177e4SLinus Torvalds| denorm and it will correctly generate the result in extended 10021da177e4SLinus Torvalds| precision. We can then call round with no sticky and the result 10031da177e4SLinus Torvalds| will be correct for the user's rounding mode and precision. If 10041da177e4SLinus Torvalds| the signs are unlike, we call round with the sticky bit set 10051da177e4SLinus Torvalds| and the result will be correct for the user's rounding mode and 10061da177e4SLinus Torvalds| precision. 10071da177e4SLinus Torvalds| 10081da177e4SLinus Torvaldssub_wrap: 10091da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 10101da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d1 10111da177e4SLinus Torvalds eorw %d1,%d0 10121da177e4SLinus Torvalds andiw #0x8000,%d0 10131da177e4SLinus Torvalds bne sub_diff 10141da177e4SLinus Torvalds| 10151da177e4SLinus Torvalds| The signs are alike. 10161da177e4SLinus Torvalds| 10171da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 10181da177e4SLinus Torvalds bnes sub_u_srcd 10191da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d0 10201da177e4SLinus Torvalds andiw #0x8000,%d0 10211da177e4SLinus Torvalds orw #0x3fff,%d0 |force the exponent to +/- 1 10221da177e4SLinus Torvalds movew %d0,FPTEMP_EX(%a6) |in the denorm 10231da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 10241da177e4SLinus Torvalds andil #0x30,%d0 10251da177e4SLinus Torvalds fmovel %d0,%fpcr |set up users rmode and X 10261da177e4SLinus Torvalds fmovex FPTEMP(%a6),%fp0 10271da177e4SLinus Torvalds fsubx ETEMP(%a6),%fp0 10281da177e4SLinus Torvalds fmovel %fpsr,%d1 10291da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 10301da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 10311da177e4SLinus Torvalds fmovex %fp0,WBTEMP(%a6) |write result to memory 10321da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 10331da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 10341da177e4SLinus Torvalds andil #0xc0,%d1 10351da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 10361da177e4SLinus Torvalds swap %d1 10371da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 10381da177e4SLinus Torvalds clrl %d0 |force sticky to zero 10391da177e4SLinus Torvalds bclrb #sign_bit,WBTEMP_EX(%a6) 10401da177e4SLinus Torvalds sne WBTEMP_SGN(%a6) 10411da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 10421da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 10431da177e4SLinus Torvalds beq frcfpnr 10441da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 10451da177e4SLinus Torvalds bra frcfpnr 10461da177e4SLinus Torvaldssub_u_srcd: 10471da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 10481da177e4SLinus Torvalds andiw #0x8000,%d0 10491da177e4SLinus Torvalds orw #0x3fff,%d0 |force the exponent to +/- 1 10501da177e4SLinus Torvalds movew %d0,ETEMP_EX(%a6) |in the denorm 10511da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 10521da177e4SLinus Torvalds andil #0x30,%d0 10531da177e4SLinus Torvalds fmovel %d0,%fpcr |set up users rmode and X 10541da177e4SLinus Torvalds fmovex FPTEMP(%a6),%fp0 10551da177e4SLinus Torvalds fsubx ETEMP(%a6),%fp0 10561da177e4SLinus Torvalds fmovel %fpsr,%d1 10571da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 10581da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 10591da177e4SLinus Torvalds fmovex %fp0,WBTEMP(%a6) |write result to memory 10601da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 10611da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 10621da177e4SLinus Torvalds andil #0xc0,%d1 10631da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 10641da177e4SLinus Torvalds swap %d1 10651da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 10661da177e4SLinus Torvalds clrl %d0 |force sticky to zero 10671da177e4SLinus Torvalds bclrb #sign_bit,WBTEMP_EX(%a6) 10681da177e4SLinus Torvalds sne WBTEMP_SGN(%a6) 10691da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 10701da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 10711da177e4SLinus Torvalds beq frcfpnr 10721da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 10731da177e4SLinus Torvalds bra frcfpnr 10741da177e4SLinus Torvalds| 10751da177e4SLinus Torvalds| Signs are unlike: 10761da177e4SLinus Torvalds| 10771da177e4SLinus Torvaldssub_diff: 10781da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 10791da177e4SLinus Torvalds bnes sub_s_srcd 10801da177e4SLinus Torvaldssub_s_destd: 10811da177e4SLinus Torvalds leal ETEMP(%a6),%a0 10821da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 10831da177e4SLinus Torvalds andil #0x30,%d0 10841da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 10851da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 10861da177e4SLinus Torvalds andil #0xc0,%d1 10871da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 10881da177e4SLinus Torvalds swap %d1 10891da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 10901da177e4SLinus Torvalds movel #0x20000000,%d0 |set sticky for round 10911da177e4SLinus Torvalds| 10921da177e4SLinus Torvalds| Since the dest is the denorm, the sign is the opposite of the 10931da177e4SLinus Torvalds| norm sign. 10941da177e4SLinus Torvalds| 10951da177e4SLinus Torvalds eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result 10961da177e4SLinus Torvalds tstw ETEMP_EX(%a6) 10971da177e4SLinus Torvalds bgts sub_s_dwr 10981da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 10991da177e4SLinus Torvaldssub_s_dwr: 11001da177e4SLinus Torvalds bclrb #sign_bit,ETEMP_EX(%a6) 11011da177e4SLinus Torvalds sne ETEMP_SGN(%a6) 11021da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 11031da177e4SLinus Torvalds bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 11041da177e4SLinus Torvalds beqs sub_s_dclr 11051da177e4SLinus Torvalds bsetb #sign_bit,ETEMP_EX(%a6) 11061da177e4SLinus Torvaldssub_s_dclr: 11071da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 11081da177e4SLinus Torvalds movel ETEMP(%a6),(%a0) |write result to wbtemp 11091da177e4SLinus Torvalds movel ETEMP_HI(%a6),4(%a0) 11101da177e4SLinus Torvalds movel ETEMP_LO(%a6),8(%a0) 11111da177e4SLinus Torvalds bra sub_ckovf 11121da177e4SLinus Torvaldssub_s_srcd: 11131da177e4SLinus Torvalds leal FPTEMP(%a6),%a0 11141da177e4SLinus Torvalds movel USER_FPCR(%a6),%d0 11151da177e4SLinus Torvalds andil #0x30,%d0 11161da177e4SLinus Torvalds lsrl #4,%d0 |put rmode in lower 2 bits 11171da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 11181da177e4SLinus Torvalds andil #0xc0,%d1 11191da177e4SLinus Torvalds lsrl #6,%d1 |put precision in upper word 11201da177e4SLinus Torvalds swap %d1 11211da177e4SLinus Torvalds orl %d0,%d1 |set up for round call 11221da177e4SLinus Torvalds movel #0x20000000,%d0 |set sticky for round 11231da177e4SLinus Torvalds bclrb #sign_bit,FPTEMP_EX(%a6) 11241da177e4SLinus Torvalds sne FPTEMP_SGN(%a6) 11251da177e4SLinus Torvalds bsrl round |round result to users rmode & prec 11261da177e4SLinus Torvalds bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 11271da177e4SLinus Torvalds beqs sub_s_sclr 11281da177e4SLinus Torvalds bsetb #sign_bit,FPTEMP_EX(%a6) 11291da177e4SLinus Torvaldssub_s_sclr: 11301da177e4SLinus Torvalds leal WBTEMP(%a6),%a0 11311da177e4SLinus Torvalds movel FPTEMP(%a6),(%a0) |write result to wbtemp 11321da177e4SLinus Torvalds movel FPTEMP_HI(%a6),4(%a0) 11331da177e4SLinus Torvalds movel FPTEMP_LO(%a6),8(%a0) 11341da177e4SLinus Torvalds tstw FPTEMP_EX(%a6) 11351da177e4SLinus Torvalds bgt sub_ckovf 11361da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 11371da177e4SLinus Torvaldssub_ckovf: 11381da177e4SLinus Torvalds movew WBTEMP_EX(%a6),%d0 11391da177e4SLinus Torvalds andiw #0x7fff,%d0 11401da177e4SLinus Torvalds cmpiw #0x7fff,%d0 11411da177e4SLinus Torvalds bne frcfpnr 11421da177e4SLinus Torvalds| 11431da177e4SLinus Torvalds| The result has overflowed to $7fff exponent. Set I, ovfl, 11441da177e4SLinus Torvalds| and aovfl, and clr the mantissa (incorrectly set by the 11451da177e4SLinus Torvalds| round routine.) 11461da177e4SLinus Torvalds| 11471da177e4SLinus Torvalds orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) 11481da177e4SLinus Torvalds clrl 4(%a0) 11491da177e4SLinus Torvalds bra frcfpnr 11501da177e4SLinus Torvalds| 11511da177e4SLinus Torvalds| Inst is fcmp. 11521da177e4SLinus Torvalds| 11531da177e4SLinus Torvaldswrap_cmp: 11541da177e4SLinus Torvalds cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 11551da177e4SLinus Torvalds beq fix_stk |restore to fpu 11561da177e4SLinus Torvalds| 11571da177e4SLinus Torvalds| One of the ops is denormalized. Test for wrap condition 11581da177e4SLinus Torvalds| and complete the instruction. 11591da177e4SLinus Torvalds| 11601da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 11611da177e4SLinus Torvalds bnes cmp_srcd 11621da177e4SLinus Torvaldscmp_destd: 11631da177e4SLinus Torvalds bsrl ckinf_ns 11641da177e4SLinus Torvalds bne fix_stk 11651da177e4SLinus Torvalds bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 11661da177e4SLinus Torvalds bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 11671da177e4SLinus Torvalds subl %d1,%d0 |subtract dest from src 11681da177e4SLinus Torvalds cmpl #0x8000,%d0 11691da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 11701da177e4SLinus Torvalds tstw ETEMP_EX(%a6) |set N to ~sign_of(src) 11711da177e4SLinus Torvalds bge cmp_setn 11721da177e4SLinus Torvalds rts 11731da177e4SLinus Torvaldscmp_srcd: 11741da177e4SLinus Torvalds bsrl ckinf_nd 11751da177e4SLinus Torvalds bne fix_stk 11761da177e4SLinus Torvalds bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 11771da177e4SLinus Torvalds bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 11781da177e4SLinus Torvalds subl %d1,%d0 |subtract src from dest 11791da177e4SLinus Torvalds cmpl #0x8000,%d0 11801da177e4SLinus Torvalds blt fix_stk |if less, not wrap case 11811da177e4SLinus Torvalds tstw FPTEMP_EX(%a6) |set N to sign_of(dest) 11821da177e4SLinus Torvalds blt cmp_setn 11831da177e4SLinus Torvalds rts 11841da177e4SLinus Torvaldscmp_setn: 11851da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 11861da177e4SLinus Torvalds rts 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds| 11891da177e4SLinus Torvalds| Inst is fmul. 11901da177e4SLinus Torvalds| 11911da177e4SLinus Torvaldswrap_mul: 11921da177e4SLinus Torvalds cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 11931da177e4SLinus Torvalds beq force_unf |force an underflow (really!) 11941da177e4SLinus Torvalds| 11951da177e4SLinus Torvalds| One of the ops is denormalized. Test for wrap condition 11961da177e4SLinus Torvalds| and complete the instruction. 11971da177e4SLinus Torvalds| 11981da177e4SLinus Torvalds cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 11991da177e4SLinus Torvalds bnes mul_srcd 12001da177e4SLinus Torvaldsmul_destd: 12011da177e4SLinus Torvalds bsrl ckinf_ns 12021da177e4SLinus Torvalds bne fix_stk 12031da177e4SLinus Torvalds bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 12041da177e4SLinus Torvalds bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 12051da177e4SLinus Torvalds addl %d1,%d0 |subtract dest from src 12061da177e4SLinus Torvalds bgt fix_stk 12071da177e4SLinus Torvalds bra force_unf 12081da177e4SLinus Torvaldsmul_srcd: 12091da177e4SLinus Torvalds bsrl ckinf_nd 12101da177e4SLinus Torvalds bne fix_stk 12111da177e4SLinus Torvalds bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 12121da177e4SLinus Torvalds bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 12131da177e4SLinus Torvalds addl %d1,%d0 |subtract src from dest 12141da177e4SLinus Torvalds bgt fix_stk 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds| 12171da177e4SLinus Torvalds| This code handles the case of the instruction resulting in 12181da177e4SLinus Torvalds| an underflow condition. 12191da177e4SLinus Torvalds| 12201da177e4SLinus Torvaldsforce_unf: 12211da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 12221da177e4SLinus Torvalds orl #unfinx_mask,USER_FPSR(%a6) 12231da177e4SLinus Torvalds clrw NMNEXC(%a6) 12241da177e4SLinus Torvalds clrb WBTEMP_SGN(%a6) 12251da177e4SLinus Torvalds movew ETEMP_EX(%a6),%d0 |find the sign of the result 12261da177e4SLinus Torvalds movew FPTEMP_EX(%a6),%d1 12271da177e4SLinus Torvalds eorw %d1,%d0 12281da177e4SLinus Torvalds andiw #0x8000,%d0 12291da177e4SLinus Torvalds beqs frcunfcont 12301da177e4SLinus Torvalds st WBTEMP_SGN(%a6) 12311da177e4SLinus Torvaldsfrcunfcont: 12321da177e4SLinus Torvalds lea WBTEMP(%a6),%a0 |point a0 to memory location 12331da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 12341da177e4SLinus Torvalds btstl #6,%d0 |test for forced precision 12351da177e4SLinus Torvalds beqs frcunf_fpcr 12361da177e4SLinus Torvalds btstl #2,%d0 |check for double 12371da177e4SLinus Torvalds bnes frcunf_dbl 12381da177e4SLinus Torvalds movel #0x1,%d0 |inst is forced single 12391da177e4SLinus Torvalds bras frcunf_rnd 12401da177e4SLinus Torvaldsfrcunf_dbl: 12411da177e4SLinus Torvalds movel #0x2,%d0 |inst is forced double 12421da177e4SLinus Torvalds bras frcunf_rnd 12431da177e4SLinus Torvaldsfrcunf_fpcr: 12441da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 12451da177e4SLinus Torvaldsfrcunf_rnd: 12461da177e4SLinus Torvalds bsrl unf_sub |get correct result based on 12471da177e4SLinus Torvalds| ;round precision/mode. This 12481da177e4SLinus Torvalds| ;sets FPSR_CC correctly 12491da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 12501da177e4SLinus Torvalds beqs frcfpn 12511da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 12521da177e4SLinus Torvalds bra frcfpn 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds| 12551da177e4SLinus Torvalds| Write the result to the user's fpn. All results must be HUGE to be 12561da177e4SLinus Torvalds| written; otherwise the results would have overflowed or underflowed. 12571da177e4SLinus Torvalds| If the rounding precision is single or double, the ovf_res routine 12581da177e4SLinus Torvalds| is needed to correctly supply the max value. 12591da177e4SLinus Torvalds| 12601da177e4SLinus Torvaldsfrcfpnr: 12611da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 12621da177e4SLinus Torvalds btstl #6,%d0 |test for forced precision 12631da177e4SLinus Torvalds beqs frcfpn_fpcr 12641da177e4SLinus Torvalds btstl #2,%d0 |check for double 12651da177e4SLinus Torvalds bnes frcfpn_dbl 12661da177e4SLinus Torvalds movel #0x1,%d0 |inst is forced single 12671da177e4SLinus Torvalds bras frcfpn_rnd 12681da177e4SLinus Torvaldsfrcfpn_dbl: 12691da177e4SLinus Torvalds movel #0x2,%d0 |inst is forced double 12701da177e4SLinus Torvalds bras frcfpn_rnd 12711da177e4SLinus Torvaldsfrcfpn_fpcr: 12721da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 12731da177e4SLinus Torvalds tstb %d0 12741da177e4SLinus Torvalds beqs frcfpn |if extended, write what you got 12751da177e4SLinus Torvaldsfrcfpn_rnd: 12761da177e4SLinus Torvalds bclrb #sign_bit,WBTEMP_EX(%a6) 12771da177e4SLinus Torvalds sne WBTEMP_SGN(%a6) 12781da177e4SLinus Torvalds bsrl ovf_res |get correct result based on 12791da177e4SLinus Torvalds| ;round precision/mode. This 12801da177e4SLinus Torvalds| ;sets FPSR_CC correctly 12811da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 12821da177e4SLinus Torvalds beqs frcfpn_clr 12831da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 12841da177e4SLinus Torvaldsfrcfpn_clr: 12851da177e4SLinus Torvalds orl #ovfinx_mask,USER_FPSR(%a6) 12861da177e4SLinus Torvalds| 12871da177e4SLinus Torvalds| Perform the write. 12881da177e4SLinus Torvalds| 12891da177e4SLinus Torvaldsfrcfpn: 12901da177e4SLinus Torvalds bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register 12911da177e4SLinus Torvalds cmpib #3,%d0 12921da177e4SLinus Torvalds bles frc0123 |check if dest is fp0-fp3 12931da177e4SLinus Torvalds movel #7,%d1 12941da177e4SLinus Torvalds subl %d0,%d1 12951da177e4SLinus Torvalds clrl %d0 12961da177e4SLinus Torvalds bsetl %d1,%d0 12971da177e4SLinus Torvalds fmovemx WBTEMP(%a6),%d0 12981da177e4SLinus Torvalds rts 12991da177e4SLinus Torvaldsfrc0123: 13001da177e4SLinus Torvalds cmpib #0,%d0 13011da177e4SLinus Torvalds beqs frc0_dst 13021da177e4SLinus Torvalds cmpib #1,%d0 13031da177e4SLinus Torvalds beqs frc1_dst 13041da177e4SLinus Torvalds cmpib #2,%d0 13051da177e4SLinus Torvalds beqs frc2_dst 13061da177e4SLinus Torvaldsfrc3_dst: 13071da177e4SLinus Torvalds movel WBTEMP_EX(%a6),USER_FP3(%a6) 13081da177e4SLinus Torvalds movel WBTEMP_HI(%a6),USER_FP3+4(%a6) 13091da177e4SLinus Torvalds movel WBTEMP_LO(%a6),USER_FP3+8(%a6) 13101da177e4SLinus Torvalds rts 13111da177e4SLinus Torvaldsfrc2_dst: 13121da177e4SLinus Torvalds movel WBTEMP_EX(%a6),USER_FP2(%a6) 13131da177e4SLinus Torvalds movel WBTEMP_HI(%a6),USER_FP2+4(%a6) 13141da177e4SLinus Torvalds movel WBTEMP_LO(%a6),USER_FP2+8(%a6) 13151da177e4SLinus Torvalds rts 13161da177e4SLinus Torvaldsfrc1_dst: 13171da177e4SLinus Torvalds movel WBTEMP_EX(%a6),USER_FP1(%a6) 13181da177e4SLinus Torvalds movel WBTEMP_HI(%a6),USER_FP1+4(%a6) 13191da177e4SLinus Torvalds movel WBTEMP_LO(%a6),USER_FP1+8(%a6) 13201da177e4SLinus Torvalds rts 13211da177e4SLinus Torvaldsfrc0_dst: 13221da177e4SLinus Torvalds movel WBTEMP_EX(%a6),USER_FP0(%a6) 13231da177e4SLinus Torvalds movel WBTEMP_HI(%a6),USER_FP0+4(%a6) 13241da177e4SLinus Torvalds movel WBTEMP_LO(%a6),USER_FP0+8(%a6) 13251da177e4SLinus Torvalds rts 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds| 13281da177e4SLinus Torvalds| Write etemp to fpn. 13291da177e4SLinus Torvalds| A check is made on enabled and signalled snan exceptions, 13301da177e4SLinus Torvalds| and the destination is not overwritten if this condition exists. 13311da177e4SLinus Torvalds| This code is designed to make fmoveins of unsupported data types 13321da177e4SLinus Torvalds| faster. 13331da177e4SLinus Torvalds| 13341da177e4SLinus Torvaldswr_etemp: 13351da177e4SLinus Torvalds btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and 13361da177e4SLinus Torvalds beqs fmoveinc |enabled, force restore 13371da177e4SLinus Torvalds btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite 13381da177e4SLinus Torvalds beqs fmoveinc |the dest 13391da177e4SLinus Torvalds movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 13401da177e4SLinus Torvalds| ;snan handler 13411da177e4SLinus Torvalds tstb ETEMP(%a6) |check for negative 13421da177e4SLinus Torvalds blts snan_neg 13431da177e4SLinus Torvalds rts 13441da177e4SLinus Torvaldssnan_neg: 13451da177e4SLinus Torvalds orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N 13461da177e4SLinus Torvalds rts 13471da177e4SLinus Torvaldsfmoveinc: 13481da177e4SLinus Torvalds clrw NMNEXC(%a6) 13491da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 13501da177e4SLinus Torvalds moveb STAG(%a6),%d0 |check if stag is inf 13511da177e4SLinus Torvalds andib #0xe0,%d0 13521da177e4SLinus Torvalds cmpib #0x40,%d0 13531da177e4SLinus Torvalds bnes fminc_cnan 13541da177e4SLinus Torvalds orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I 13551da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |check sign 13561da177e4SLinus Torvalds bges fminc_con 13571da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 13581da177e4SLinus Torvalds bra fminc_con 13591da177e4SLinus Torvaldsfminc_cnan: 13601da177e4SLinus Torvalds cmpib #0x60,%d0 |check if stag is NaN 13611da177e4SLinus Torvalds bnes fminc_czero 13621da177e4SLinus Torvalds orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN 13631da177e4SLinus Torvalds movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 13641da177e4SLinus Torvalds| ;snan handler 13651da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |check sign 13661da177e4SLinus Torvalds bges fminc_con 13671da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 13681da177e4SLinus Torvalds bra fminc_con 13691da177e4SLinus Torvaldsfminc_czero: 13701da177e4SLinus Torvalds cmpib #0x20,%d0 |check if zero 13711da177e4SLinus Torvalds bnes fminc_con 13721da177e4SLinus Torvalds orl #z_mask,USER_FPSR(%a6) |if zero, set Z 13731da177e4SLinus Torvalds tstw LOCAL_EX(%a0) |check sign 13741da177e4SLinus Torvalds bges fminc_con 13751da177e4SLinus Torvalds orl #neg_mask,USER_FPSR(%a6) 13761da177e4SLinus Torvaldsfminc_con: 13771da177e4SLinus Torvalds bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register 13781da177e4SLinus Torvalds cmpib #3,%d0 13791da177e4SLinus Torvalds bles fp0123 |check if dest is fp0-fp3 13801da177e4SLinus Torvalds movel #7,%d1 13811da177e4SLinus Torvalds subl %d0,%d1 13821da177e4SLinus Torvalds clrl %d0 13831da177e4SLinus Torvalds bsetl %d1,%d0 13841da177e4SLinus Torvalds fmovemx ETEMP(%a6),%d0 13851da177e4SLinus Torvalds rts 13861da177e4SLinus Torvalds 13871da177e4SLinus Torvaldsfp0123: 13881da177e4SLinus Torvalds cmpib #0,%d0 13891da177e4SLinus Torvalds beqs fp0_dst 13901da177e4SLinus Torvalds cmpib #1,%d0 13911da177e4SLinus Torvalds beqs fp1_dst 13921da177e4SLinus Torvalds cmpib #2,%d0 13931da177e4SLinus Torvalds beqs fp2_dst 13941da177e4SLinus Torvaldsfp3_dst: 13951da177e4SLinus Torvalds movel ETEMP_EX(%a6),USER_FP3(%a6) 13961da177e4SLinus Torvalds movel ETEMP_HI(%a6),USER_FP3+4(%a6) 13971da177e4SLinus Torvalds movel ETEMP_LO(%a6),USER_FP3+8(%a6) 13981da177e4SLinus Torvalds rts 13991da177e4SLinus Torvaldsfp2_dst: 14001da177e4SLinus Torvalds movel ETEMP_EX(%a6),USER_FP2(%a6) 14011da177e4SLinus Torvalds movel ETEMP_HI(%a6),USER_FP2+4(%a6) 14021da177e4SLinus Torvalds movel ETEMP_LO(%a6),USER_FP2+8(%a6) 14031da177e4SLinus Torvalds rts 14041da177e4SLinus Torvaldsfp1_dst: 14051da177e4SLinus Torvalds movel ETEMP_EX(%a6),USER_FP1(%a6) 14061da177e4SLinus Torvalds movel ETEMP_HI(%a6),USER_FP1+4(%a6) 14071da177e4SLinus Torvalds movel ETEMP_LO(%a6),USER_FP1+8(%a6) 14081da177e4SLinus Torvalds rts 14091da177e4SLinus Torvaldsfp0_dst: 14101da177e4SLinus Torvalds movel ETEMP_EX(%a6),USER_FP0(%a6) 14111da177e4SLinus Torvalds movel ETEMP_HI(%a6),USER_FP0+4(%a6) 14121da177e4SLinus Torvalds movel ETEMP_LO(%a6),USER_FP0+8(%a6) 14131da177e4SLinus Torvalds rts 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvaldsopclass3: 14161da177e4SLinus Torvalds st CU_ONLY(%a6) 14171da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 |check if packed moveout 14181da177e4SLinus Torvalds andiw #0x0c00,%d0 |isolate last 2 bits of size field 14191da177e4SLinus Torvalds cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed 14201da177e4SLinus Torvalds beq pack_out |else it is norm or denorm 14211da177e4SLinus Torvalds bra mv_out 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds 14241da177e4SLinus Torvalds| 14251da177e4SLinus Torvalds| MOVE OUT 14261da177e4SLinus Torvalds| 14271da177e4SLinus Torvalds 14281da177e4SLinus Torvaldsmv_tbl: 14291da177e4SLinus Torvalds .long li 14301da177e4SLinus Torvalds .long sgp 14311da177e4SLinus Torvalds .long xp 14321da177e4SLinus Torvalds .long mvout_end |should never be taken 14331da177e4SLinus Torvalds .long wi 14341da177e4SLinus Torvalds .long dp 14351da177e4SLinus Torvalds .long bi 14361da177e4SLinus Torvalds .long mvout_end |should never be taken 14371da177e4SLinus Torvaldsmv_out: 14381da177e4SLinus Torvalds bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1 14391da177e4SLinus Torvalds leal mv_tbl,%a0 14401da177e4SLinus Torvalds movel %a0@(%d1:l:4),%a0 14411da177e4SLinus Torvalds jmp (%a0) 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds| 14441da177e4SLinus Torvalds| This exit is for move-out to memory. The aunfl bit is 14451da177e4SLinus Torvalds| set if the result is inex and unfl is signalled. 14461da177e4SLinus Torvalds| 14471da177e4SLinus Torvaldsmvout_end: 14481da177e4SLinus Torvalds btstb #inex2_bit,FPSR_EXCEPT(%a6) 14491da177e4SLinus Torvalds beqs no_aufl 14501da177e4SLinus Torvalds btstb #unfl_bit,FPSR_EXCEPT(%a6) 14511da177e4SLinus Torvalds beqs no_aufl 14521da177e4SLinus Torvalds bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) 14531da177e4SLinus Torvaldsno_aufl: 14541da177e4SLinus Torvalds clrw NMNEXC(%a6) 14551da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 14561da177e4SLinus Torvalds fmovel #0,%FPSR |clear any cc bits from res_func 14571da177e4SLinus Torvalds| 14581da177e4SLinus Torvalds| Return ETEMP to extended format from internal extended format so 14591da177e4SLinus Torvalds| that gen_except will have a correctly signed value for ovfl/unfl 14601da177e4SLinus Torvalds| handlers. 14611da177e4SLinus Torvalds| 14621da177e4SLinus Torvalds bfclr ETEMP_SGN(%a6){#0:#8} 14631da177e4SLinus Torvalds beqs mvout_con 14641da177e4SLinus Torvalds bsetb #sign_bit,ETEMP_EX(%a6) 14651da177e4SLinus Torvaldsmvout_con: 14661da177e4SLinus Torvalds rts 14671da177e4SLinus Torvalds| 14681da177e4SLinus Torvalds| This exit is for move-out to int register. The aunfl bit is 14691da177e4SLinus Torvalds| not set in any case for this move. 14701da177e4SLinus Torvalds| 14711da177e4SLinus Torvaldsmvouti_end: 14721da177e4SLinus Torvalds clrw NMNEXC(%a6) 14731da177e4SLinus Torvalds bclrb #E1,E_BYTE(%a6) 14741da177e4SLinus Torvalds fmovel #0,%FPSR |clear any cc bits from res_func 14751da177e4SLinus Torvalds| 14761da177e4SLinus Torvalds| Return ETEMP to extended format from internal extended format so 14771da177e4SLinus Torvalds| that gen_except will have a correctly signed value for ovfl/unfl 14781da177e4SLinus Torvalds| handlers. 14791da177e4SLinus Torvalds| 14801da177e4SLinus Torvalds bfclr ETEMP_SGN(%a6){#0:#8} 14811da177e4SLinus Torvalds beqs mvouti_con 14821da177e4SLinus Torvalds bsetb #sign_bit,ETEMP_EX(%a6) 14831da177e4SLinus Torvaldsmvouti_con: 14841da177e4SLinus Torvalds rts 14851da177e4SLinus Torvalds| 14861da177e4SLinus Torvalds| li is used to handle a long integer source specifier 14871da177e4SLinus Torvalds| 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvaldsli: 14901da177e4SLinus Torvalds moveql #4,%d0 |set byte count 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 14931da177e4SLinus Torvalds bne int_dnrm |if so, branch 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds fmovemx ETEMP(%a6),%fp0-%fp0 14961da177e4SLinus Torvalds fcmpd #0x41dfffffffc00000,%fp0 14971da177e4SLinus Torvalds| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec 14981da177e4SLinus Torvalds fbge lo_plrg 14991da177e4SLinus Torvalds fcmpd #0xc1e0000000000000,%fp0 15001da177e4SLinus Torvalds| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec 15011da177e4SLinus Torvalds fble lo_nlrg 15021da177e4SLinus Torvalds| 15031da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values 15041da177e4SLinus Torvalds| 15051da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 |use user's rounding mode 15061da177e4SLinus Torvalds andil #0x30,%d1 15071da177e4SLinus Torvalds fmovel %d1,%fpcr 15081da177e4SLinus Torvalds fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion 15091da177e4SLinus Torvalds fmovel %fpsr,%d1 15101da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 15111da177e4SLinus Torvalds bra int_wrt 15121da177e4SLinus Torvalds 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvaldslo_plrg: 15151da177e4SLinus Torvalds movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int 15161da177e4SLinus Torvalds fbeq int_wrt |exact answer 15171da177e4SLinus Torvalds fcmpd #0x41dfffffffe00000,%fp0 15181da177e4SLinus Torvalds| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec 15191da177e4SLinus Torvalds fbge int_operr |set operr 15201da177e4SLinus Torvalds bra int_inx |set inexact 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvaldslo_nlrg: 15231da177e4SLinus Torvalds movel #0x80000000,L_SCR1(%a6) 15241da177e4SLinus Torvalds fbeq int_wrt |exact answer 15251da177e4SLinus Torvalds fcmpd #0xc1e0000000100000,%fp0 15261da177e4SLinus Torvalds| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec 15271da177e4SLinus Torvalds fblt int_operr |set operr 15281da177e4SLinus Torvalds bra int_inx |set inexact 15291da177e4SLinus Torvalds 15301da177e4SLinus Torvalds| 15311da177e4SLinus Torvalds| wi is used to handle a word integer source specifier 15321da177e4SLinus Torvalds| 15331da177e4SLinus Torvalds 15341da177e4SLinus Torvaldswi: 15351da177e4SLinus Torvalds moveql #2,%d0 |set byte count 15361da177e4SLinus Torvalds 15371da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 15381da177e4SLinus Torvalds bne int_dnrm |branch if so 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds fmovemx ETEMP(%a6),%fp0-%fp0 15411da177e4SLinus Torvalds fcmps #0x46fffe00,%fp0 15421da177e4SLinus Torvalds| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec 15431da177e4SLinus Torvalds fbge wo_plrg 15441da177e4SLinus Torvalds fcmps #0xc7000000,%fp0 15451da177e4SLinus Torvalds| c7000000 in sgl prec = c00e00008000000000000000 in ext prec 15461da177e4SLinus Torvalds fble wo_nlrg 15471da177e4SLinus Torvalds 15481da177e4SLinus Torvalds| 15491da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values 15501da177e4SLinus Torvalds| 15511da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 |use user's rounding mode 15521da177e4SLinus Torvalds andil #0x30,%d1 15531da177e4SLinus Torvalds fmovel %d1,%fpcr 15541da177e4SLinus Torvalds fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion 15551da177e4SLinus Torvalds fmovel %fpsr,%d1 15561da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 15571da177e4SLinus Torvalds bra int_wrt 15581da177e4SLinus Torvalds 15591da177e4SLinus Torvaldswo_plrg: 15601da177e4SLinus Torvalds movew #0x7fff,L_SCR1(%a6) |answer is largest positive int 15611da177e4SLinus Torvalds fbeq int_wrt |exact answer 15621da177e4SLinus Torvalds fcmps #0x46ffff00,%fp0 15631da177e4SLinus Torvalds| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec 15641da177e4SLinus Torvalds fbge int_operr |set operr 15651da177e4SLinus Torvalds bra int_inx |set inexact 15661da177e4SLinus Torvalds 15671da177e4SLinus Torvaldswo_nlrg: 15681da177e4SLinus Torvalds movew #0x8000,L_SCR1(%a6) 15691da177e4SLinus Torvalds fbeq int_wrt |exact answer 15701da177e4SLinus Torvalds fcmps #0xc7000080,%fp0 15711da177e4SLinus Torvalds| c7000080 in sgl prec = c00e00008000800000000000 in ext prec 15721da177e4SLinus Torvalds fblt int_operr |set operr 15731da177e4SLinus Torvalds bra int_inx |set inexact 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds| 15761da177e4SLinus Torvalds| bi is used to handle a byte integer source specifier 15771da177e4SLinus Torvalds| 15781da177e4SLinus Torvalds 15791da177e4SLinus Torvaldsbi: 15801da177e4SLinus Torvalds moveql #1,%d0 |set byte count 15811da177e4SLinus Torvalds 15821da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 15831da177e4SLinus Torvalds bne int_dnrm |branch if so 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds fmovemx ETEMP(%a6),%fp0-%fp0 15861da177e4SLinus Torvalds fcmps #0x42fe0000,%fp0 15871da177e4SLinus Torvalds| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec 15881da177e4SLinus Torvalds fbge by_plrg 15891da177e4SLinus Torvalds fcmps #0xc3000000,%fp0 15901da177e4SLinus Torvalds| c3000000 in sgl prec = c00600008000000000000000 in ext prec 15911da177e4SLinus Torvalds fble by_nlrg 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds| 15941da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values 15951da177e4SLinus Torvalds| 15961da177e4SLinus Torvalds movel USER_FPCR(%a6),%d1 |use user's rounding mode 15971da177e4SLinus Torvalds andil #0x30,%d1 15981da177e4SLinus Torvalds fmovel %d1,%fpcr 15991da177e4SLinus Torvalds fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion 16001da177e4SLinus Torvalds fmovel %fpsr,%d1 16011da177e4SLinus Torvalds orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 16021da177e4SLinus Torvalds bra int_wrt 16031da177e4SLinus Torvalds 16041da177e4SLinus Torvaldsby_plrg: 16051da177e4SLinus Torvalds moveb #0x7f,L_SCR1(%a6) |answer is largest positive int 16061da177e4SLinus Torvalds fbeq int_wrt |exact answer 16071da177e4SLinus Torvalds fcmps #0x42ff0000,%fp0 16081da177e4SLinus Torvalds| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec 16091da177e4SLinus Torvalds fbge int_operr |set operr 16101da177e4SLinus Torvalds bra int_inx |set inexact 16111da177e4SLinus Torvalds 16121da177e4SLinus Torvaldsby_nlrg: 16131da177e4SLinus Torvalds moveb #0x80,L_SCR1(%a6) 16141da177e4SLinus Torvalds fbeq int_wrt |exact answer 16151da177e4SLinus Torvalds fcmps #0xc3008000,%fp0 16161da177e4SLinus Torvalds| c3008000 in sgl prec = c00600008080000000000000 in ext prec 16171da177e4SLinus Torvalds fblt int_operr |set operr 16181da177e4SLinus Torvalds bra int_inx |set inexact 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds| 16211da177e4SLinus Torvalds| Common integer routines 16221da177e4SLinus Torvalds| 16231da177e4SLinus Torvalds| int_drnrm---account for possible nonzero result for round up with positive 16241da177e4SLinus Torvalds| operand and round down for negative answer. In the first case (result = 1) 16251da177e4SLinus Torvalds| byte-width (store in d0) of result must be honored. In the second case, 16261da177e4SLinus Torvalds| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out). 16271da177e4SLinus Torvalds 16281da177e4SLinus Torvaldsint_dnrm: 16291da177e4SLinus Torvalds movel #0,L_SCR1(%a6) | initialize result to 0 16301da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode 16311da177e4SLinus Torvalds cmpb #2,%d1 16321da177e4SLinus Torvalds bmis int_inx | if RN or RZ, done 16331da177e4SLinus Torvalds bnes int_rp | if RP, continue below 16341da177e4SLinus Torvalds tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative 16351da177e4SLinus Torvalds bpls int_inx | otherwise result is 0 16361da177e4SLinus Torvalds movel #-1,L_SCR1(%a6) 16371da177e4SLinus Torvalds bras int_inx 16381da177e4SLinus Torvaldsint_rp: 16391da177e4SLinus Torvalds tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if 16401da177e4SLinus Torvalds| ; source is greater than 0 16411da177e4SLinus Torvalds bmis int_inx | otherwise, result is 0 16421da177e4SLinus Torvalds lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1 16431da177e4SLinus Torvalds addal %d0,%a1 | offset by destination width -1 16441da177e4SLinus Torvalds subal #1,%a1 16451da177e4SLinus Torvalds bsetb #0,(%a1) | set low bit at a1 address 16461da177e4SLinus Torvaldsint_inx: 16471da177e4SLinus Torvalds oril #inx2a_mask,USER_FPSR(%a6) 16481da177e4SLinus Torvalds bras int_wrt 16491da177e4SLinus Torvaldsint_operr: 16501da177e4SLinus Torvalds fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended 16511da177e4SLinus Torvalds| ;precision source that needs to be 16521da177e4SLinus Torvalds| ;converted to integer this is required 16531da177e4SLinus Torvalds| ;if the operr exception is enabled. 16541da177e4SLinus Torvalds| ;set operr/aiop (no inex2 on int ovfl) 16551da177e4SLinus Torvalds 16561da177e4SLinus Torvalds oril #opaop_mask,USER_FPSR(%a6) 16571da177e4SLinus Torvalds| ;fall through to perform int_wrt 16581da177e4SLinus Torvaldsint_wrt: 16591da177e4SLinus Torvalds movel EXC_EA(%a6),%a1 |load destination address 16601da177e4SLinus Torvalds tstl %a1 |check to see if it is a dest register 16611da177e4SLinus Torvalds beqs wrt_dn |write data register 16621da177e4SLinus Torvalds lea L_SCR1(%a6),%a0 |point to supervisor source address 16631da177e4SLinus Torvalds bsrl mem_write 16641da177e4SLinus Torvalds bra mvouti_end 16651da177e4SLinus Torvalds 16661da177e4SLinus Torvaldswrt_dn: 16671da177e4SLinus Torvalds movel %d0,-(%sp) |d0 currently contains the size to write 16681da177e4SLinus Torvalds bsrl get_fline |get_fline returns Dn in d0 16691da177e4SLinus Torvalds andiw #0x7,%d0 |isolate register 16701da177e4SLinus Torvalds movel (%sp)+,%d1 |get size 16711da177e4SLinus Torvalds cmpil #4,%d1 |most frequent case 16721da177e4SLinus Torvalds beqs sz_long 16731da177e4SLinus Torvalds cmpil #2,%d1 16741da177e4SLinus Torvalds bnes sz_con 16751da177e4SLinus Torvalds orl #8,%d0 |add 'word' size to register# 16761da177e4SLinus Torvalds bras sz_con 16771da177e4SLinus Torvaldssz_long: 16781da177e4SLinus Torvalds orl #0x10,%d0 |add 'long' size to register# 16791da177e4SLinus Torvaldssz_con: 16801da177e4SLinus Torvalds movel %d0,%d1 |reg_dest expects size:reg in d1 16811da177e4SLinus Torvalds bsrl reg_dest |load proper data register 16821da177e4SLinus Torvalds bra mvouti_end 16831da177e4SLinus Torvaldsxp: 16841da177e4SLinus Torvalds lea ETEMP(%a6),%a0 16851da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 16861da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 16871da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 16881da177e4SLinus Torvalds bne xdnrm 16891da177e4SLinus Torvalds clrl %d0 16901da177e4SLinus Torvalds bras do_fp |do normal case 16911da177e4SLinus Torvaldssgp: 16921da177e4SLinus Torvalds lea ETEMP(%a6),%a0 16931da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 16941da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 16951da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 16961da177e4SLinus Torvalds bne sp_catas |branch if so 16971da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d0 16981da177e4SLinus Torvalds lea sp_bnds,%a1 16991da177e4SLinus Torvalds cmpw (%a1),%d0 17001da177e4SLinus Torvalds blt sp_under 17011da177e4SLinus Torvalds cmpw 2(%a1),%d0 17021da177e4SLinus Torvalds bgt sp_over 17031da177e4SLinus Torvalds movel #1,%d0 |set destination format to single 17041da177e4SLinus Torvalds bras do_fp |do normal case 17051da177e4SLinus Torvaldsdp: 17061da177e4SLinus Torvalds lea ETEMP(%a6),%a0 17071da177e4SLinus Torvalds bclrb #sign_bit,LOCAL_EX(%a0) 17081da177e4SLinus Torvalds sne LOCAL_SGN(%a0) 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds btstb #7,STAG(%a6) |check for extended denorm 17111da177e4SLinus Torvalds bne dp_catas |branch if so 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds movew LOCAL_EX(%a0),%d0 17141da177e4SLinus Torvalds lea dp_bnds,%a1 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds cmpw (%a1),%d0 17171da177e4SLinus Torvalds blt dp_under 17181da177e4SLinus Torvalds cmpw 2(%a1),%d0 17191da177e4SLinus Torvalds bgt dp_over 17201da177e4SLinus Torvalds 17211da177e4SLinus Torvalds movel #2,%d0 |set destination format to double 17221da177e4SLinus Torvalds| ;fall through to do_fp 17231da177e4SLinus Torvalds| 17241da177e4SLinus Torvaldsdo_fp: 17251da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1 17261da177e4SLinus Torvalds swap %d0 |rnd prec in upper word 17271da177e4SLinus Torvalds addl %d0,%d1 |d1 has PREC/MODE info 17281da177e4SLinus Torvalds 17291da177e4SLinus Torvalds clrl %d0 |clear g,r,s 17301da177e4SLinus Torvalds 17311da177e4SLinus Torvalds bsrl round |round 17321da177e4SLinus Torvalds 17331da177e4SLinus Torvalds movel %a0,%a1 17341da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 17351da177e4SLinus Torvalds 17361da177e4SLinus Torvalds bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format 17371da177e4SLinus Torvalds| ;at this point only the dest 17381da177e4SLinus Torvalds| ;formats sgl, dbl, ext are 17391da177e4SLinus Torvalds| ;possible 17401da177e4SLinus Torvalds cmpb #2,%d1 17411da177e4SLinus Torvalds bgts ddbl |double=5, extended=2, single=1 17421da177e4SLinus Torvalds bnes dsgl 17431da177e4SLinus Torvalds| ;fall through to dext 17441da177e4SLinus Torvaldsdext: 17451da177e4SLinus Torvalds bsrl dest_ext 17461da177e4SLinus Torvalds bra mvout_end 17471da177e4SLinus Torvaldsdsgl: 17481da177e4SLinus Torvalds bsrl dest_sgl 17491da177e4SLinus Torvalds bra mvout_end 17501da177e4SLinus Torvaldsddbl: 17511da177e4SLinus Torvalds bsrl dest_dbl 17521da177e4SLinus Torvalds bra mvout_end 17531da177e4SLinus Torvalds 17541da177e4SLinus Torvalds| 17551da177e4SLinus Torvalds| Handle possible denorm or catastrophic underflow cases here 17561da177e4SLinus Torvalds| 17571da177e4SLinus Torvaldsxdnrm: 17581da177e4SLinus Torvalds bsr set_xop |initialize WBTEMP 17591da177e4SLinus Torvalds bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds movel %a0,%a1 17621da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 |a0 has the destination pointer 17631da177e4SLinus Torvalds bsrl dest_ext |store to memory 17641da177e4SLinus Torvalds bsetb #unfl_bit,FPSR_EXCEPT(%a6) 17651da177e4SLinus Torvalds bra mvout_end 17661da177e4SLinus Torvalds 17671da177e4SLinus Torvaldssp_under: 17681da177e4SLinus Torvalds bsetb #etemp15_bit,STAG(%a6) 17691da177e4SLinus Torvalds 17701da177e4SLinus Torvalds cmpw 4(%a1),%d0 17711da177e4SLinus Torvalds blts sp_catas |catastrophic underflow case 17721da177e4SLinus Torvalds 17731da177e4SLinus Torvalds movel #1,%d0 |load in round precision 17741da177e4SLinus Torvalds movel #sgl_thresh,%d1 |load in single denorm threshold 17751da177e4SLinus Torvalds bsrl dpspdnrm |expects d1 to have the proper 17761da177e4SLinus Torvalds| ;denorm threshold 17771da177e4SLinus Torvalds bsrl dest_sgl |stores value to destination 17781da177e4SLinus Torvalds bsetb #unfl_bit,FPSR_EXCEPT(%a6) 17791da177e4SLinus Torvalds bra mvout_end |exit 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvaldsdp_under: 17821da177e4SLinus Torvalds bsetb #etemp15_bit,STAG(%a6) 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds cmpw 4(%a1),%d0 17851da177e4SLinus Torvalds blts dp_catas |catastrophic underflow case 17861da177e4SLinus Torvalds 17871da177e4SLinus Torvalds movel #dbl_thresh,%d1 |load in double precision threshold 17881da177e4SLinus Torvalds movel #2,%d0 17891da177e4SLinus Torvalds bsrl dpspdnrm |expects d1 to have proper 17901da177e4SLinus Torvalds| ;denorm threshold 17911da177e4SLinus Torvalds| ;expects d0 to have round precision 17921da177e4SLinus Torvalds bsrl dest_dbl |store value to destination 17931da177e4SLinus Torvalds bsetb #unfl_bit,FPSR_EXCEPT(%a6) 17941da177e4SLinus Torvalds bra mvout_end |exit 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds| 17971da177e4SLinus Torvalds| Handle catastrophic underflow cases here 17981da177e4SLinus Torvalds| 17991da177e4SLinus Torvaldssp_catas: 18001da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub 18011da177e4SLinus Torvalds movel USER_FPSR(%a6),-(%a7) 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds movel #1,%d0 |set round precision to sgl 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds bsrl unf_sub |a0 points to result 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds movel (%a7)+,USER_FPSR(%a6) 18081da177e4SLinus Torvalds 18091da177e4SLinus Torvalds movel #1,%d0 18101da177e4SLinus Torvalds subw %d0,LOCAL_EX(%a0) |account for difference between 18111da177e4SLinus Torvalds| ;denorm/norm bias 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds movel %a0,%a1 |a1 has the operand input 18141da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 |a0 has the destination pointer 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds bsrl dest_sgl |store the result 18171da177e4SLinus Torvalds oril #unfinx_mask,USER_FPSR(%a6) 18181da177e4SLinus Torvalds bra mvout_end 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvaldsdp_catas: 18211da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub 18221da177e4SLinus Torvalds movel USER_FPSR(%a6),-(%a7) 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds movel #2,%d0 |set round precision to dbl 18251da177e4SLinus Torvalds bsrl unf_sub |a0 points to result 18261da177e4SLinus Torvalds 18271da177e4SLinus Torvalds movel (%a7)+,USER_FPSR(%a6) 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds movel #1,%d0 18301da177e4SLinus Torvalds subw %d0,LOCAL_EX(%a0) |account for difference between 18311da177e4SLinus Torvalds| ;denorm/norm bias 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds movel %a0,%a1 |a1 has the operand input 18341da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 |a0 has the destination pointer 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds bsrl dest_dbl |store the result 18371da177e4SLinus Torvalds oril #unfinx_mask,USER_FPSR(%a6) 18381da177e4SLinus Torvalds bra mvout_end 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds| 18411da177e4SLinus Torvalds| Handle catastrophic overflow cases here 18421da177e4SLinus Torvalds| 18431da177e4SLinus Torvaldssp_over: 18441da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub 18451da177e4SLinus Torvalds movel USER_FPSR(%a6),-(%a7) 18461da177e4SLinus Torvalds 18471da177e4SLinus Torvalds movel #1,%d0 18481da177e4SLinus Torvalds leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result 18491da177e4SLinus Torvalds movel ETEMP_EX(%a6),(%a0) 18501da177e4SLinus Torvalds movel ETEMP_HI(%a6),4(%a0) 18511da177e4SLinus Torvalds movel ETEMP_LO(%a6),8(%a0) 18521da177e4SLinus Torvalds bsrl ovf_res 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds movel (%a7)+,USER_FPSR(%a6) 18551da177e4SLinus Torvalds 18561da177e4SLinus Torvalds movel %a0,%a1 18571da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 18581da177e4SLinus Torvalds bsrl dest_sgl 18591da177e4SLinus Torvalds orl #ovfinx_mask,USER_FPSR(%a6) 18601da177e4SLinus Torvalds bra mvout_end 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvaldsdp_over: 18631da177e4SLinus Torvalds| Temp fix for z bit set in ovf_res 18641da177e4SLinus Torvalds movel USER_FPSR(%a6),-(%a7) 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds movel #2,%d0 18671da177e4SLinus Torvalds leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result 18681da177e4SLinus Torvalds movel ETEMP_EX(%a6),(%a0) 18691da177e4SLinus Torvalds movel ETEMP_HI(%a6),4(%a0) 18701da177e4SLinus Torvalds movel ETEMP_LO(%a6),8(%a0) 18711da177e4SLinus Torvalds bsrl ovf_res 18721da177e4SLinus Torvalds 18731da177e4SLinus Torvalds movel (%a7)+,USER_FPSR(%a6) 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds movel %a0,%a1 18761da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 18771da177e4SLinus Torvalds bsrl dest_dbl 18781da177e4SLinus Torvalds orl #ovfinx_mask,USER_FPSR(%a6) 18791da177e4SLinus Torvalds bra mvout_end 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds| 18821da177e4SLinus Torvalds| DPSPDNRM 18831da177e4SLinus Torvalds| 18841da177e4SLinus Torvalds| This subroutine takes an extended normalized number and denormalizes 18851da177e4SLinus Torvalds| it to the given round precision. This subroutine also decrements 18861da177e4SLinus Torvalds| the input operand's exponent by 1 to account for the fact that 18871da177e4SLinus Torvalds| dest_sgl or dest_dbl expects a normalized number's bias. 18881da177e4SLinus Torvalds| 18891da177e4SLinus Torvalds| Input: a0 points to a normalized number in internal extended format 18901da177e4SLinus Torvalds| d0 is the round precision (=1 for sgl; =2 for dbl) 18911da177e4SLinus Torvalds| d1 is the single precision or double precision 18921da177e4SLinus Torvalds| denorm threshold 18931da177e4SLinus Torvalds| 18941da177e4SLinus Torvalds| Output: (In the format for dest_sgl or dest_dbl) 18951da177e4SLinus Torvalds| a0 points to the destination 18961da177e4SLinus Torvalds| a1 points to the operand 18971da177e4SLinus Torvalds| 18981da177e4SLinus Torvalds| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits 18991da177e4SLinus Torvalds| 19001da177e4SLinus Torvaldsdpspdnrm: 19011da177e4SLinus Torvalds movel %d0,-(%a7) |save round precision 19021da177e4SLinus Torvalds clrl %d0 |clear initial g,r,s 19031da177e4SLinus Torvalds bsrl dnrm_lp |careful with d0, it's needed by round 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode 19061da177e4SLinus Torvalds swap %d1 19071da177e4SLinus Torvalds movew 2(%a7),%d1 |set rounding precision 19081da177e4SLinus Torvalds swap %d1 |at this point d1 has PREC/MODE info 19091da177e4SLinus Torvalds bsrl round |round result, sets the inex bit in 19101da177e4SLinus Torvalds| ;USER_FPSR if needed 19111da177e4SLinus Torvalds 19121da177e4SLinus Torvalds movew #1,%d0 19131da177e4SLinus Torvalds subw %d0,LOCAL_EX(%a0) |account for difference in denorm 19141da177e4SLinus Torvalds| ;vs norm bias 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds movel %a0,%a1 |a1 has the operand input 19171da177e4SLinus Torvalds movel EXC_EA(%a6),%a0 |a0 has the destination pointer 19181da177e4SLinus Torvalds addw #4,%a7 |pop stack 19191da177e4SLinus Torvalds rts 19201da177e4SLinus Torvalds| 19211da177e4SLinus Torvalds| SET_XOP initialized WBTEMP with the value pointed to by a0 19221da177e4SLinus Torvalds| input: a0 points to input operand in the internal extended format 19231da177e4SLinus Torvalds| 19241da177e4SLinus Torvaldsset_xop: 19251da177e4SLinus Torvalds movel LOCAL_EX(%a0),WBTEMP_EX(%a6) 19261da177e4SLinus Torvalds movel LOCAL_HI(%a0),WBTEMP_HI(%a6) 19271da177e4SLinus Torvalds movel LOCAL_LO(%a0),WBTEMP_LO(%a6) 19281da177e4SLinus Torvalds bfclr WBTEMP_SGN(%a6){#0:#8} 19291da177e4SLinus Torvalds beqs sxop 19301da177e4SLinus Torvalds bsetb #sign_bit,WBTEMP_EX(%a6) 19311da177e4SLinus Torvaldssxop: 19321da177e4SLinus Torvalds bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit 19331da177e4SLinus Torvalds rts 19341da177e4SLinus Torvalds| 19351da177e4SLinus Torvalds| P_MOVE 19361da177e4SLinus Torvalds| 19371da177e4SLinus Torvaldsp_movet: 19381da177e4SLinus Torvalds .long p_move 19391da177e4SLinus Torvalds .long p_movez 19401da177e4SLinus Torvalds .long p_movei 19411da177e4SLinus Torvalds .long p_moven 19421da177e4SLinus Torvalds .long p_move 19431da177e4SLinus Torvaldsp_regd: 19441da177e4SLinus Torvalds .long p_dyd0 19451da177e4SLinus Torvalds .long p_dyd1 19461da177e4SLinus Torvalds .long p_dyd2 19471da177e4SLinus Torvalds .long p_dyd3 19481da177e4SLinus Torvalds .long p_dyd4 19491da177e4SLinus Torvalds .long p_dyd5 19501da177e4SLinus Torvalds .long p_dyd6 19511da177e4SLinus Torvalds .long p_dyd7 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvaldspack_out: 19541da177e4SLinus Torvalds leal p_movet,%a0 |load jmp table address 19551da177e4SLinus Torvalds movew STAG(%a6),%d0 |get source tag 19561da177e4SLinus Torvalds bfextu %d0{#16:#3},%d0 |isolate source bits 19571da177e4SLinus Torvalds movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag 19581da177e4SLinus Torvalds jmp (%a0) |go to the routine 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvaldsp_write: 19611da177e4SLinus Torvalds movel #0x0c,%d0 |get byte count 19621da177e4SLinus Torvalds movel EXC_EA(%a6),%a1 |get the destination address 19631da177e4SLinus Torvalds bsr mem_write |write the user's destination 19641da177e4SLinus Torvalds moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's 19651da177e4SLinus Torvalds 19661da177e4SLinus Torvalds| 19671da177e4SLinus Torvalds| Also note that the dtag must be set to norm here - this is because 19681da177e4SLinus Torvalds| the 040 uses the dtag to execute the correct microcode. 19691da177e4SLinus Torvalds| 19701da177e4SLinus Torvalds bfclr DTAG(%a6){#0:#3} |set dtag to norm 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds rts 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds| Notes on handling of special case (zero, inf, and nan) inputs: 19751da177e4SLinus Torvalds| 1. Operr is not signalled if the k-factor is greater than 18. 19761da177e4SLinus Torvalds| 2. Per the manual, status bits are not set. 19771da177e4SLinus Torvalds| 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvaldsp_move: 19801da177e4SLinus Torvalds movew CMDREG1B(%a6),%d0 19811da177e4SLinus Torvalds btstl #kfact_bit,%d0 |test for dynamic k-factor 19821da177e4SLinus Torvalds beqs statick |if clear, k-factor is static 19831da177e4SLinus Torvaldsdynamick: 19841da177e4SLinus Torvalds bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor 19851da177e4SLinus Torvalds lea p_regd,%a0 19861da177e4SLinus Torvalds movel %a0@(%d0:l:4),%a0 19871da177e4SLinus Torvalds jmp (%a0) 19881da177e4SLinus Torvaldsstatick: 19891da177e4SLinus Torvalds andiw #0x007f,%d0 |get k-factor 19901da177e4SLinus Torvalds bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec 19911da177e4SLinus Torvalds leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 19921da177e4SLinus Torvalds bsrl bindec |perform the convert; data at a6 19931da177e4SLinus Torvalds leal FP_SCR1(%a6),%a0 |load a0 with result address 19941da177e4SLinus Torvalds bral p_write 19951da177e4SLinus Torvaldsp_movez: 19961da177e4SLinus Torvalds leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 19971da177e4SLinus Torvalds clrw 2(%a0) |clear lower word of exp 19981da177e4SLinus Torvalds clrl 4(%a0) |load second lword of ZERO 19991da177e4SLinus Torvalds clrl 8(%a0) |load third lword of ZERO 20001da177e4SLinus Torvalds bra p_write |go write results 20011da177e4SLinus Torvaldsp_movei: 20021da177e4SLinus Torvalds fmovel #0,%FPSR |clear aiop 20031da177e4SLinus Torvalds leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 20041da177e4SLinus Torvalds clrw 2(%a0) |clear lower word of exp 20051da177e4SLinus Torvalds bra p_write |go write the result 20061da177e4SLinus Torvaldsp_moven: 20071da177e4SLinus Torvalds leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 20081da177e4SLinus Torvalds clrw 2(%a0) |clear lower word of exp 20091da177e4SLinus Torvalds bra p_write |go write the result 20101da177e4SLinus Torvalds 20111da177e4SLinus Torvalds| 20121da177e4SLinus Torvalds| Routines to read the dynamic k-factor from Dn. 20131da177e4SLinus Torvalds| 20141da177e4SLinus Torvaldsp_dyd0: 20151da177e4SLinus Torvalds movel USER_D0(%a6),%d0 20161da177e4SLinus Torvalds bras statick 20171da177e4SLinus Torvaldsp_dyd1: 20181da177e4SLinus Torvalds movel USER_D1(%a6),%d0 20191da177e4SLinus Torvalds bras statick 20201da177e4SLinus Torvaldsp_dyd2: 20211da177e4SLinus Torvalds movel %d2,%d0 20221da177e4SLinus Torvalds bras statick 20231da177e4SLinus Torvaldsp_dyd3: 20241da177e4SLinus Torvalds movel %d3,%d0 20251da177e4SLinus Torvalds bras statick 20261da177e4SLinus Torvaldsp_dyd4: 20271da177e4SLinus Torvalds movel %d4,%d0 20281da177e4SLinus Torvalds bras statick 20291da177e4SLinus Torvaldsp_dyd5: 20301da177e4SLinus Torvalds movel %d5,%d0 20311da177e4SLinus Torvalds bras statick 20321da177e4SLinus Torvaldsp_dyd6: 20331da177e4SLinus Torvalds movel %d6,%d0 20341da177e4SLinus Torvalds bra statick 20351da177e4SLinus Torvaldsp_dyd7: 20361da177e4SLinus Torvalds movel %d7,%d0 20371da177e4SLinus Torvalds bra statick 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds |end 2040